invite button and can navigate to submissions (no submissions will appear yet)
This commit is contained in:
@@ -423,10 +423,35 @@ exports.createInvitation = onRequest({ cors: true }, async (req, res) => {
|
|||||||
// Generate invite links
|
// Generate invite links
|
||||||
const baseUrl = process.env.CLIENT_URL || 'http://localhost:5173';
|
const baseUrl = process.env.CLIENT_URL || 'http://localhost:5173';
|
||||||
const inviteLink = `${baseUrl}/#/employee-form/${code}`;
|
const inviteLink = `${baseUrl}/#/employee-form/${code}`;
|
||||||
const emailLink = `mailto:${email}?subject=You're invited to join our organization&body=Hi ${name},%0A%0AYou've been invited to complete a questionnaire for our organization. Please click the link below to get started:%0A%0A${inviteLink}%0A%0AThis link will expire in 7 days.%0A%0AThank you!`;
|
try {
|
||||||
|
if (!!process.env.SENDGRID_API_KEY) {
|
||||||
|
await fetch('https://api.sendgrid.com/v3/mail/send', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
personalizations: [
|
||||||
|
{
|
||||||
|
to: [{ email }],
|
||||||
|
dynamic_template_data: {
|
||||||
|
name,
|
||||||
|
inviteLink,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
from: { email: 'no-reply@auditly.com', name: 'Auditly' },
|
||||||
|
template_id: process.env.SENDGRID_TEMPLATE_ID,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
console.log(`📧 Invitation sent to ${email} (${name}) with code: ${code}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("SendGrid email error:", error);
|
||||||
|
}
|
||||||
|
|
||||||
// In production, send actual invitation email
|
// In production, send actual invitation email
|
||||||
console.log(`📧 Invitation sent to ${email} (${name}) with code: ${code}`);
|
|
||||||
console.log(`📧 Invite link: ${inviteLink}`);
|
console.log(`📧 Invite link: ${inviteLink}`);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
@@ -434,7 +459,6 @@ exports.createInvitation = onRequest({ cors: true }, async (req, res) => {
|
|||||||
code,
|
code,
|
||||||
employee,
|
employee,
|
||||||
inviteLink,
|
inviteLink,
|
||||||
emailLink,
|
|
||||||
message: "Invitation sent successfully",
|
message: "Invitation sent successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1574,8 +1598,8 @@ exports.createCheckoutSession = onRequest({ cors: true }, async (req, res) => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
mode: 'subscription',
|
mode: 'subscription',
|
||||||
success_url: `${process.env.CLIENT_URL || 'http://localhost:5174'}/#/dashboard?session_id={CHECKOUT_SESSION_ID}`,
|
success_url: `${process.env.CLIENT_URL || 'http://localhost:5173'}/#/dashboard?session_id={CHECKOUT_SESSION_ID}`,
|
||||||
cancel_url: `${process.env.CLIENT_URL || 'http://localhost:5174'}/#/dashboard?canceled=true`,
|
cancel_url: `${process.env.CLIENT_URL || 'http://localhost:5173'}/#/dashboard?canceled=true`,
|
||||||
metadata: {
|
metadata: {
|
||||||
orgId,
|
orgId,
|
||||||
userId: authContext.userId,
|
userId: authContext.userId,
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ const Sidebar = () => {
|
|||||||
department: inviteForm.department
|
department: inviteForm.department
|
||||||
});
|
});
|
||||||
setInviteLink(result.inviteLink);
|
setInviteLink(result.inviteLink);
|
||||||
setEmailLink(result.emailLink);
|
// setEmailLink(result.emailLink);
|
||||||
setInviteForm({ name: '', email: '', role: '', department: '' });
|
setInviteForm({ name: '', email: '', role: '', department: '' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to invite employee:', error);
|
console.error('Failed to invite employee:', error);
|
||||||
@@ -126,7 +126,7 @@ const Sidebar = () => {
|
|||||||
<aside className="w-64 flex-shrink-0 bg-[--sidebar-bg] border-r border-[--border-color] flex flex-col p-4">
|
<aside className="w-64 flex-shrink-0 bg-[--sidebar-bg] border-r border-[--border-color] flex flex-col p-4">
|
||||||
<div className="flex items-center mb-8">
|
<div className="flex items-center mb-8">
|
||||||
<div className="w-8 h-8 bg-[--accent] rounded-full flex items-center justify-center font-bold text-white text-lg mr-2">A</div>
|
<div className="w-8 h-8 bg-[--accent] rounded-full flex items-center justify-center font-bold text-white text-lg mr-2">A</div>
|
||||||
<h1 className="text-xl font-bold text-[--text-primary]">{org?.name || 'Auditly'}</h1>
|
<h1 className="text-xl font-bold text-[--text-primary]">{org?.companyName || 'Auditly'}</h1>
|
||||||
</div>
|
</div>
|
||||||
<nav className="flex-1">
|
<nav className="flex-1">
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
@@ -271,7 +271,7 @@ export const Layout = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-[--Neutrals-NeutralSlate0]">
|
<div className="flex h-screen bg-[--Neutrals-NeutralSlate0]">
|
||||||
<FigmaSidebar companyName={org?.name || "Auditly"} />
|
<FigmaSidebar companyName={org?.companyName || "Auditly"} />
|
||||||
<main className="flex-1 overflow-y-auto">
|
<main className="flex-1 overflow-y-auto">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -2,20 +2,57 @@ import React, { useState } from 'react';
|
|||||||
|
|
||||||
// Icon SVG Component - From Figma designs
|
// Icon SVG Component - From Figma designs
|
||||||
export const AuditlyIcon: React.FC = () => (
|
export const AuditlyIcon: React.FC = () => (
|
||||||
<svg width="24" height="30" viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<div data-svg-wrapper className="relative">
|
||||||
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M2.57408 17.8138C3.11835 18.3649 3.11834 19.2585 2.57406 19.8097L2.54619 19.8379C2.00191 20.389 1.11946 20.389 0.57519 19.8379C0.030919 19.2867 0.0309274 18.3931 0.575208 17.842L0.603083 17.8137C1.14736 17.2626 2.02981 17.2626 2.57408 17.8138Z" fill="url(#paint0_linear_981_10577)" />
|
<svg width="24" height="30" viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path opacity="0.7" fillRule="evenodd" clipRule="evenodd" d="M9.12583 18.2374C9.66912 18.7896 9.66752 19.6832 9.12226 20.2333L5.2617 24.1286C4.71644 24.6787 3.83399 24.6771 3.2907 24.125C2.74741 23.5728 2.74901 22.6792 3.29427 22.1291L7.15483 18.2338C7.70009 17.6837 8.58254 17.6853 9.12583 18.2374Z" fill="url(#paint1_linear_981_10577)" />
|
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M2.57408 17.8138C3.11835 18.3649 3.11834 19.2585 2.57406 19.8097L2.54619 19.8379C2.00191 20.389 1.11946 20.389 0.57519 19.8379C0.030919 19.2867 0.0309274 18.3931 0.575208 17.842L0.603083 17.8137C1.14736 17.2626 2.02981 17.2626 2.57408 17.8138Z" fill="url(#paint0_linear_984_10696)" />
|
||||||
<defs>
|
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M9.12583 18.2374C9.66912 18.7896 9.66752 19.6832 9.12226 20.2333L5.2617 24.1286C4.71644 24.6787 3.83399 24.6771 3.2907 24.125C2.74741 23.5728 2.74901 22.6792 3.29427 22.1291L7.15483 18.2338C7.70009 17.6837 8.58254 17.6853 9.12583 18.2374Z" fill="url(#paint1_linear_984_10696)" />
|
||||||
<linearGradient id="paint0_linear_981_10577" x1="1.57463" y1="17.4004" x2="1.57463" y2="20.2513" gradientUnits="userSpaceOnUse">
|
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M14.3656 24.9431C14.7925 24.2945 15.6578 24.1193 16.2983 24.5516L16.3819 24.6081C17.0224 25.0404 17.1954 25.9167 16.7685 26.5652C16.3415 27.2138 15.4762 27.389 14.8357 26.9567L14.7521 26.9002C14.1117 26.4678 13.9386 25.5916 14.3656 24.9431Z" fill="url(#paint2_linear_984_10696)" />
|
||||||
<stop stopColor="white" stopOpacity="0.8" />
|
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M23.5637 17.7278C24.108 18.279 24.108 19.1726 23.5637 19.7237L21.6683 21.6431C21.124 22.1943 20.2415 22.1943 19.6973 21.6431C19.153 21.092 19.153 20.1984 19.6973 19.6472L21.5927 17.7278C22.137 17.1767 23.0194 17.1767 23.5637 17.7278Z" fill="url(#paint3_linear_984_10696)" />
|
||||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.592 10.6302C24.1363 11.1813 24.1363 12.0749 23.592 12.6261L9.58526 26.8098C9.04098 27.361 8.15854 27.361 7.61426 26.8098C7.06999 26.2587 7.06999 25.3651 7.61426 24.8139L21.621 10.6302C22.1653 10.079 23.0477 10.079 23.592 10.6302Z" fill="url(#paint4_linear_984_10696)" />
|
||||||
</linearGradient>
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.9426 6.26883C21.4869 6.81999 21.4869 7.71359 20.9426 8.26474L12.887 16.4222C12.3427 16.9733 11.4603 16.9733 10.916 16.4222C10.3717 15.871 10.3717 14.9774 10.916 14.4263L18.9716 6.26883C19.5159 5.71768 20.3984 5.71768 20.9426 6.26883Z" fill="url(#paint5_linear_984_10696)" />
|
||||||
<linearGradient id="paint1_linear_981_10577" x1="6.20827" y1="17.8223" x2="6.20827" y2="24.5401" gradientUnits="userSpaceOnUse">
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6918 3.50254C17.2364 4.05332 17.237 4.94692 16.6931 5.49844L6.33787 15.9987C5.79396 16.5502 4.91152 16.5508 4.36688 16C3.82224 15.4492 3.82164 14.5556 4.36555 14.0041L14.7208 3.50388C15.2647 2.95236 16.1471 2.95176 16.6918 3.50254Z" fill="url(#paint6_linear_984_10696)" />
|
||||||
<stop stopColor="white" stopOpacity="0.8" />
|
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M6.43658 6.86235C6.97992 7.41445 6.9784 8.30805 6.43319 8.85825L2.37751 12.9511C1.83229 13.5013 0.94985 13.4997 0.406512 12.9476C-0.136826 12.3955 -0.135307 11.5019 0.409905 10.9517L4.46559 6.85892C5.0108 6.30871 5.89324 6.31025 6.43658 6.86235Z" fill="url(#paint7_linear_984_10696)" />
|
||||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M8.92007 2.7793C9.6898 2.7793 10.3138 3.41117 10.3138 4.19062V4.33175C10.3138 5.1112 9.6898 5.74307 8.92007 5.74307C8.15035 5.74307 7.52637 5.1112 7.52637 4.33175V4.19062C7.52637 3.41117 8.15035 2.7793 8.92007 2.7793Z" fill="url(#paint8_linear_984_10696)" />
|
||||||
</linearGradient>
|
<defs>
|
||||||
</defs>
|
<linearGradient id="paint0_linear_984_10696" x1="1.57463" y1="17.4004" x2="1.57463" y2="20.2513" gradientUnits="userSpaceOnUse">
|
||||||
</svg>
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_984_10696" x1="6.20827" y1="17.8223" x2="6.20827" y2="24.5401" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_984_10696" x1="15.567" y1="24.3145" x2="15.567" y2="27.1938" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_984_10696" x1="21.6305" y1="17.3145" x2="21.6305" y2="22.0565" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_984_10696" x1="15.6031" y1="10.2168" x2="15.6031" y2="27.2232" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_984_10696" x1="15.9293" y1="5.85547" x2="15.9293" y2="16.8355" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_984_10696" x1="10.5293" y1="3.08984" x2="10.5293" y2="16.4127" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_984_10696" x1="3.42155" y1="6.44727" x2="3.42155" y2="13.3627" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_984_10696" x1="8.92007" y1="2.7793" x2="8.92007" y2="5.74307" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0.8" />
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
// Progress Bar Component for Section Headers
|
// Progress Bar Component for Section Headers
|
||||||
@@ -55,9 +92,9 @@ export const SectionProgressBar: React.FC<{ currentSection: number; totalSection
|
|||||||
export const WelcomeScreen: React.FC<{
|
export const WelcomeScreen: React.FC<{
|
||||||
onStart: () => void;
|
onStart: () => void;
|
||||||
imageUrl?: string;
|
imageUrl?: string;
|
||||||
}> = ({ onStart, imageUrl = "https://placehold.co/560x682" }) => {
|
}> = ({ onStart, imageUrl = "/image/onboarding-robot.png" }) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] bg-white inline-flex justify-start items-center overflow-hidden">
|
<div className="w-full bg-[--Neutrals-NeutralSlate0] inline-flex justify-start items-center overflow-hidden">
|
||||||
<div className="flex-1 h-[810px] px-32 py-48 bg-[--Neutrals-NeutralSlate0] flex justify-center items-center gap-2.5 overflow-hidden">
|
<div className="flex-1 h-[810px] px-32 py-48 bg-[--Neutrals-NeutralSlate0] flex justify-center items-center gap-2.5 overflow-hidden">
|
||||||
<div className="flex-1 max-w-[464px] inline-flex flex-col justify-start items-start gap-12">
|
<div className="flex-1 max-w-[464px] inline-flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-6">
|
<div className="self-stretch flex flex-col justify-start items-start gap-6">
|
||||||
@@ -78,15 +115,15 @@ export const WelcomeScreen: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={onStart}
|
onClick={onStart}
|
||||||
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
|
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden hover:bg-blue-500 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 h-[810px] px-20 py-16 flex justify-center items-center gap-2.5 overflow-hidden">
|
<div className="flex-1 h-[810px] px-20 py-16 flex justify-center items-center gap-2.5 overflow-hidden h-fit">
|
||||||
<div className="flex-1 self-stretch origin-top-left rotate-180 rounded-3xl inline-flex flex-col justify-center items-center gap-2.5 overflow-hidden">
|
<div className="flex-1 self-stretch origin-top-left rotate-180 rounded-3xl inline-flex flex-col justify-center items-center gap-2.5 overflow-hidden">
|
||||||
<img className="self-stretch flex-1" src={imageUrl} alt="Welcome" />
|
<img className="self-stretch flex-1" src={imageUrl} alt="Welcome" />
|
||||||
</div>
|
</div>
|
||||||
@@ -104,7 +141,7 @@ export const SectionIntro: React.FC<{
|
|||||||
imageUrl?: string;
|
imageUrl?: string;
|
||||||
}> = ({ sectionNumber, title, description, onStart, imageUrl = "https://placehold.co/560x682" }) => {
|
}> = ({ sectionNumber, title, description, onStart, imageUrl = "https://placehold.co/560x682" }) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] bg-white inline-flex justify-start items-center overflow-hidden">
|
<div className="w-full self-stretch bg-[--Neutrals-NeutralSlate0] inline-flex justify-start items-center overflow-hidden">
|
||||||
<div className="flex-1 h-[810px] px-32 py-48 bg-[--Neutrals-NeutralSlate0] flex justify-center items-center gap-2.5 overflow-hidden">
|
<div className="flex-1 h-[810px] px-32 py-48 bg-[--Neutrals-NeutralSlate0] flex justify-center items-center gap-2.5 overflow-hidden">
|
||||||
<div className="flex-1 max-w-[464px] inline-flex flex-col justify-start items-start gap-12">
|
<div className="flex-1 max-w-[464px] inline-flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-6">
|
<div className="self-stretch flex flex-col justify-start items-start gap-6">
|
||||||
@@ -130,10 +167,10 @@ export const SectionIntro: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={onStart}
|
onClick={onStart}
|
||||||
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
|
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden hover:bg-blue-600 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,7 +227,7 @@ export const PersonalInfoForm: React.FC<{
|
|||||||
const isValid = formData.email && formData.name && formData.company;
|
const isValid = formData.email && formData.name && formData.company;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] h-[810px] px-[488px] py-32 bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
<div className="w-full self-stretch h-[810px] px-[488px] py-32 bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
||||||
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
||||||
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
||||||
@@ -224,10 +261,10 @@ export const PersonalInfoForm: React.FC<{
|
|||||||
<button
|
<button
|
||||||
onClick={onNext}
|
onClick={onNext}
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
className="self-stretch h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-orange-600 transition-colors"
|
className="self-stretch h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-500 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -249,7 +286,7 @@ export const TextAreaQuestion: React.FC<{
|
|||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}> = ({ question, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName, placeholder = "Type your answer...." }) => {
|
}> = ({ question, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName, placeholder = "Type your answer...." }) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] h-[810px] py-6 relative bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
<div className="w-full self-stretch h-[810px] py-6 relative bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
||||||
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
||||||
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
||||||
@@ -264,8 +301,8 @@ export const TextAreaQuestion: React.FC<{
|
|||||||
rows={6}
|
rows={6}
|
||||||
/>
|
/>
|
||||||
<div className="w-3 h-3 absolute right-5 bottom-5">
|
<div className="w-3 h-3 absolute right-5 bottom-5">
|
||||||
<div className="w-2 h-2 absolute top-0.5 left-0.5 outline outline-1 outline-offset-[-0.50px] outline-[--$1]" />
|
<div className="w-2 h-2 absolute top-0.5 left-0.5 outline outline-1 outline-offset-[-0.50px] outline-[--Neutrals-NeutralSlate950]" />
|
||||||
<div className="w-1 h-1 absolute bottom-0 right-0 outline outline-1 outline-offset-[-0.50px] outline-[--$1]" />
|
<div className="w-1 h-1 absolute bottom-0 right-0 outline outline-1 outline-offset-[-0.50px] outline-[--Neutrals-NeutralSlate950]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -273,7 +310,7 @@ export const TextAreaQuestion: React.FC<{
|
|||||||
{onBack && (
|
{onBack && (
|
||||||
<button
|
<button
|
||||||
onClick={onBack}
|
onClick={onBack}
|
||||||
className="h-12 px-8 py-3.5 bg-[--Neutrals-NeutralSlate100] rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-neutral-200 transition-colors"
|
className="h-12 px-8 py-3.5 bg-[--Neutrals-NeutralSlate100] rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-[--Neutrals-NeutralSlate200] transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-[--Neutrals-NeutralSlate950] text-sm font-medium font-['Inter'] leading-tight">Back</div>
|
<div className="justify-center text-[--Neutrals-NeutralSlate950] text-sm font-medium font-['Inter'] leading-tight">Back</div>
|
||||||
@@ -282,10 +319,10 @@ export const TextAreaQuestion: React.FC<{
|
|||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={onNext}
|
onClick={onNext}
|
||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden hover:bg-blue-500 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -304,7 +341,7 @@ export const TextAreaQuestion: React.FC<{
|
|||||||
{onSkip && (
|
{onSkip && (
|
||||||
<button
|
<button
|
||||||
onClick={onSkip}
|
onClick={onSkip}
|
||||||
className="px-3 py-1.5 right-[24px] top-[24px] absolute bg-[--Neutrals-NeutralSlate100] rounded-[50px] inline-flex justify-center items-center gap-2 overflow-hidden hover:bg-neutral-200 transition-colors"
|
className="px-3 py-1.5 right-[24px] top-[24px] absolute bg-[--Neutrals-NeutralSlate100] rounded-[50px] inline-flex justify-center items-center gap-2 overflow-hidden hover:bg-[--Neutrals-NeutralSlate200 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="justify-start text-[--Neutrals-NeutralSlate500] text-sm font-medium font-['Inter'] leading-none">Skip</div>
|
<div className="justify-start text-[--Neutrals-NeutralSlate500] text-sm font-medium font-['Inter'] leading-none">Skip</div>
|
||||||
</button>
|
</button>
|
||||||
@@ -338,7 +375,7 @@ export const RatingScaleQuestion: React.FC<{
|
|||||||
scale?: number;
|
scale?: number;
|
||||||
}> = ({ question, leftLabel, rightLabel, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName, scale = 10 }) => {
|
}> = ({ question, leftLabel, rightLabel, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName, scale = 10 }) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] h-[810px] py-6 relative bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
<div className="w-full self-stretch h-[810px] py-6 relative bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
||||||
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-center items-center gap-8">
|
<div className="self-stretch flex flex-col justify-center items-center gap-8">
|
||||||
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
||||||
@@ -387,7 +424,7 @@ export const RatingScaleQuestion: React.FC<{
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-orange-600 transition-colors"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-orange-600 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -437,7 +474,7 @@ export const YesNoChoice: React.FC<{
|
|||||||
sectionName?: string;
|
sectionName?: string;
|
||||||
}> = ({ question, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName }) => {
|
}> = ({ question, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName }) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] h-[810px] py-6 relative bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
<div className="w-full self-stretch h-[810px] py-6 relative bg-[--Neutrals-NeutralSlate0] inline-flex flex-col justify-center items-center gap-9">
|
||||||
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
||||||
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
<div className="self-stretch text-center justify-start text-[--Neutrals-NeutralSlate950] text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
||||||
@@ -483,7 +520,7 @@ export const YesNoChoice: React.FC<{
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-orange-600 transition-colors"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-orange-600 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -523,7 +560,7 @@ export const YesNoChoice: React.FC<{
|
|||||||
// Thank You Page Component
|
// Thank You Page Component
|
||||||
export const ThankYouPage: React.FC = () => {
|
export const ThankYouPage: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="w-[1440px] bg-white inline-flex justify-start items-center overflow-hidden">
|
<div className="w-full self-stretch bg-white inline-flex justify-start items-center overflow-hidden">
|
||||||
<div className="flex-1 h-[810px] px-32 py-48 bg-[--Neutrals-NeutralSlate0] flex justify-center items-center gap-2.5 overflow-hidden">
|
<div className="flex-1 h-[810px] px-32 py-48 bg-[--Neutrals-NeutralSlate0] flex justify-center items-center gap-2.5 overflow-hidden">
|
||||||
<div className="flex-1 max-w-[464px] inline-flex flex-col justify-start items-start gap-12">
|
<div className="flex-1 max-w-[464px] inline-flex flex-col justify-start items-start gap-12">
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-6">
|
<div className="self-stretch flex flex-col justify-start items-start gap-6">
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const FigmaQuestion: React.FC<FigmaQuestionProps> = ({
|
|||||||
className = ''
|
className = ''
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={`w-[600px] px-5 pt-5 pb-6 bg-Other-White rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--$1] inline-flex flex-col justify-end items-end gap-4 ${className}`}>
|
<div className={`w-[600px] px-5 pt-5 pb-6 bg-white rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--$1] inline-flex flex-col justify-end items-end gap-4 ${className}`}>
|
||||||
{/* Question Header */}
|
{/* Question Header */}
|
||||||
<div className="self-stretch inline-flex justify-start items-start gap-3">
|
<div className="self-stretch inline-flex justify-start items-start gap-3">
|
||||||
<div className="justify-start text-zinc-300 text-xl font-medium font-['Inter'] leading-loose">
|
<div className="justify-start text-zinc-300 text-xl font-medium font-['Inter'] leading-loose">
|
||||||
@@ -107,7 +107,7 @@ export const FigmaQuestion: React.FC<FigmaQuestionProps> = ({
|
|||||||
className="px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
|
className="px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">
|
||||||
{nextLabel}
|
{nextLabel}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -269,7 +269,7 @@ export const FigmaNavigationButtons: React.FC<{
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import React from 'react';
|
import React, { useState, ReactNode } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { Button, PlusIcon, CopyIcon } from '../UiKit';
|
||||||
|
import { useOrg } from '../../contexts/OrgContext';
|
||||||
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
companyName?: string;
|
companyName?: string;
|
||||||
@@ -7,8 +10,36 @@ interface SidebarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Sidebar({ companyName = "Zitlac Media", collapsed = false }: SidebarProps) {
|
export default function Sidebar({ companyName = "Zitlac Media", collapsed = false }: SidebarProps) {
|
||||||
|
const { org, issueInviteViaApi } = useOrg();
|
||||||
|
const { signOutUser } = useAuth();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [showInviteModal, setShowInviteModal] = useState(false);
|
||||||
|
const [inviteForm, setInviteForm] = useState({ name: '', email: '', role: '', department: '' });
|
||||||
|
const [inviteLink, setInviteLink] = useState('');
|
||||||
|
const [emailLink, setEmailLink] = useState('');
|
||||||
|
|
||||||
|
const handleInvite = async () => {
|
||||||
|
try {
|
||||||
|
const result = await issueInviteViaApi({
|
||||||
|
name: inviteForm.name,
|
||||||
|
email: inviteForm.email,
|
||||||
|
role: inviteForm.role,
|
||||||
|
department: inviteForm.department
|
||||||
|
});
|
||||||
|
setInviteLink(result.inviteLink);
|
||||||
|
// if (process.env.SENDGRID_API_KEY) {
|
||||||
|
// setEmailLink(result.emailLink);
|
||||||
|
// }
|
||||||
|
setInviteForm({ name: '', email: '', role: '', department: '' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to invite employee:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyToClipboard = (text: string) => {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
};
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{
|
{
|
||||||
@@ -186,6 +217,116 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{showInviteModal && (
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
|
<div className="bg-[--background-secondary] p-6 rounded-lg max-w-md w-full mx-4">
|
||||||
|
<h3 className="text-lg font-semibold text-[--text-primary] mb-4">Invite Employee</h3>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-[--text-primary] mb-2">Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={inviteForm.name}
|
||||||
|
onChange={(e) => setInviteForm(prev => ({ ...prev, name: e.target.value }))}
|
||||||
|
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-primary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
placeholder="Employee name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-[--text-primary] mb-2">Email</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
value={inviteForm.email}
|
||||||
|
onChange={(e) => setInviteForm(prev => ({ ...prev, email: e.target.value }))}
|
||||||
|
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-primary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
placeholder="employee@company.com"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-[--text-primary] mb-2">Role</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={inviteForm.role}
|
||||||
|
onChange={(e) => setInviteForm(prev => ({ ...prev, role: e.target.value }))}
|
||||||
|
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-primary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
placeholder="e.g. Software Engineer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-[--text-primary] mb-2">Department</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={inviteForm.department}
|
||||||
|
onChange={(e) => setInviteForm(prev => ({ ...prev, department: e.target.value }))}
|
||||||
|
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-primary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
placeholder="e.g. Engineering"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{(inviteLink || emailLink) && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
{emailLink && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-[--text-primary] mb-2">
|
||||||
|
Email Link (for GET requests)
|
||||||
|
</label>
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={emailLink}
|
||||||
|
readOnly
|
||||||
|
className="flex-1 px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-primary] text-[--text-primary] focus:outline-none text-sm"
|
||||||
|
/>
|
||||||
|
<Button size="sm" onClick={() => copyToClipboard(emailLink)}>
|
||||||
|
<CopyIcon className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{inviteLink && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-[--text-primary] mb-2">
|
||||||
|
App Link (direct)
|
||||||
|
</label>
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={inviteLink}
|
||||||
|
readOnly
|
||||||
|
className="flex-1 px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-primary] text-[--text-primary] focus:outline-none text-sm"
|
||||||
|
/>
|
||||||
|
<Button size="sm" onClick={() => copyToClipboard(inviteLink)}>
|
||||||
|
<CopyIcon className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex space-x-2 mt-6">
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
className="flex-1"
|
||||||
|
onClick={() => {
|
||||||
|
setShowInviteModal(false);
|
||||||
|
setInviteLink('');
|
||||||
|
setInviteForm({ name: '', email: '', role: '', department: '' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="flex-1"
|
||||||
|
onClick={handleInvite}
|
||||||
|
disabled={!inviteForm.name || !inviteForm.email}
|
||||||
|
>
|
||||||
|
Generate Invite
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Bottom Section */}
|
{/* Bottom Section */}
|
||||||
<div className="self-stretch flex flex-col justify-start items-start gap-3">
|
<div className="self-stretch flex flex-col justify-start items-start gap-3">
|
||||||
{/* Settings */}
|
{/* Settings */}
|
||||||
@@ -224,30 +365,18 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
|
|||||||
</div>
|
</div>
|
||||||
<div className="self-stretch px-3 pb-3 flex flex-col justify-start items-start gap-8">
|
<div className="self-stretch px-3 pb-3 flex flex-col justify-start items-start gap-8">
|
||||||
<div className="self-stretch inline-flex justify-start items-start gap-2">
|
<div className="self-stretch inline-flex justify-start items-start gap-2">
|
||||||
<div className="flex-1 px-3 py-1.5 bg-[--Neutrals-NeutralSlate100] rounded-[999px] flex justify-center items-center gap-0.5 overflow-hidden">
|
<Button size="sm" className="w-full" onClick={() => setShowInviteModal(true)}>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<PlusIcon className="w-4 h-4 mr-1" /> Invite
|
||||||
<div className="justify-center text-[--Neutrals-NeutralSlate950] text-sm font-medium font-['Inter'] leading-tight">Invite</div>
|
</Button>
|
||||||
</div>
|
|
||||||
<div>
|
<Button size="sm" variant="secondary" className="w-full" onClick={() => (emailLink || inviteLink) && copyToClipboard(emailLink || inviteLink)}>
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<CopyIcon className="w-4 h-4 mr-1" /> Copy
|
||||||
<path d="M7.99967 3.33333V12.6667M3.33301 8H12.6663" stroke="var(--Neutrals-NeutralSlate950, #0A0D12)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
</Button>
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 px-3 py-1.5 bg-[--Brand-Orange] rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
|
|
||||||
<div>
|
|
||||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M8.97203 12.2426L8.02922 13.1854C6.72748 14.4872 4.61693 14.4872 3.31518 13.1854C2.01343 11.8837 2.01343 9.77312 3.31518 8.47138L4.25799 7.52857M12.7433 8.47138L13.6861 7.52857C14.9878 6.22682 14.9878 4.11627 13.6861 2.81452C12.3843 1.51277 10.2738 1.51277 8.97203 2.81452L8.02922 3.75733M6.16729 10.3333L10.834 5.66662" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div className="px-1 flex justify-center items-center">
|
|
||||||
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Copy</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<Button size="sm" variant="ghost" className="w-full mt-2" onClick={signOutUser}>Sign out</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ export const FigmaOnboardingIntro: React.FC<FigmaOnboardingIntroProps> = ({
|
|||||||
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden hover:bg-[--Brand-Orange]/90 transition-colors"
|
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden hover:bg-[--Brand-Orange]/90 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -193,7 +193,7 @@ export const FigmaOnboardingQuestion: React.FC<FigmaOnboardingQuestionProps> = (
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[--Brand-Orange]/90 transition-colors"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[--Brand-Orange]/90 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -309,7 +309,7 @@ export const FigmaOnboardingMultipleChoice: React.FC<FigmaOnboardingMultipleChoi
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[--Brand-Orange]/90 transition-colors"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[--Brand-Orange]/90 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -448,7 +448,7 @@ export const FigmaOnboardingForm: React.FC<FigmaOnboardingFormProps> = ({
|
|||||||
className="self-stretch h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[--Brand-Orange]/90 transition-colors"
|
className="self-stretch h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[--Brand-Orange]/90 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ interface OrgContextType {
|
|||||||
upsertOrg: (data: Partial<OrgData>) => Promise<void>;
|
upsertOrg: (data: Partial<OrgData>) => Promise<void>;
|
||||||
saveReport: (employeeId: string, report: EmployeeReport) => Promise<void>;
|
saveReport: (employeeId: string, report: EmployeeReport) => Promise<void>;
|
||||||
inviteEmployee: (args: { name: string; email: string }) => Promise<{ employeeId: string; inviteLink: string }>;
|
inviteEmployee: (args: { name: string; email: string }) => Promise<{ employeeId: string; inviteLink: string }>;
|
||||||
issueInviteViaApi: (args: { name: string; email: string; role?: string; department?: string }) => Promise<{ code: string; inviteLink: string; emailLink: string; employee: any }>;
|
issueInviteViaApi: (args: { name: string; email: string; role?: string; department?: string }) => Promise<{ code: string; inviteLink: string; employee: any }>;
|
||||||
getInviteStatus: (code: string) => Promise<{ used: boolean; employee: any } | null>;
|
getInviteStatus: (code: string) => Promise<{ used: boolean; employee: any } | null>;
|
||||||
consumeInvite: (code: string) => Promise<{ employee: any; orgId?: string } | null>;
|
consumeInvite: (code: string) => Promise<{ employee: any; orgId?: string } | null>;
|
||||||
getReportVersions: (employeeId: string) => Promise<Array<{ id: string; createdAt: number; report: EmployeeReport }>>;
|
getReportVersions: (employeeId: string) => Promise<Array<{ id: string; createdAt: number; report: EmployeeReport }>>;
|
||||||
@@ -182,12 +182,12 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const inviteEmployee = async ({ name, email }: { name: string; email: string }) => {
|
const inviteEmployee = async ({ name, email, role, department }: { name: string; email: string, role?: string, department?: string }) => {
|
||||||
console.log('inviteEmployee called:', { name, email, orgId });
|
console.log('inviteEmployee called:', { name, email, orgId });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use secure API for invites
|
// Use secure API for invites
|
||||||
const data = await secureApi.createInvitation(name, email);
|
const data = await secureApi.createInvitation({ name, email, role, department });
|
||||||
|
|
||||||
console.log('Invite created successfully:', { code: data.code, employee: data.employee.name, inviteLink: data.inviteLink });
|
console.log('Invite created successfully:', { code: data.code, employee: data.employee.name, inviteLink: data.inviteLink });
|
||||||
|
|
||||||
@@ -199,7 +199,8 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
|||||||
initials: data.employee.name ? data.employee.name.split(' ').map(n => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase(),
|
initials: data.employee.name ? data.employee.name.split(' ').map(n => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase(),
|
||||||
department: data.employee.department,
|
department: data.employee.department,
|
||||||
role: data.employee.role,
|
role: data.employee.role,
|
||||||
isOwner: false
|
isOwner: false,
|
||||||
|
status: data.employee.status
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add to local state for immediate UI update
|
// Add to local state for immediate UI update
|
||||||
@@ -509,7 +510,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
|||||||
throw new Error('User authentication required');
|
throw new Error('User authentication required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await secureApi.createInvitation(name, email, role, department);
|
const data = await secureApi.createInvitation({ name, email, role, department });
|
||||||
|
|
||||||
// Optimistically add employee shell (not yet active until consume)
|
// Optimistically add employee shell (not yet active until consume)
|
||||||
setEmployees(prev => prev.find(e => e.id === data.employee.id) ? prev : [...prev, {
|
setEmployees(prev => prev.find(e => e.id === data.employee.id) ? prev : [...prev, {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ const YesNoChoice: React.FC<{
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,7 +164,7 @@ const SectionIntro: React.FC<{
|
|||||||
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden"
|
className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -363,7 +363,7 @@ const EmployeeFormStep2: React.FC<{ onNext: (data: any) => void; onBack: () => v
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1146,7 +1146,7 @@ const EmployeeFormStep35: React.FC<{ onNext: () => void; onBack: () => void }> =
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1238,7 +1238,7 @@ const EmployeeFormStep36: React.FC<{ onNext: () => void; onBack: () => void }> =
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1330,7 +1330,7 @@ const EmployeeFormStep37: React.FC<{ onNext: () => void; onBack: () => void }> =
|
|||||||
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden"
|
className="flex-1 h-12 px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Submit</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Submit</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1453,7 +1453,7 @@ const EmployeeFormStep38: React.FC<{ formData: any }> = ({ formData }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden">
|
<div className="self-stretch px-4 py-3.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden">
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ const EmployeeQuestionnaire: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
||||||
<div className="max-w-4xl mx-auto text-center">
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
<div className="w-16 h-16 bg-[--Brand-Orange] rounded-full flex items-center justify-center font-bold text-Other-White text-2xl mx-auto mb-4">
|
<div className="w-16 h-16 bg-[--Brand-Orange] rounded-full flex items-center justify-center font-bold text-white text-2xl mx-auto mb-4">
|
||||||
A
|
A
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-3xl font-bold text-[--Neutrals-NeutralSlate950] mb-4">Loading Your Invitation...</h1>
|
<h1 className="text-3xl font-bold text-[--Neutrals-NeutralSlate950] mb-4">Loading Your Invitation...</h1>
|
||||||
@@ -174,14 +174,14 @@ const EmployeeQuestionnaire: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
||||||
<div className="max-w-4xl mx-auto text-center">
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
<div className="w-16 h-16 bg-red-500 rounded-full flex items-center justify-center font-bold text-Other-White text-2xl mx-auto mb-4">
|
<div className="w-16 h-16 bg-red-500 rounded-full flex items-center justify-center font-bold text-white text-2xl mx-auto mb-4">
|
||||||
!
|
!
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-3xl font-bold text-[--Neutrals-NeutralSlate950] mb-4">Invitation Error</h1>
|
<h1 className="text-3xl font-bold text-[--Neutrals-NeutralSlate950] mb-4">Invitation Error</h1>
|
||||||
<p className="text-[--Neutrals-NeutralSlate500] mb-6">{error}</p>
|
<p className="text-[--Neutrals-NeutralSlate500] mb-6">{error}</p>
|
||||||
<button
|
<button
|
||||||
onClick={() => window.location.href = '/'}
|
onClick={() => window.location.href = '/'}
|
||||||
className="px-6 py-3 bg-[--Brand-Orange] text-Other-White rounded-lg hover:bg-orange-600"
|
className="px-6 py-3 bg-[--Brand-Orange] text-white rounded-lg hover:bg-orange-600"
|
||||||
>
|
>
|
||||||
Return to Homepage
|
Return to Homepage
|
||||||
</button>
|
</button>
|
||||||
@@ -575,7 +575,7 @@ const EmployeeQuestionnaire: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
||||||
<div className="max-w-4xl mx-auto text-center">
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
<div className="w-16 h-16 bg-[--Brand-Orange] rounded-full flex items-center justify-center font-bold text-Other-White text-2xl mx-auto mb-4 animate-pulse">
|
<div className="w-16 h-16 bg-[--Brand-Orange] rounded-full flex items-center justify-center font-bold text-white text-2xl mx-auto mb-4 animate-pulse">
|
||||||
A
|
A
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-3xl font-bold text-[--Neutrals-NeutralSlate950] mb-4">Submitting Your Responses...</h1>
|
<h1 className="text-3xl font-bold text-[--Neutrals-NeutralSlate950] mb-4">Submitting Your Responses...</h1>
|
||||||
@@ -586,7 +586,7 @@ const EmployeeQuestionnaire: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white">
|
<div className="flex h-screen bg-[--Neutrals-NeutralSlate0]">
|
||||||
{renderStep()}
|
{renderStep()}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="fixed bottom-4 right-4 bg-red-500 text-white p-4 rounded-lg shadow-lg z-50">
|
<div className="fixed bottom-4 right-4 bg-red-500 text-white p-4 rounded-lg shadow-lg z-50">
|
||||||
|
|||||||
@@ -116,11 +116,11 @@ const HelpNew: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M5.58685 5.90223C6.05085 6.86865 6.68337 7.77441 7.48443 8.57546C8.28548 9.37651 9.19124 10.009 10.1577 10.473C10.2408 10.5129 10.2823 10.5329 10.3349 10.5482C10.5218 10.6027 10.7513 10.5636 10.9096 10.4502C10.9542 10.4183 10.9923 10.3802 11.0685 10.304C11.3016 10.071 11.4181 9.95443 11.5353 9.87824C11.9772 9.59091 12.5469 9.59091 12.9889 9.87824C13.106 9.95443 13.2226 10.071 13.4556 10.304L13.5856 10.4339C13.9398 10.7882 14.117 10.9654 14.2132 11.1556C14.4046 11.534 14.4046 11.9809 14.2132 12.3592C14.117 12.5495 13.9399 12.7266 13.5856 13.0809L13.4805 13.186C13.1274 13.5391 12.9508 13.7156 12.7108 13.8505C12.4445 14.0001 12.0308 14.1077 11.7253 14.1068C11.45 14.1059 11.2619 14.0525 10.8856 13.9457C8.86333 13.3718 6.95509 12.2888 5.36311 10.6968C3.77112 9.10479 2.68814 7.19655 2.11416 5.17429C2.00735 4.79799 1.95395 4.60984 1.95313 4.33455C1.95222 4.02906 2.0598 3.6154 2.20941 3.34907C2.34424 3.10904 2.52078 2.9325 2.87386 2.57942L2.97895 2.47433C3.33325 2.12004 3.5104 1.94289 3.70065 1.84666C4.07903 1.65528 4.52587 1.65528 4.90424 1.84666C5.0945 1.94289 5.27164 2.12004 5.62594 2.47433L5.75585 2.60424C5.98892 2.83732 6.10546 2.95385 6.18165 3.07104C6.46898 3.51296 6.46898 4.08268 6.18165 4.52461C6.10546 4.6418 5.98892 4.75833 5.75585 4.9914C5.67964 5.06761 5.64154 5.10571 5.60965 5.15026C5.4963 5.30854 5.45717 5.53805 5.51165 5.72495C5.52698 5.77754 5.54694 5.81911 5.58685 5.90223Z" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M5.58685 5.90223C6.05085 6.86865 6.68337 7.77441 7.48443 8.57546C8.28548 9.37651 9.19124 10.009 10.1577 10.473C10.2408 10.5129 10.2823 10.5329 10.3349 10.5482C10.5218 10.6027 10.7513 10.5636 10.9096 10.4502C10.9542 10.4183 10.9923 10.3802 11.0685 10.304C11.3016 10.071 11.4181 9.95443 11.5353 9.87824C11.9772 9.59091 12.5469 9.59091 12.9889 9.87824C13.106 9.95443 13.2226 10.071 13.4556 10.304L13.5856 10.4339C13.9398 10.7882 14.117 10.9654 14.2132 11.1556C14.4046 11.534 14.4046 11.9809 14.2132 12.3592C14.117 12.5495 13.9399 12.7266 13.5856 13.0809L13.4805 13.186C13.1274 13.5391 12.9508 13.7156 12.7108 13.8505C12.4445 14.0001 12.0308 14.1077 11.7253 14.1068C11.45 14.1059 11.2619 14.0525 10.8856 13.9457C8.86333 13.3718 6.95509 12.2888 5.36311 10.6968C3.77112 9.10479 2.68814 7.19655 2.11416 5.17429C2.00735 4.79799 1.95395 4.60984 1.95313 4.33455C1.95222 4.02906 2.0598 3.6154 2.20941 3.34907C2.34424 3.10904 2.52078 2.9325 2.87386 2.57942L2.97895 2.47433C3.33325 2.12004 3.5104 1.94289 3.70065 1.84666C4.07903 1.65528 4.52587 1.65528 4.90424 1.84666C5.0945 1.94289 5.27164 2.12004 5.62594 2.47433L5.75585 2.60424C5.98892 2.83732 6.10546 2.95385 6.18165 3.07104C6.46898 3.51296 6.46898 4.08268 6.18165 4.52461C6.10546 4.6418 5.98892 4.75833 5.75585 4.9914C5.67964 5.06761 5.64154 5.10571 5.60965 5.15026C5.4963 5.30854 5.45717 5.53805 5.51165 5.72495C5.52698 5.77754 5.54694 5.81911 5.58685 5.90223Z" stroke="var(--white, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Contact Us</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Contact Us</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ const ModernLogin: React.FC = () => {
|
|||||||
} transition-all duration-200`}
|
} transition-all duration-200`}
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className={`justify-center text-sm font-medium font-['Inter'] leading-tight ${hasEmail && !isLoading ? 'text-Other-White' : 'text-[--Neutrals-NeutralSlate500]'}`}>
|
<div className={`justify-center text-sm font-medium font-['Inter'] leading-tight ${hasEmail && !isLoading ? 'text-white' : 'text-[--Neutrals-NeutralSlate500]'}`}>
|
||||||
{isLoading ? 'Sending...' : 'Continue'}
|
{isLoading ? 'Sending...' : 'Continue'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -422,7 +422,7 @@ const ModernLogin: React.FC = () => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className={`justify-center text-sm font-medium font-['Inter'] leading-tight ${allOtpFilled && !isLoading ? 'text-Other-White' : 'text-[--Neutrals-NeutralSlate500]'
|
<div className={`justify-center text-sm font-medium font-['Inter'] leading-tight ${allOtpFilled && !isLoading ? 'text-white' : 'text-[--Neutrals-NeutralSlate500]'
|
||||||
}`}>
|
}`}>
|
||||||
{isLoading ? 'Verifying...' : 'Continue'}
|
{isLoading ? 'Verifying...' : 'Continue'}
|
||||||
</div>
|
</div>
|
||||||
@@ -498,7 +498,7 @@ const ModernLogin: React.FC = () => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className={`justify-center text-sm font-medium font-['Inter'] leading-tight ${password.trim() && !isLoading ? 'text-Other-White' : 'text-[--Neutrals-NeutralSlate500]'
|
<div className={`justify-center text-sm font-medium font-['Inter'] leading-tight ${password.trim() && !isLoading ? 'text-white' : 'text-[--Neutrals-NeutralSlate500]'
|
||||||
}`}>
|
}`}>
|
||||||
{isLoading ? 'Signing in...' : 'Sign In'}
|
{isLoading ? 'Signing in...' : 'Sign In'}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -663,11 +663,11 @@ const EmployeeReportContent: React.FC<{
|
|||||||
<div className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden">
|
<div className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M14 14H2M12 7.33333L8 11.3333M8 11.3333L4 7.33333M8 11.3333V2" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M14 14H2M12 7.33333L8 11.3333M8 11.3333L4 7.33333M8 11.3333V2" stroke="var(--white, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Download as PDF</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Download as PDF</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ const SettingsNew: React.FC = () => {
|
|||||||
className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden cursor-pointer hover:bg-[--Brand-Orange]/90"
|
className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden cursor-pointer hover:bg-[--Brand-Orange]/90"
|
||||||
>
|
>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Save Changes</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Save Changes</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const Submissions: React.FC = () => {
|
|||||||
const data = { submissions: [] }; // temp fix
|
const data = { submissions: [] }; // temp fix
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
setSubmissions(data.submissions);
|
// setSubmissions(data.submissions);
|
||||||
|
|
||||||
// Auto-select first employee with submission
|
// Auto-select first employee with submission
|
||||||
const employeesWithSubmissions = employees.filter(emp => data.submissions?.[emp.id]);
|
const employeesWithSubmissions = employees.filter(emp => data.submissions?.[emp.id]);
|
||||||
@@ -41,7 +41,7 @@ const Submissions: React.FC = () => {
|
|||||||
setSelectedEmployee(employeesWithSubmissions[0]);
|
setSelectedEmployee(employeesWithSubmissions[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to load submissions:', response.statusText);
|
// console.error('Failed to load submissions:', response.statusText);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading submissions:', error);
|
console.error('Error loading submissions:', error);
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ const ChatAIResponse: React.FC = () => {
|
|||||||
<div className="flex-1 px-3 py-1.5 bg-[--Brand-Orange] rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
|
<div className="flex-1 px-3 py-1.5 bg-[--Brand-Orange] rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M8.97179 12.2442L8.02898 13.1871C6.72723 14.4888 4.61668 14.4888 3.31493 13.1871C2.01319 11.8853 2.01319 9.77476 3.31493 8.47301L4.25774 7.5302M12.743 8.47301L13.6858 7.5302C14.9876 6.22845 14.9876 4.1179 13.6858 2.81615C12.3841 1.51441 10.2735 1.51441 8.97179 2.81615L8.02898 3.75896M6.16705 10.3349L10.8337 5.66826" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M8.97179 12.2442L8.02898 13.1871C6.72723 14.4888 4.61668 14.4888 3.31493 13.1871C2.01319 11.8853 2.01319 9.77476 3.31493 8.47301L4.25774 7.5302M12.743 8.47301L13.6858 7.5302C14.9876 6.22845 14.9876 4.1179 13.6858 2.81615C12.3841 1.51441 10.2735 1.51441 8.97179 2.81615L8.02898 3.75896M6.16705 10.3349L10.8337 5.66826" stroke="var(--white, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Copy</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Copy</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -130,11 +130,11 @@ const ChatLight: React.FC = () => {
|
|||||||
<div className="flex-1 px-3 py-1.5 bg-[--Brand-Orange] rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
|
<div className="flex-1 px-3 py-1.5 bg-[--Brand-Orange] rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M8.97167 12.2423L8.02886 13.1851C6.72711 14.4868 4.61656 14.4868 3.31481 13.1851C2.01306 11.8834 2.01306 9.7728 3.31481 8.47106L4.25762 7.52825M12.7429 8.47106L13.6857 7.52825C14.9875 6.2265 14.9875 4.11595 13.6857 2.8142C12.384 1.51245 10.2734 1.51245 8.97167 2.8142L8.02886 3.75701M6.16693 10.333L10.8336 5.6663" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M8.97167 12.2423L8.02886 13.1851C6.72711 14.4868 4.61656 14.4868 3.31481 13.1851C2.01306 11.8834 2.01306 9.7728 3.31481 8.47106L4.25762 7.52825M12.7429 8.47106L13.6857 7.52825C14.9875 6.2265 14.9875 4.11595 13.6857 2.8142C12.384 1.51245 10.2734 1.51245 8.97167 2.8142L8.02886 3.75701M6.16693 10.333L10.8336 5.6663" stroke="var(--white, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-1 flex justify-center items-center">
|
<div className="px-1 flex justify-center items-center">
|
||||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Copy</div>
|
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Copy</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -71,6 +71,20 @@ interface JoinOrganization {
|
|||||||
success: boolean;
|
success: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CreateInvitation {
|
||||||
|
success: boolean;
|
||||||
|
code: string;
|
||||||
|
employee: Employee;
|
||||||
|
inviteLink: string;
|
||||||
|
message: "Invitation sent successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConsumeInvitation {
|
||||||
|
success: boolean;
|
||||||
|
orgId: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface CreateCheckoutSession {
|
interface CreateCheckoutSession {
|
||||||
success: true;
|
success: true;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
@@ -222,14 +236,7 @@ class SecureApiService {
|
|||||||
return this.makeRequest('verifyOTP', 'POST', { email, otp }, false);
|
return this.makeRequest('verifyOTP', 'POST', { email, otp }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createInvitation(name: string, email: string, role?: string, department?: string): Promise<{
|
async createInvitation({ name, email, role, department }: { name: string, email: string, role?: string, department?: string }): Promise<CreateInvitation> {
|
||||||
success: boolean;
|
|
||||||
code: string;
|
|
||||||
employee: Employee;
|
|
||||||
inviteLink: string;
|
|
||||||
emailLink: string;
|
|
||||||
message: string;
|
|
||||||
}> {
|
|
||||||
return this.makeRequest('createInvitation', 'POST', { name, email, role, department });
|
return this.makeRequest('createInvitation', 'POST', { name, email, role, department });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +248,7 @@ class SecureApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async consumeInvitation(code: string, userId?: string) {
|
async consumeInvitation(code: string, userId?: string): Promise<ConsumeInvitation> {
|
||||||
return this.makeRequest('consumeInvitation', 'POST', { code, userId });
|
return this.makeRequest('consumeInvitation', 'POST', { code, userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
src/types.ts
12
src/types.ts
@@ -10,13 +10,17 @@ export enum Theme {
|
|||||||
export interface Employee {
|
export interface Employee {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
initials: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
department?: string;
|
role?: 'owner' | 'admin' | 'employee';
|
||||||
role?: string;
|
department?: string | 'General';
|
||||||
isOwner?: boolean; // Company owner/HR access
|
joinedAt?: number;
|
||||||
|
status: 'invited' | 'active';
|
||||||
|
initials?: string;
|
||||||
|
inviteCode?: string;
|
||||||
|
isOwner?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface UserOrganization {
|
export interface UserOrganization {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user