fix most of the listed bugs

This commit is contained in:
Ra
2025-08-26 11:23:27 -07:00
parent 772d1d4c10
commit ad15aaa35e
22 changed files with 3493 additions and 2375 deletions

View File

@@ -0,0 +1,113 @@
import React, { useState } from 'react';
import { secureApi } from '../services/secureApi';
/**
* Migration utility component to remove company owners from employees collection
* This fixes the architectural issue where owners were incorrectly stored as employees
*/
const OwnerMigrationUtility: React.FC = () => {
const [isRunning, setIsRunning] = useState(false);
const [result, setResult] = useState<any>(null);
const [error, setError] = useState<string | null>(null);
const runMigration = async () => {
setIsRunning(true);
setError(null);
setResult(null);
try {
const migrationResult = await secureApi.migrateOwnersFromEmployees();
setResult(migrationResult);
console.log('Migration completed:', migrationResult);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Migration failed';
setError(errorMessage);
console.error('Migration error:', err);
} finally {
setIsRunning(false);
}
};
return (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-6 max-w-2xl mx-auto">
<div className="flex items-start">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-yellow-800">
Data Migration Required
</h3>
<div className="mt-2 text-sm text-yellow-700">
<p>
Your organization data needs to be migrated to fix an architectural issue.
Previously, company owners were incorrectly stored in the employees collection.
This migration will move your owner data to the correct location.
</p>
</div>
<div className="mt-4">
<div className="flex">
<button
type="button"
onClick={runMigration}
disabled={isRunning}
className="bg-yellow-100 px-2 py-1.5 rounded-md text-sm font-medium text-yellow-800 hover:bg-yellow-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-yellow-50 focus:ring-yellow-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
{isRunning ? 'Running Migration...' : 'Run Migration'}
</button>
</div>
</div>
</div>
</div>
{result && (
<div className="mt-4 p-4 bg-green-50 border border-green-200 rounded-md">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-green-800">
Migration Completed Successfully
</h3>
<div className="mt-2 text-sm text-green-700">
<p>Migrated {result.migratedCount} owner record(s) from employees collection.</p>
{result.ownerInfo && (
<p className="mt-1">
Owner: {result.ownerInfo.name} ({result.ownerInfo.email})
</p>
)}
</div>
</div>
</div>
</div>
)}
{error && (
<div className="mt-4 p-4 bg-red-50 border border-red-200 rounded-md">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">
Migration Failed
</h3>
<div className="mt-2 text-sm text-red-700">
<p>{error}</p>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default OwnerMigrationUtility;

View File

@@ -309,13 +309,13 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
}
export const Button: React.FC<ButtonProps> = ({ children, variant = 'primary', size = 'md', className, ...props }) => {
const baseClasses = 'inline-flex items-center justify-center font-semibold rounded-lg focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed';
const baseClasses = 'inline-flex items-center justify-center font-semibold rounded-lg focus:outline-none transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed';
const variantClasses = {
primary: 'bg-[--accent] text-[--accent-text] hover:bg-[--accent-hover] focus:ring-[--accent]',
secondary: 'bg-[--button-secondary-bg] text-[--text-primary] hover:bg-[--button-secondary-hover] focus:ring-[--accent] border border-[--border-color]',
primary: 'bg-[--Brand-Orange] text-[--accent-text] hover:bg-blue-400 focus:ring-[--accent-hover]',
secondary: 'bg-[--button-secondary-bg] text-[--text-primary] hover:bg-[--button-secondary-hover] focus:ring-[--accent]',
danger: 'bg-[--status-red] text-white hover:bg-red-700 focus:ring-red-500',
ghost: 'bg-transparent text-[--text-primary] hover:bg-[--background-tertiary]'
ghost: 'bg-[--Neutrals-NeutralSlate100] text-[--text-primary] hover:bg-[--background-tertiary]'
};
const sizeClasses = {

View File

@@ -62,7 +62,7 @@ export const SectionProgressBar: React.FC<{ currentSection: number; totalSection
sectionName
}) => {
return (
<div className="w-[464px] max-w-[464px] min-w-[464px] absolute top-[24px] left-1/2 transform -translate-x-1/2 flex flex-col justify-start items-center gap-4">
<div className="min-w-[464px] col-span-2 col-start-6 inline-flex flex-col justify-self-center justify-center items-center gap-4 self-start">
<div className="p-4 bg-[--Neutrals-NeutralSlate100] rounded-[50px] inline-flex justify-center items-center gap-2 overflow-hidden">
{Array.from({ length: 7 }, (_, index) => {
const isActive = index === currentSection - 1;
@@ -70,11 +70,11 @@ export const SectionProgressBar: React.FC<{ currentSection: number; totalSection
<div key={index}>
{isActive ? (
<svg width="24" height="4" viewBox="0 0 24 4" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="4" rx="2" fill="var(--Brand-Orange, #3399FF)" />
<rect width="24" height="4" rx="2" fill="var(--Brand-Orange)" />
</svg>
) : (
<svg width="4" height="4" viewBox="0 0 4 4" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="4" height="4" rx="2" fill="var(--Neutrals-NeutralSlate300, #D5D7DA)" />
<rect width="4" height="4" rx="2" fill="var(--Neutrals-NeutralSlate300)" />
</svg>
)}
</div>
@@ -139,7 +139,7 @@ export const SectionIntro: React.FC<{
description: string;
onStart: () => void;
imageUrl?: string;
}> = ({ sectionNumber, title, description, onStart, imageUrl = "https://placehold.co/560x682" }) => {
}> = ({ sectionNumber, title, description, onStart, imageUrl = "/image/onboarding-robot.png" }) => {
return (
<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">
@@ -167,7 +167,7 @@ export const SectionIntro: React.FC<{
</div>
<button
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-blue-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="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Start</div>
@@ -175,7 +175,7 @@ export const SectionIntro: React.FC<{
</button>
</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-max px-20 py-16 flex justify-center items-center gap-2.5 flex-shrink">
<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={title} />
</div>
@@ -286,8 +286,8 @@ export const TextAreaQuestion: React.FC<{
placeholder?: string;
}> = ({ question, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName, placeholder = "Type your answer...." }) => {
return (
<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 h-full py-6 relative bg-[--Neutrals-NeutralSlate0] grid grid-cols-12 grid-rows-5 justify-center items-center gap-3">
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col row-start-3 col-span-12 self-center justify-self-center justify-center gap-12">
<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">
{question}
@@ -341,7 +341,7 @@ export const TextAreaQuestion: React.FC<{
{onSkip && (
<button
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-[--Neutrals-NeutralSlate200 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>
</button>
@@ -375,13 +375,13 @@ export const RatingScaleQuestion: React.FC<{
scale?: number;
}> = ({ question, leftLabel, rightLabel, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName, scale = 10 }) => {
return (
<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 h-full py-6 relative bg-[--Neutrals-NeutralSlate0] grid grid-cols-12 grid-rows-5 justify-center items-center gap-3">
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col row-start-3 col-span-12 self-center justify-self-center justify-center gap-12">
<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">
{question}
</div>
<div className="inline-flex justify-center items-center gap-3">
<div className="inline-flex justify-center w-max items-center gap-3">
<div className="justify-center text-[--Neutrals-NeutralSlate950] text-sm font-medium font-['Inter'] leading-tight">
{leftLabel}
</div>
@@ -392,10 +392,10 @@ export const RatingScaleQuestion: React.FC<{
<button
key={ratingValue}
onClick={() => onChange(ratingValue)}
className={`w-12 h-12 relative rounded-[576.35px] overflow-hidden transition-colors ${isSelected ? 'bg-[--Neutrals-NeutralSlate800]' : 'bg-[--Neutrals-NeutralSlate800] hover:bg-neutral-200'
className={`w-12 h-12 relative rounded-[576.35px] overflow-hidden transition-colors ${isSelected ? 'bg-[--Neutrals-NeutralSlate50]' : 'bg-[--Neutrals-NeutralSlate800] hover:bg-[--Neutrals-NeutralSlate50]'
}`}
>
<div className={`absolute inset-0 flex items-center justify-center text-xl font-medium font-['Inter'] leading-7 ${isSelected ? 'text-[--Neutrals-NeutralSlate0]' : 'text-[--Neutrals-NeutralSlate0]'
<div className={`absolute inset-0 flex items-center justify-center text-xl font-medium font-['Inter'] leading-7 ${isSelected ? 'text-[--Neutrals-NeutralSlate950] bg-[--Neutrals-NeutralSlate50]' : 'text-[--Neutrals-NeutralSlate0] hover:text-[--Neutrals-NeutralSlate800]'
}`}>
{ratingValue}
</div>
@@ -421,7 +421,7 @@ export const RatingScaleQuestion: React.FC<{
<button
onClick={onNext}
disabled={!value}
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-blue-500 transition-colors"
>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
@@ -474,8 +474,8 @@ export const YesNoChoice: React.FC<{
sectionName?: string;
}> = ({ question, value, onChange, onBack, onNext, onSkip, currentStep, totalSteps, sectionName }) => {
return (
<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 h-full py-6 relative bg-[--Neutrals-NeutralSlate0] grid grid-cols-12 grid-rows-5 justify-center items-center gap-3">
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col row-start-3 col-span-12 self-center justify-self-center justify-center gap-12">
<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">
{question}
@@ -483,20 +483,20 @@ export const YesNoChoice: React.FC<{
<div className="self-stretch inline-flex justify-center items-center gap-3">
<button
onClick={() => onChange('No')}
className={`w-20 h-20 relative rounded-[999px] overflow-hidden transition-colors ${value === 'No' ? 'bg-[--Neutrals-NeutralSlate800]' : 'bg-[--Neutrals-NeutralSlate800] hover:bg-neutral-200'
className={`w-20 h-20 relative rounded-[999px] overflow-hidden transition-colors ${value === 'No' ? 'bg-[--Neutrals-NeutralSlate50]' : 'bg-[--Neutrals-NeutralSlate800] hover:bg-[--Neutrals-NeutralSlate50]'
}`}
>
<div className={`absolute inset-0 flex items-center justify-center text-base font-normal font-['Inter'] leading-normal ${value === 'No' ? 'text-[--Neutrals-NeutralSlate0]' : 'text-[--Neutrals-NeutralSlate0]'
<div className={`absolute inset-0 flex items-center justify-center text-base font-normal font-['Inter'] leading-normal ${value === 'No' ? 'text-[--Neutrals-NeutralSlate950] bg-[--Neutrals-NeutralSlate50]' : 'text-[--Neutrals-NeutralSlate50] hover:bg-[--Neutrals-NeutralSlate50] hover:text-[--Neutrals-NeutralSlate950]'
}`}>
No
</div>
</button>
<button
onClick={() => onChange('Yes')}
className={`w-20 h-20 relative rounded-[999px] overflow-hidden transition-colors ${value === 'Yes' ? 'bg-[--Neutrals-NeutralSlate800]' : 'bg-[--Neutrals-NeutralSlate800] hover:bg-neutral-200'
className={`w-20 h-20 relative rounded-[999px] overflow-hidden transition-colors ${value === 'Yes' ? 'bg-[--Neutrals-NeutralSlate50]' : 'bg-[--Neutrals-NeutralSlate800] hover:bg-[--Neutrals-NeutralSlate50]'
}`}
>
<div className={`absolute inset-0 flex items-center justify-center text-base font-normal font-['Inter'] leading-normal ${value === 'Yes' ? 'text-[--Neutrals-NeutralSlate0]' : 'text-[--Neutrals-NeutralSlate0]'
<div className={`absolute inset-0 flex items-center justify-center text-base font-normal font-['Inter'] leading-normal ${value === 'Yes' ? 'text-[--Neutrals-NeutralSlate950] bg-[--Neutrals-NeutralSlate50]' : 'text-[--Neutrals-NeutralSlate50] hover:bg-[--Neutrals-NeutralSlate50] hover:text-[--Neutrals-NeutralSlate950]'
}`}>
Yes
</div>
@@ -517,7 +517,7 @@ export const YesNoChoice: React.FC<{
<button
onClick={onNext}
disabled={!value}
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-blue-500 transition-colors"
>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">Next</div>
@@ -560,7 +560,7 @@ export const YesNoChoice: React.FC<{
// Thank You Page Component
export const ThankYouPage: React.FC = () => {
return (
<div className="w-full self-stretch 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 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">
@@ -581,9 +581,9 @@ export const ThankYouPage: React.FC = () => {
</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 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="https://placehold.co/560x682" alt="Thank you" />
<div className="flex-1 h-[810px] px-20 py-16 flex justify-center items-center gap-2.5">
<div className="flex-1 self-stretch origin-top-left rotate-180 rounded-3xl inline-flex flex-col justify-center items-center gap-2.5">
<img className="self-stretch flex-1" src="/image/onboarding-robot.png" alt="Thank you" />
</div>
</div>
</div>

View File

@@ -1,8 +1,9 @@
import React, { useState, ReactNode } from 'react';
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;
@@ -11,13 +12,48 @@ interface SidebarProps {
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 {
@@ -125,67 +161,151 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
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 */}
<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">
<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="left-0 top-0 absolute">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="32" height="32" fill="url(#paint0_linear_731_19280)" />
<defs>
<linearGradient id="paint0_linear_731_19280" x1="16" y1="3.97364e-07" x2="17.3333" y2="32" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0" />
<stop offset="1" stopColor="white" stopOpacity="0.12" />
</linearGradient>
</defs>
</svg>
{/* 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 className="left-[8.80px] top-[7.20px] 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_731_19281)">
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M4.34367 10.6873C4.67023 11.018 4.67022 11.5541 4.34366 11.8848L4.32693 11.9018C4.00036 12.2325 3.47089 12.2325 3.14433 11.9018C2.81777 11.5711 2.81778 11.0349 3.14434 10.7042L3.16107 10.6873C3.48764 10.3566 4.0171 10.3566 4.34367 10.6873Z" fill="url(#paint0_linear_731_19281)" />
<path opacity="0.7" fillRule="evenodd" clipRule="evenodd" d="M8.2752 10.9423C8.60118 11.2736 8.60022 11.8097 8.27306 12.1398L5.95673 14.477C5.62957 14.8071 5.1001 14.8061 4.77413 14.4748C4.44815 14.1435 4.44911 13.6074 4.77627 13.2773L7.09261 10.9401C7.41976 10.61 7.94923 10.611 8.2752 10.9423Z" fill="url(#paint1_linear_731_19281)" />
</g>
<defs>
<filter id="filter0_d_731_19281" x="0.398828" y="-0.399988" width="19.2014" height="22.4" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
<feFlood floodOpacity="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_731_19281" />
<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_731_19281" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_731_19281" result="shape" />
</filter>
<linearGradient id="paint0_linear_731_19281" x1="3.744" y1="10.4393" x2="3.744" y2="12.1498" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
<linearGradient id="paint1_linear_731_19281" x1="6.52467" y1="10.6932" x2="6.52467" y2="14.7239" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
</defs>
</svg>
</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 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">{companyName}</div>
</div>
</div>
<div>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.83301 12.5L9.99967 16.6667L14.1663 12.5M5.83301 7.50001L9.99967 3.33334L14.1663 7.50001" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
)}
</div>
{/* Navigation Items */}
@@ -202,7 +322,7 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
>
<div className="relative">
{React.cloneElement(item.icon, {
stroke: item.active ? "var(--Brand-Orange, #5E48FC)" : "var(--Neutrals-NeutralSlate400, #A4A7AE)"
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
@@ -217,6 +337,57 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
</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">
@@ -332,12 +503,22 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
{/* 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 hover:bg-[--Neutrals-NeutralSlate50]"
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">
{settingsIcon}
{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 className="flex-1 justify-start text-[--Neutrals-NeutralSlate500] text-sm font-medium font-['Inter'] leading-tight">Settings</div>
</div>
{/* Build Report Card */}
@@ -360,7 +541,7 @@ export default function Sidebar({ companyName = "Zitlac Media", collapsed = fals
</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 [Company]'s Report</div>
<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">