update 9/23

This commit is contained in:
Ra
2025-09-23 09:53:05 -07:00
parent b41f489fe6
commit 5b5bf76c9a
22 changed files with 8769 additions and 8316 deletions

View File

@@ -4,6 +4,9 @@ import { Button, PlusIcon, CopyIcon } from '../UiKit';
import { useOrg } from '../../contexts/OrgContext';
import { useAuth } from '../../contexts/AuthContext';
import { useUserOrganizations } from '../../contexts/UserOrganizationsContext';
import { FigmaPrimaryButton, FigmaSecondaryButton } from './FigmaButton';
import { FigmaIcons } from './figmaIcon';
import { FigmaInviteEmployeesModal } from './FigmaInviteEmployeesModal';
interface SidebarProps {
companyName?: string;
@@ -19,7 +22,6 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
const [showInviteModal, setShowInviteModal] = useState(false);
const [showOrgDropdown, setShowOrgDropdown] = useState(false);
const [showCreateOrgModal, setShowCreateOrgModal] = useState(false);
const [inviteForm, setInviteForm] = useState({ name: '', email: '', role: '', department: '' });
const [createOrgForm, setCreateOrgForm] = useState({ name: '', description: '' });
const [inviteLink, setInviteLink] = useState('');
const [emailLink, setEmailLink] = useState('');
@@ -55,21 +57,33 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
setShowOrgDropdown(false);
};
const handleInvite = async () => {
const handleInvite = async (emails: string[]) => {
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: '' });
// Send invitations for multiple emails
const results = await Promise.allSettled(
emails.map(email => issueInviteViaApi({
name: '', // Name can be extracted from email or left empty
email: email,
role: '',
department: ''
}))
);
// Check for any successful invites to generate links
const successfulResults = results.filter(result => result.status === 'fulfilled') as PromiseFulfilledResult<any>[];
if (successfulResults.length > 0) {
// Use the first successful result for link generation
const result = successfulResults[0].value;
setInviteLink(result.inviteLink);
// if (process.env.SENDGRID_API_KEY) {
// setEmailLink(result.emailLink);
// }
}
console.log(`Successfully sent ${successfulResults.length} invitations out of ${emails.length}`);
} catch (error) {
console.error('Failed to invite employee:', error);
console.error('Failed to invite employees:', error);
throw error;
}
};
@@ -387,116 +401,16 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
</div>
)}
{/* Invite Employee Modal */}
{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>
)}
{/* Figma Invite Employee Modal */}
<FigmaInviteEmployeesModal
isOpen={showInviteModal}
onClose={() => {
setShowInviteModal(false);
setInviteLink('');
setEmailLink('');
}}
onInvite={handleInvite}
/>
{/* Bottom Section */}
<div className="self-stretch flex flex-col justify-start items-start gap-3">
@@ -546,13 +460,18 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
</div>
<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">
<Button variant="secondary" size="sm" className="w-full rounded-[999px]" onClick={() => setShowInviteModal(true)}>
{/* <Button variant="secondary" size="sm" className="w-full rounded-[999px]" onClick={() => setShowInviteModal(true)}>
<PlusIcon className="w-4 h-4 mr-1" /> Invite
</Button>
</Button> */}
<FigmaSecondaryButton iconLeft={<FigmaIcons.PlusIcon size="16" />} buttonExtra="w-full" size="tiny" text="Invite" onClick={() => {
console.log('Figma Sidebar invite button clicked');
setShowInviteModal(true);
}} />
<FigmaPrimaryButton iconLeft={<FigmaIcons.LinkIcon size="16" />} buttonExtra="w-full" size="tiny" text="Copy" onClick={() => (emailLink || inviteLink) && copyToClipboard(emailLink || inviteLink)} />
{/*
<Button size="sm" variant="primary" className="w-full rounded-[999px]" onClick={() => (emailLink || inviteLink) && copyToClipboard(emailLink || inviteLink)}>
<CopyIcon className="mr-2" /> Copy
</Button>
</Button> */}
</div>
</div>
</div>