fix most of the listed bugs
This commit is contained in:
113
src/components/OwnerMigrationUtility.tsx
Normal file
113
src/components/OwnerMigrationUtility.tsx
Normal 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;
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user