invite button and can navigate to submissions (no submissions will appear yet)
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import React from 'react';
|
||||
import React, { useState, ReactNode } from 'react';
|
||||
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 {
|
||||
companyName?: string;
|
||||
@@ -7,8 +10,36 @@ interface SidebarProps {
|
||||
}
|
||||
|
||||
export default function Sidebar({ companyName = "Zitlac Media", collapsed = false }: SidebarProps) {
|
||||
const { org, issueInviteViaApi } = useOrg();
|
||||
const { signOutUser } = useAuth();
|
||||
const location = useLocation();
|
||||
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 = [
|
||||
{
|
||||
@@ -186,6 +217,116 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
|
||||
</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 */}
|
||||
<div className="self-stretch flex flex-col justify-start items-start gap-3">
|
||||
{/* Settings */}
|
||||
@@ -224,30 +365,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">
|
||||
<div className="flex-1 px-3 py-1.5 bg-[--Neutrals-NeutralSlate100] rounded-[999px] flex justify-center items-center gap-0.5 overflow-hidden">
|
||||
<div className="px-1 flex justify-center items-center">
|
||||
<div className="justify-center text-[--Neutrals-NeutralSlate950] text-sm font-medium font-['Inter'] leading-tight">Invite</div>
|
||||
</div>
|
||||
<div>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.99967 3.33333V12.6667M3.33301 8H12.6663" stroke="var(--Neutrals-NeutralSlate950, #0A0D12)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</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>
|
||||
<Button size="sm" className="w-full" onClick={() => setShowInviteModal(true)}>
|
||||
<PlusIcon className="w-4 h-4 mr-1" /> Invite
|
||||
</Button>
|
||||
|
||||
<Button size="sm" variant="secondary" className="w-full" onClick={() => (emailLink || inviteLink) && copyToClipboard(emailLink || inviteLink)}>
|
||||
<CopyIcon className="w-4 h-4 mr-1" /> Copy
|
||||
</Button>
|
||||
</div>
|
||||
<Button size="sm" variant="ghost" className="w-full mt-2" onClick={signOutUser}>Sign out</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user