Files
auditly/src/components/figma/Sidebar.tsx
2025-08-26 11:23:27 -07:00

563 lines
46 KiB
TypeScript

import React, { useState, ReactNode, useRef, useEffect } 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';
import { useUserOrganizations } from '../../contexts/UserOrganizationsContext';
interface SidebarProps {
companyName?: string;
collapsed?: boolean;
}
export default function Sidebar({ companyName = "Zitlac Media", collapsed = false }: SidebarProps) {
const { org, issueInviteViaApi } = useOrg();
const { createOrganization, selectOrganization, organizations, refreshOrganizations } = useUserOrganizations();
const { signOutUser } = useAuth();
const location = useLocation();
const navigate = useNavigate();
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('');
const dropdownRef = useRef<HTMLDivElement>(null);
// Close dropdown when clicking outside
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setShowOrgDropdown(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const handleCreateOrg = async () => {
try {
let { orgId } = await createOrganization(
createOrgForm.name
);
setCreateOrgForm({ name: '', description: '' });
setShowCreateOrgModal(false);
selectOrganization(orgId);
navigate(`/company-wiki`);
} catch (error) {
console.error('Failed to create organization:', error);
}
};
const handleOrgSwitch = (orgId: string) => {
selectOrganization(orgId);
setShowOrgDropdown(false);
};
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 = [
{
icon: (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 17.5V11.3333C7.5 10.8666 7.5 10.6333 7.59083 10.455C7.67072 10.2982 7.79821 10.1707 7.95501 10.0908C8.13327 9.99999 8.36662 9.99999 8.83333 9.99999H11.1667C11.6334 9.99999 11.8667 9.99999 12.045 10.0908C12.2018 10.1707 12.3293 10.2982 12.4092 10.455C12.5 10.6333 12.5 10.8666 12.5 11.3333V17.5M9.18141 2.30333L3.52949 6.69927C3.15168 6.99312 2.96278 7.14005 2.82669 7.32405C2.70614 7.48704 2.61633 7.67065 2.56169 7.86588C2.5 8.08627 2.5 8.32558 2.5 8.80421V14.8333C2.5 15.7667 2.5 16.2335 2.68166 16.59C2.84144 16.9036 3.09641 17.1585 3.41002 17.3183C3.76654 17.5 4.23325 17.5 5.16667 17.5H14.8333C15.7668 17.5 16.2335 17.5 16.59 17.3183C16.9036 17.1585 17.1586 16.9036 17.3183 16.59C17.5 16.2335 17.5 15.7667 17.5 14.8333V8.80421C17.5 8.32558 17.5 8.08627 17.4383 7.86588C17.3837 7.67065 17.2939 7.48704 17.1733 7.32405C17.0372 7.14005 16.8483 6.99312 16.4705 6.69927L10.8186 2.30333C10.5258 2.07562 10.3794 1.96177 10.2178 1.918C10.0752 1.87938 9.92484 1.87938 9.78221 1.918C9.62057 1.96177 9.47418 2.07562 9.18141 2.30333Z" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
),
label: "Company Wiki",
path: "/company-wiki",
active: location.pathname === "/company-wiki"
},
{
icon: (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6663 9.16666H6.66634M8.33301 12.5H6.66634M13.333 5.83332H6.66634M16.6663 5.66666V14.3333C16.6663 15.7335 16.6663 16.4335 16.3939 16.9683C16.1542 17.4387 15.7717 17.8212 15.3013 18.0608C14.7665 18.3333 14.0665 18.3333 12.6663 18.3333H7.33301C5.93288 18.3333 5.23281 18.3333 4.69803 18.0608C4.22763 17.8212 3.84517 17.4387 3.60549 16.9683C3.33301 16.4335 3.33301 15.7335 3.33301 14.3333V5.66666C3.33301 4.26653 3.33301 3.56646 3.60549 3.03168C3.84517 2.56128 4.22763 2.17882 4.69803 1.93914C5.23281 1.66666 5.93288 1.66666 7.33301 1.66666H12.6663C14.0665 1.66666 14.7665 1.66666 15.3013 1.93914C15.7717 2.17882 16.1542 2.56128 16.3939 3.03168C16.6663 3.56646 16.6663 4.26653 16.6663 5.66666Z" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
),
label: "Submissions",
path: "/submissions",
active: location.pathname === "/submissions"
},
{
icon: (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_914_468)">
<path d="M10.0003 1.66666C11.0947 1.66666 12.1783 1.8822 13.1894 2.30099C14.2004 2.71978 15.1191 3.33361 15.8929 4.10744C16.6667 4.88126 17.2805 5.79992 17.6993 6.81097C18.1181 7.82201 18.3337 8.90565 18.3337 10M10.0003 1.66666V9.99999M10.0003 1.66666C5.39795 1.66666 1.66699 5.39762 1.66699 9.99999C1.66699 14.6024 5.39795 18.3333 10.0003 18.3333C14.6027 18.3333 18.3337 14.6024 18.3337 10M10.0003 1.66666C14.6027 1.66666 18.3337 5.39762 18.3337 10M18.3337 10L10.0003 9.99999M18.3337 10C18.3337 11.3151 18.0224 12.6115 17.4254 13.7832C16.8283 14.955 15.9625 15.9688 14.8985 16.7418L10.0003 9.99999" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_914_468">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
),
label: "Reports",
path: "/reports",
active: location.pathname === "/reports" || location.pathname === "/"
},
{
icon: (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.4999 9.58333C17.4999 13.4953 14.3285 16.6667 10.4165 16.6667C9.5192 16.6667 8.66086 16.4998 7.87081 16.1954C7.72637 16.1398 7.65415 16.112 7.59671 16.0987C7.54022 16.0857 7.49933 16.0803 7.4414 16.0781C7.3825 16.0758 7.31789 16.0825 7.18865 16.0958L2.92113 16.537C2.51427 16.579 2.31083 16.6001 2.19083 16.5269C2.08631 16.4631 2.01512 16.3566 1.99617 16.2356C1.97441 16.0968 2.07162 15.9168 2.26605 15.557L3.62909 13.034C3.74135 12.8262 3.79747 12.7223 3.82289 12.6225C3.848 12.5238 3.85407 12.4527 3.84604 12.3512C3.83791 12.2484 3.79283 12.1147 3.70266 11.8472C3.46306 11.1363 3.33318 10.375 3.33318 9.58333C3.33318 5.67132 6.5045 2.5 10.4165 2.5C14.3285 2.5 17.4999 5.67132 17.4999 9.58333Z" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
),
label: "Chat",
path: "/chat",
active: location.pathname === "/chat"
},
{
icon: (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_914_474)">
<path d="M7.57533 7.50001C7.77125 6.94306 8.15795 6.47343 8.66695 6.17428C9.17596 5.87514 9.77441 5.76579 10.3563 5.8656C10.9382 5.96541 11.466 6.26794 11.8462 6.71961C12.2264 7.17128 12.4345 7.74294 12.4337 8.33334C12.4337 10 9.93366 10.8333 9.93366 10.8333M10.0003 14.1667H10.0087M18.3337 10C18.3337 14.6024 14.6027 18.3333 10.0003 18.3333C5.39795 18.3333 1.66699 14.6024 1.66699 10C1.66699 5.39763 5.39795 1.66667 10.0003 1.66667C14.6027 1.66667 18.3337 5.39763 18.3337 10Z" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_914_474">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
),
label: "Help",
path: "/help",
active: location.pathname === "/help"
}
];
const settingsIcon = (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_914_477)">
<path d="M10.0003 12.5C11.381 12.5 12.5003 11.3807 12.5003 10C12.5003 8.61929 11.381 7.5 10.0003 7.5C8.61961 7.5 7.50033 8.61929 7.50033 10C7.50033 11.3807 8.61961 12.5 10.0003 12.5Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M15.6064 12.2727C15.5055 12.5012 15.4755 12.7547 15.52 13.0004C15.5646 13.2462 15.6817 13.473 15.8564 13.6515L15.9018 13.697C16.0427 13.8377 16.1545 14.0048 16.2307 14.1887C16.307 14.3727 16.3462 14.5698 16.3462 14.7689C16.3462 14.9681 16.307 15.1652 16.2307 15.3492C16.1545 15.5331 16.0427 15.7002 15.9018 15.8409C15.7611 15.9818 15.594 16.0935 15.4101 16.1698C15.2261 16.246 15.029 16.2853 14.8299 16.2853C14.6308 16.2853 14.4336 16.246 14.2497 16.1698C14.0657 16.0935 13.8986 15.9818 13.7579 15.8409L13.7124 15.7955C13.5339 15.6208 13.3071 15.5036 13.0614 15.4591C12.8156 15.4145 12.5622 15.4446 12.3337 15.5455C12.1096 15.6415 11.9185 15.8009 11.7839 16.0042C11.6493 16.2074 11.5771 16.4456 11.5761 16.6894V16.8182C11.5761 17.22 11.4165 17.6054 11.1323 17.8896C10.8482 18.1737 10.4628 18.3333 10.0609 18.3333C9.65909 18.3333 9.2737 18.1737 8.98956 17.8896C8.70541 17.6054 8.54578 17.22 8.54578 16.8182V16.75C8.53991 16.4992 8.45875 16.2561 8.31283 16.052C8.16692 15.848 7.963 15.6926 7.7276 15.6061C7.4991 15.5052 7.24563 15.4751 6.99988 15.5197C6.75413 15.5643 6.52736 15.6814 6.34881 15.8561L6.30336 15.9015C6.16264 16.0424 5.99554 16.1541 5.8116 16.2304C5.62766 16.3066 5.4305 16.3459 5.23139 16.3459C5.03227 16.3459 4.83511 16.3066 4.65117 16.2304C4.46724 16.1541 4.30013 16.0424 4.15942 15.9015C4.01854 15.7608 3.90679 15.5937 3.83054 15.4098C3.75429 15.2258 3.71504 15.0287 3.71504 14.8295C3.71504 14.6304 3.75429 14.4333 3.83054 14.2493C3.90679 14.0654 4.01854 13.8983 4.15942 13.7576L4.20487 13.7121C4.37952 13.5336 4.49668 13.3068 4.54124 13.0611C4.5858 12.8153 4.55572 12.5618 4.45487 12.3333C4.35884 12.1093 4.19938 11.9182 3.99613 11.7836C3.79288 11.649 3.55471 11.5767 3.31093 11.5758H3.18214C2.7803 11.5758 2.39492 11.4161 2.11077 11.132C1.82662 10.8478 1.66699 10.4624 1.66699 10.0606C1.66699 9.65876 1.82662 9.27338 2.11077 8.98923C2.39492 8.70509 2.7803 8.54545 3.18214 8.54545H3.25033C3.50108 8.53959 3.74427 8.45842 3.94828 8.31251C4.15229 8.16659 4.30769 7.96268 4.39427 7.72727C4.49511 7.49878 4.52519 7.24531 4.48063 6.99955C4.43607 6.7538 4.31891 6.52703 4.14427 6.34848L4.09881 6.30303C3.95794 6.16231 3.84618 5.99521 3.76993 5.81127C3.69368 5.62734 3.65444 5.43018 3.65444 5.23106C3.65444 5.03195 3.69368 4.83478 3.76993 4.65085C3.84618 4.46691 3.95794 4.29981 4.09881 4.15909C4.23953 4.01822 4.40663 3.90646 4.59057 3.83021C4.7745 3.75396 4.97167 3.71472 5.17078 3.71472C5.36989 3.71472 5.56706 3.75396 5.75099 3.83021C5.93493 3.90646 6.10203 4.01822 6.24275 4.15909L6.2882 4.20455C6.46675 4.37919 6.69352 4.49635 6.93927 4.54091C7.18503 4.58547 7.4385 4.55539 7.66699 4.45455H7.7276C7.95167 4.35851 8.14276 4.19906 8.27737 3.99581C8.41197 3.79256 8.4842 3.55438 8.48517 3.31061V3.18182C8.48517 2.77998 8.64481 2.39459 8.92895 2.11044C9.2131 1.8263 9.59848 1.66667 10.0003 1.66667C10.4022 1.66667 10.7876 1.8263 11.0717 2.11044C11.3558 2.39459 11.5155 2.77998 11.5155 3.18182V3.25C11.5164 3.49378 11.5887 3.73195 11.7233 3.9352C11.8579 4.13845 12.049 4.29791 12.2731 4.39394C12.5016 4.49478 12.755 4.52487 13.0008 4.48031C13.2465 4.43575 13.4733 4.31859 13.6518 4.14394L13.6973 4.09848C13.838 3.95761 14.0051 3.84586 14.1891 3.76961C14.373 3.69336 14.5702 3.65411 14.7693 3.65411C14.9684 3.65411 15.1655 3.69336 15.3495 3.76961C15.5334 3.84586 15.7005 3.95761 15.8412 4.09848C15.9821 4.2392 16.0939 4.40631 16.1701 4.59024C16.2464 4.77418 16.2856 4.97134 16.2856 5.17045C16.2856 5.36957 16.2464 5.56673 16.1701 5.75067C16.0939 5.9346 15.9821 6.10171 15.8412 6.24242L15.7958 6.28788C15.6211 6.46642 15.504 6.69319 15.4594 6.93895C15.4149 7.1847 15.4449 7.43817 15.5458 7.66667V7.72727C15.6418 7.95134 15.8013 8.14244 16.0045 8.27704C16.2078 8.41164 16.4459 8.48388 16.6897 8.48485H16.8185C17.2204 8.48485 17.6057 8.64448 17.8899 8.92863C18.174 9.21277 18.3337 9.59816 18.3337 10C18.3337 10.4018 18.174 10.7872 17.8899 11.0714C17.6057 11.3555 17.2204 11.5152 16.8185 11.5152H16.7503C16.5065 11.5161 16.2684 11.5884 16.0651 11.723C15.8619 11.8576 15.7024 12.0487 15.6064 12.2727Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_914_477">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
);
const handleNavClick = (path: string) => {
navigate(path);
};
return (
<div className="h-full w-64 max-w-64 min-w-64 px-3 pt-4 pb-3 bg-[--Neutrals-NeutralSlate0] border-r border-[--Neutrals-NeutralSlate200] inline-flex flex-col justify-between items-center overflow-hidden">
{/* Header Section */}
<div className="self-stretch flex flex-col justify-start items-start gap-5">
{/* Company Selector Dropdown */}
<div className="relative w-60" ref={dropdownRef}>
<div
className="w-60 pl-2 pr-4 py-2 bg-[--Neutrals-NeutralSlate0] rounded-3xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] inline-flex justify-between items-center overflow-hidden cursor-pointer hover:bg-[--Neutrals-NeutralSlate50]"
onClick={() => refreshOrganizations() && setShowOrgDropdown(!showOrgDropdown)}
>
<div className="flex-1 flex justify-start items-center gap-2">
<div className="w-8 h-8 rounded-full flex justify-start items-center gap-2.5">
<div className="w-8 h-8 relative bg-[--Brand-Orange] rounded-full outline outline-[1.60px] outline-offset-[-1.60px] outline-white/10 overflow-hidden">
<div className="w-8 h-8 left-0 top-0 absolute bg-gradient-to-b from-white/0 to-white/10" />
<div data-svg-wrapper className="left-[7px] top-[7px] absolute">
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_1141_1906)">
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M4.34354 10.6855C4.67011 11.0162 4.6701 11.5524 4.34353 11.8831L4.32681 11.9C4.00024 12.2307 3.47077 12.2307 3.14421 11.9C2.81765 11.5693 2.81765 11.0331 3.14422 10.7024L3.16095 10.6855C3.48751 10.3548 4.01698 10.3548 4.34354 10.6855Z" fill="url(#paint0_linear_1141_1906)" />
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M8.27545 10.9405C8.60142 11.2718 8.60046 11.808 8.27331 12.1381L5.95697 14.4752C5.62981 14.8053 5.10035 14.8043 4.77437 14.473C4.4484 14.1417 4.44936 13.6056 4.77651 13.2755L7.09285 10.9383C7.42001 10.6082 7.94947 10.6092 8.27545 10.9405Z" fill="url(#paint1_linear_1141_1906)" />
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M11.4179 14.9651C11.6741 14.5759 12.1932 14.4708 12.5775 14.7302L12.6277 14.7641C13.012 15.0235 13.1158 15.5492 12.8596 15.9384C12.6034 16.3275 12.0842 16.4326 11.7 16.1732L11.6498 16.1393C11.2655 15.8799 11.1617 15.3542 11.4179 14.9651Z" fill="url(#paint2_linear_1141_1906)" />
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M16.9375 10.6347C17.264 10.9654 17.264 11.5016 16.9375 11.8323L15.8002 12.9839C15.4736 13.3146 14.9442 13.3146 14.6176 12.9839C14.291 12.6532 14.291 12.1171 14.6176 11.7864L15.7549 10.6347C16.0814 10.304 16.6109 10.304 16.9375 10.6347Z" fill="url(#paint3_linear_1141_1906)" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.9542 6.37693C17.2808 6.70762 17.2808 7.24378 16.9542 7.57447L8.5502 16.0847C8.22364 16.4154 7.69417 16.4154 7.3676 16.0847C7.04104 15.754 7.04104 15.2179 7.3676 14.8872L15.7717 6.37693C16.0982 6.04623 16.6277 6.04623 16.9542 6.37693Z" fill="url(#paint4_linear_1141_1906)" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.3649 3.75974C15.6915 4.09043 15.6915 4.62659 15.3649 4.95728L10.5315 9.85174C10.205 10.1824 9.67549 10.1824 9.34893 9.85174C9.02236 9.52104 9.02236 8.98489 9.34893 8.65419L14.1823 3.75974C14.5089 3.42905 15.0383 3.42905 15.3649 3.75974Z" fill="url(#paint5_linear_1141_1906)" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.8146 2.09918C13.1414 2.42965 13.1417 2.96581 12.8154 3.29672L6.60224 9.59685C6.27589 9.92777 5.74642 9.92813 5.41964 9.59766C5.09285 9.26719 5.0925 8.73103 5.41884 8.40011L11.632 2.09998C11.9583 1.76907 12.4878 1.76871 12.8146 2.09918Z" fill="url(#paint6_linear_1141_1906)" />
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M6.66127 4.11624C6.98727 4.4475 6.98636 4.98366 6.65923 5.31378L4.22582 7.76948C3.89869 8.0996 3.36923 8.09868 3.04322 7.76741C2.71722 7.43615 2.71813 6.9 3.04526 6.56987L5.47867 4.11418C5.8058 3.78405 6.33526 3.78498 6.66127 4.11624Z" fill="url(#paint7_linear_1141_1906)" />
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M8.15116 1.66602C8.613 1.66602 8.98739 2.04514 8.98739 2.51281V2.59749C8.98739 3.06516 8.613 3.44428 8.15116 3.44428C7.68933 3.44428 7.31494 3.06516 7.31494 2.59749V2.51281C7.31494 2.04514 7.68933 1.66602 8.15116 1.66602Z" fill="url(#paint8_linear_1141_1906)" />
</g>
<defs>
<filter id="filter0_d_1141_1906" x="0.399316" y="-0.400781" width="19.2008" height="22.3996" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feMorphology radius="1.2" operator="erode" in="SourceAlpha" result="effect1_dropShadow_1141_1906" />
<feOffset dy="1.8" />
<feGaussianBlur stdDeviation="1.8" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 0.141176 0 0 0 0 0.141176 0 0 0 0 0.141176 0 0 0 0.1 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1141_1906" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1141_1906" result="shape" />
</filter>
<linearGradient id="paint0_linear_1141_1906" x1="3.74388" y1="10.4375" x2="3.74388" y2="12.148" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0.8" />
<stop offset="1" stop-color="white" stop-opacity="0.5" />
</linearGradient>
<linearGradient id="paint1_linear_1141_1906" x1="6.52491" y1="10.6914" x2="6.52491" y2="14.7221" 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_1141_1906" x1="12.1387" y1="14.5879" x2="12.1387" y2="16.3155" 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_1141_1906" x1="15.7775" y1="10.3867" x2="15.7775" y2="13.2319" 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_1141_1906" x1="12.1609" y1="6.12891" x2="12.1609" y2="16.3327" 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_1141_1906" x1="12.3569" y1="3.51172" x2="12.3569" y2="10.0998" 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_1141_1906" x1="9.11711" y1="1.85156" x2="9.11711" y2="9.84527" 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_1141_1906" x1="4.85224" y1="3.86719" x2="4.85224" y2="8.01647" 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_1141_1906" x1="8.15117" y1="1.66602" x2="8.15117" y2="3.44428" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0.8" />
<stop offset="1" stop-color="white" stop-opacity="0.5" />
</linearGradient>
</defs>
</svg>
</div>
</div>
</div>
<div className="flex-1 inline-flex flex-col justify-start items-start gap-0.5">
<div className="self-stretch justify-start text-[--Neutrals-NeutralSlate950] text-base font-medium font-['Inter'] leading-normal">{org?.name || 'Select Organization'}</div>
</div>
</div>
<div className={`transition-transform duration-200 ${showOrgDropdown ? 'rotate-180' : ''}`}>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.83301 7.50001L9.99967 11.6667L14.1663 7.50001" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
{/* Dropdown Menu */}
{showOrgDropdown && (
<div className="absolute top-full left-0 right-0 mt-2 bg-[--Neutrals-NeutralSlate0] rounded-2xl shadow-[0px_10px_30px_0px_rgba(14,18,27,0.15)] outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] z-50 max-h-80 overflow-y-auto">
<div className="p-2">
{/* Current Organizations */}
{organizations.map((organization) => (
<div
key={organization.orgId}
className={`w-full px-3 py-2.5 rounded-xl flex items-center gap-3 cursor-pointer hover:bg-[--Neutrals-NeutralSlate50] ${org?.orgId === organization.orgId ? 'bg-[--Neutrals-NeutralSlate100]' : ''
}`}
onClick={() => handleOrgSwitch(organization.orgId)}
>
<div className="w-6 h-6 relative bg-[--Brand-Orange] rounded-full flex items-center justify-center text-white text-xs font-medium">
{organization.name.charAt(0).toUpperCase()}
</div>
<div className="flex-1">
<div className="text-[--Neutrals-NeutralSlate950] text-sm font-medium">{organization.name}</div>
{organization.name && (
<div className="text-[--Neutrals-NeutralSlate500] text-xs">{organization.name}</div>
)}
</div>
{org?.orgId === organization.orgId && (
<div className="w-4 h-4 text-[--Brand-Orange]">
<svg viewBox="0 0 16 16" fill="currentColor">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z" />
</svg>
</div>
)}
</div>
))}
{/* Divider */}
{organizations.length > 0 && (
<div className="my-2 border-t border-[--Neutrals-NeutralSlate200]"></div>
)}
{/* Create New Organization */}
<div
className="w-full px-3 py-2.5 rounded-xl flex items-center gap-3 cursor-pointer hover:bg-[--Neutrals-NeutralSlate50] text-[--Neutrals-NeutralSlate600]"
onClick={() => {
setShowOrgDropdown(false);
setShowCreateOrgModal(true);
}}
>
<div className="w-6 h-6 border-2 border-dashed border-[--Neutrals-NeutralSlate300] rounded-full flex items-center justify-center">
<PlusIcon className="w-3 h-3" />
</div>
<div className="flex-1">
<div className="text-sm font-medium">Create New Organization</div>
</div>
</div>
</div>
</div>
)}
</div>
{/* Navigation Items */}
<div className="self-stretch flex flex-col justify-start items-start gap-5">
<div className="self-stretch flex flex-col justify-start items-start gap-1.5">
{navItems.map((item, index) => (
<div
key={index}
onClick={() => handleNavClick(item.path)}
className={`w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2 cursor-pointer ${item.active
? 'bg-[--Neutrals-NeutralSlate100]'
: 'hover:bg-[--Neutrals-NeutralSlate50]'
}`}
>
<div className="relative">
{React.cloneElement(item.icon, {
stroke: item.active ? "var(--Brand-Orange)" : "var(--Neutrals-NeutralSlate400, #A4A7AE)"
})}
</div>
<div className={`justify-start text-sm font-medium font-['Inter'] leading-tight ${item.active
? 'text-[--Neutrals-NeutralSlate950]'
: 'text-[--Neutrals-NeutralSlate500]'
}`}>
{item.label}
</div>
</div>
))}
</div>
</div>
</div>
{/* Create Organization Modal */}
{showCreateOrgModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-[--Neutrals-NeutralSlate0] p-6 rounded-2xl max-w-md w-full mx-4 shadow-[0px_20px_40px_0px_rgba(14,18,27,0.25)]">
<h3 className="text-lg font-semibold text-[--Neutrals-NeutralSlate950] mb-4">Create New Organization</h3>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-[--Neutrals-NeutralSlate700] mb-2">Organization Name</label>
<input
type="text"
value={createOrgForm.name}
onChange={(e) => setCreateOrgForm(prev => ({ ...prev, name: e.target.value }))}
className="w-full px-3 py-2.5 border border-[--Neutrals-NeutralSlate200] rounded-xl bg-[--Neutrals-NeutralSlate0] text-[--Neutrals-NeutralSlate950] focus:outline-none focus:ring-2 focus:ring-[--Brand-Orange] focus:border-transparent"
placeholder="Enter organization name"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--Neutrals-NeutralSlate700] mb-2">Description (Optional)</label>
<textarea
value={createOrgForm.description}
onChange={(e) => setCreateOrgForm(prev => ({ ...prev, description: e.target.value }))}
className="w-full px-3 py-2.5 border border-[--Neutrals-NeutralSlate200] rounded-xl bg-[--Neutrals-NeutralSlate0] text-[--Neutrals-NeutralSlate950] focus:outline-none focus:ring-2 focus:ring-[--Brand-Orange] focus:border-transparent resize-none"
rows={3}
placeholder="Brief description of your organization"
/>
</div>
</div>
<div className="flex space-x-3 mt-6">
<Button
variant="secondary"
className="flex-1"
onClick={() => {
setShowCreateOrgModal(false);
setCreateOrgForm({ name: '', description: '' });
}}
>
Cancel
</Button>
<Button
className="flex-1"
onClick={handleCreateOrg}
disabled={!createOrgForm.name.trim()}
>
Create Organization
</Button>
</div>
</div>
</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>
)}
{/* Bottom Section */}
<div className="self-stretch flex flex-col justify-start items-start gap-3">
{/* Settings */}
<div
onClick={() => handleNavClick("/settings")}
className={`w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2 cursor-pointer ${location.pathname === "/settings"
? 'bg-[--Neutrals-NeutralSlate100]'
: 'hover:bg-[--Neutrals-NeutralSlate50]'
}`}
>
<div className="relative">
{React.cloneElement(settingsIcon, {
stroke: location.pathname === "/settings" ? "var(--Brand-Orange)" : "var(--Neutrals-NeutralSlate400, #A4A7AE)"
})}
</div>
<div className={`flex-1 justify-start text-sm font-medium font-['Inter'] leading-tight ${location.pathname === "/settings"
? 'text-[--Neutrals-NeutralSlate950]'
: 'text-[--Neutrals-NeutralSlate500]'
}`}>
Settings
</div>
</div>
{/* Build Report Card */}
<div className="self-stretch bg-[--Neutrals-NeutralSlate0] rounded-[20px] shadow-[0px_1px_4px_0px_rgba(14,18,27,0.04)] outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start overflow-hidden">
<div className="self-stretch h-24 relative">
<div className="w-60 p-3 origin-top-left rotate-[-28.34deg] bg-[--Neutrals-NeutralSlate0] rounded-xl shadow-[0px_10px_20px_4px_rgba(14,18,27,0.08)] outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate100]
inline-flex flex-col justify-start items-start gap-3 overflow-hidden">
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch h-2 bg-[--Neutrals-NeutralSlate100] rounded-sm" />
<div className="w-20 h-2 bg-[--Neutrals-NeutralSlate100] rounded-sm" />
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1.5">
<div className="w-20 h-2 bg-[--Neutrals-NeutralSlate100] rounded-sm" />
<div className="self-stretch h-5 bg-[--Neutrals-NeutralSlate100] rounded-sm" />
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1.5">
<div className="w-20 h-2 bg-[--Neutrals-NeutralSlate100] rounded-sm" />
<div className="self-stretch h-5 bg-[--Neutrals-NeutralSlate100] rounded-sm" />
</div>
</div>
</div>
<div className="self-stretch p-3 flex flex-col justify-start items-start gap-1">
<div className="self-stretch justify-start text-[--Neutrals-NeutralSlate800] text-sm font-semibold font-['Inter'] leading-tight">Build {org.name}'s Report</div>
<div className="self-stretch justify-start text-[--Neutrals-NeutralSlate500] text-xs font-normal font-['Inter'] leading-none">Share this form with your team members to capture valuable info about your company to train Auditly.</div>
</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 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 >
);
}