feat: major UI overhaul with new components and enhanced UX

- Add comprehensive Company Wiki feature with complete state management
  - CompanyWikiManager, empty states, invite modals
- Implement new Chat system with enhanced layout and components
  - ChatLayout, ChatSidebar, MessageThread, FileUploadInput
- Create modern Login and OTP verification flows
  - LoginNew page, OTPVerification component
- Add new Employee Forms system with enhanced controller
- Introduce Figma-based design components and multiple choice inputs
- Add new font assets (NeueMontreal) and robot images for onboarding
- Enhance existing components with improved styling and functionality
- Update build configuration and dependencies
- Remove deprecated ModernLogin component
This commit is contained in:
Ra
2025-08-20 03:30:04 -07:00
parent 1a9e92d7bd
commit cf565df13e
47 changed files with 6654 additions and 2007 deletions

View File

@@ -1,165 +1,12 @@
import React, { useState, useMemo } from 'react';
import { Card, Button } from '../components/UiKit';
import { useOrg } from '../contexts/OrgContext';
import { CHAT_STARTERS } from '../constants';
import { apiPost } from '../services/api';
import React from 'react';
import ChatLayout from '../components/chat/ChatLayout';
import ChatEmptyState from '../components/chat/ChatEmptyState';
const Chat: React.FC = () => {
const { employees, reports, generateEmployeeReport, orgId } = useOrg();
const [messages, setMessages] = useState<Array<{ id: string, role: 'user' | 'assistant', text: string }>>([]);
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [selectedEmployeeId, setSelectedEmployeeId] = useState<string>('');
const selectedReport = selectedEmployeeId ? reports[selectedEmployeeId] : undefined;
const dynamicStarters = useMemo(() => {
if (!selectedReport) return CHAT_STARTERS.slice(0, 4);
const strengths = selectedReport.insights.strengths?.slice(0, 2) || [];
const weaknesses = selectedReport.insights.weaknesses?.slice(0, 1) || [];
const risk = selectedReport.retentionRisk;
const starters: string[] = [];
if (strengths[0]) starters.push(`How can we further leverage ${strengths[0]} for cross-team impact?`);
if (weaknesses[0]) starters.push(`What is an actionable plan to address ${weaknesses[0]} this quarter?`);
if (risk) starters.push(`What factors contribute to ${selectedReport.employeeId}'s ${risk} retention risk?`);
starters.push(`Is ${selectedReport.employeeId} a candidate for expanded scope or leadership?`);
while (starters.length < 4) starters.push(CHAT_STARTERS[starters.length] || 'Provide an organizational insight.');
return starters.slice(0, 4);
}, [selectedReport]);
const handleSend = async (message?: string) => {
const textToSend = message || input;
if (!textToSend.trim()) return;
const userMessage = { id: Date.now().toString(), role: 'user' as const, text: textToSend };
setMessages(prev => [...prev, userMessage]);
setInput('');
setIsLoading(true);
try {
// Build context for the AI
const context = {
selectedEmployee: selectedEmployeeId ? employees.find(e => e.id === selectedEmployeeId) : null,
selectedReport: selectedReport,
totalEmployees: employees.length,
organizationScope: !selectedEmployeeId
};
const res = await apiPost('/chat', {
message: textToSend,
employeeId: selectedEmployeeId,
context
}, orgId);
if (!res.ok) {
const errorData = await res.json();
throw new Error(errorData.error || 'Failed to get AI response');
}
const data = await res.json();
const aiResponse = {
id: (Date.now() + 1).toString(),
role: 'assistant' as const,
text: data.response || 'I apologize, but I couldn\'t generate a response at this time.'
};
setMessages(prev => [...prev, aiResponse]);
} catch (error) {
console.error('Chat error:', error);
const errorResponse = {
id: (Date.now() + 1).toString(),
role: 'assistant' as const,
text: `I apologize, but I encountered an error: ${error.message}. Please try again.`
};
setMessages(prev => [...prev, errorResponse]);
} finally {
setIsLoading(false);
}
};
return (
<div className="p-6 max-w-4xl mx-auto h-full flex flex-col">
<div className="mb-6">
<h1 className="text-3xl font-bold text-[--text-primary]">Chat with AI</h1>
<p className="text-[--text-secondary] mt-1">Ask questions about your employees and organization</p>
</div>
<div className="mb-4 flex flex-col md:flex-row md:items-center gap-3">
<div className="flex items-center gap-2">
<label className="text-sm text-[--text-secondary]">Focus Employee:</label>
<select
className="px-2 py-1 text-sm bg-[--background-secondary] border border-[--border-color] rounded"
value={selectedEmployeeId}
onChange={e => setSelectedEmployeeId(e.target.value)}
>
<option value="">(Organization)</option>
{employees.map(emp => <option key={emp.id} value={emp.id}>{emp.name}</option>)}
</select>
{selectedEmployeeId && !selectedReport && (
<Button size="sm" variant="secondary" onClick={() => generateEmployeeReport(employees.find(e => e.id === selectedEmployeeId)!)}>
Generate Report
</Button>
)}
</div>
</div>
{messages.length === 0 && (
<Card className="mb-6">
<h3 className="text-lg font-semibold text-[--text-primary] mb-4">Get started with these questions:</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{dynamicStarters.map((starter, idx) => (
<Button
key={idx}
variant="secondary"
size="sm"
className="text-left justify-start"
onClick={() => handleSend(starter)}
>
{starter}
</Button>
))}
</div>
</Card>
)}
<div className="flex-1 overflow-y-auto mb-4 space-y-4">
{messages.map(message => (
<div key={message.id} className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div className={`max-w-[70%] p-4 rounded-lg ${message.role === 'user'
? 'bg-blue-500 text-white'
: 'bg-[--background-secondary] text-[--text-primary]'
}`}>
{message.text}
</div>
</div>
))}
{isLoading && (
<div className="flex justify-start">
<div className="bg-[--background-secondary] text-[--text-primary] p-4 rounded-lg">
<div className="flex space-x-1">
<div className="w-2 h-2 bg-gray-500 rounded-full animate-bounce"></div>
<div className="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div>
<div className="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div>
</div>
</div>
</div>
)}
</div>
<Card padding="sm">
<div className="flex space-x-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSend()}
placeholder="Ask about employees, reports, or company insights..."
className="flex-1 px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<Button onClick={() => handleSend()} disabled={isLoading || !input.trim()}>
Send
</Button>
</div>
</Card>
</div>
<ChatLayout>
<ChatEmptyState />
</ChatLayout>
);
};

390
pages/ChatNew.tsx Normal file
View File

@@ -0,0 +1,390 @@
import React, { useState, useRef, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import { useOrg } from '../contexts/OrgContext';
import Sidebar from '../components/figma/Sidebar';
interface Message {
id: string;
role: 'user' | 'assistant';
content: string;
timestamp: Date;
}
interface ChatState {
messages: Message[];
isLoading: boolean;
showEmployeeMenu: boolean;
mentionQuery: string;
selectedEmployees: string[];
hasUploadedFiles: boolean;
uploadedFiles: Array<{
name: string;
type: string;
size: number;
}>;
}
const ChatNew: React.FC = () => {
const { user } = useAuth();
const { employees, orgId } = useOrg();
const navigate = useNavigate();
const inputRef = useRef<HTMLTextAreaElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const [state, setState] = useState<ChatState>({
messages: [],
isLoading: false,
showEmployeeMenu: false,
mentionQuery: '',
selectedEmployees: [],
hasUploadedFiles: false,
uploadedFiles: []
});
const [currentInput, setCurrentInput] = useState('');
const [selectedCategory, setSelectedCategory] = useState('Accountability');
useEffect(() => {
if (!user) {
navigate('/login');
}
}, [user, navigate]);
const questionStarters = [
"How can the company serve them better?",
"How can the company serve them better?",
"How can the company serve them better?",
"How can the company serve them better?"
];
const categories = ['Accountability', 'Employee Growth', 'Customer Focus', 'Teamwork'];
const handleSendMessage = async () => {
if (!currentInput.trim() && state.uploadedFiles.length === 0) return;
const newMessage: Message = {
id: Date.now().toString(),
role: 'user',
content: currentInput.trim(),
timestamp: new Date()
};
setState(prev => ({
...prev,
messages: [...prev.messages, newMessage],
isLoading: true
}));
setCurrentInput('');
// Simulate AI response
setTimeout(() => {
const aiResponse: Message = {
id: (Date.now() + 1).toString(),
role: 'assistant',
content: "Based on the information provided and the company data, here are my insights and recommendations...",
timestamp: new Date()
};
setState(prev => ({
...prev,
messages: [...prev.messages, aiResponse],
isLoading: false
}));
}, 2000);
};
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const value = e.target.value;
setCurrentInput(value);
// Check for @ mentions
const atIndex = value.lastIndexOf('@');
if (atIndex !== -1 && atIndex === value.length - 1) {
setState(prev => ({
...prev,
showEmployeeMenu: true,
mentionQuery: ''
}));
} else if (atIndex !== -1 && value.length > atIndex + 1) {
const query = value.substring(atIndex + 1);
setState(prev => ({
...prev,
showEmployeeMenu: true,
mentionQuery: query
}));
} else {
setState(prev => ({
...prev,
showEmployeeMenu: false,
mentionQuery: ''
}));
}
};
const handleEmployeeSelect = (employeeName: string) => {
const atIndex = currentInput.lastIndexOf('@');
if (atIndex !== -1) {
const newInput = currentInput.substring(0, atIndex) + '@' + employeeName + ' ';
setCurrentInput(newInput);
}
setState(prev => ({
...prev,
showEmployeeMenu: false,
mentionQuery: ''
}));
};
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(e.target.files || []);
if (files.length > 0) {
const uploadedFiles = files.map(file => ({
name: file.name,
type: file.type,
size: file.size
}));
setState(prev => ({
...prev,
hasUploadedFiles: true,
uploadedFiles: [...prev.uploadedFiles, ...uploadedFiles]
}));
}
};
const removeFile = (index: number) => {
setState(prev => ({
...prev,
uploadedFiles: prev.uploadedFiles.filter((_, i) => i !== index),
hasUploadedFiles: prev.uploadedFiles.length > 1
}));
};
const handleQuestionClick = (question: string) => {
setCurrentInput(question);
};
const renderEmployeeMenu = () => {
if (!state.showEmployeeMenu) return null;
const filteredEmployees = employees.filter(emp =>
emp.name.toLowerCase().includes(state.mentionQuery.toLowerCase())
);
return (
<div className="absolute bottom-full left-[285px] mb-2 w-48 p-2 bg-Text-White-00 rounded-2xl shadow-[0px_1px_4px_4px_rgba(14,18,27,0.08)] flex flex-col justify-start items-start gap-1 z-10">
{filteredEmployees.slice(0, 3).map((employee, index) => (
<div
key={employee.id}
onClick={() => handleEmployeeSelect(employee.name)}
className={`self-stretch px-3 py-2 rounded-xl flex flex-col justify-start items-start gap-2.5 overflow-hidden cursor-pointer hover:bg-Text-Gray-100 ${index === 2 ? 'bg-Text-Gray-100' : ''
}`}
>
<div className={`self-stretch justify-start text-Text-Dark-950 text-sm leading-tight ${index === 2 ? 'font-medium' : 'font-normal'
}`}>
{employee.name}
</div>
</div>
))}
</div>
);
};
const renderUploadedFiles = () => {
if (state.uploadedFiles.length === 0) return null;
return (
<div className="inline-flex justify-start items-center gap-3 mb-4">
{state.uploadedFiles.map((file, index) => (
<div key={index} className="w-40 max-w-40 p-2 bg-Text-White-00 rounded-full outline outline-1 outline-offset-[-1px] outline-Outline-Outline-Gray-200 inline-flex flex-col justify-start items-start gap-2.5 overflow-hidden">
<div className="self-stretch pr-2 inline-flex justify-between items-center">
<div className="flex-1 flex justify-start items-center gap-1.5">
<div className="w-6 h-6 relative bg-Icon-Gray-600 rounded-full overflow-hidden">
<div className="left-[6px] top-[6px] absolute">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 1.13477V3.20004C7 3.48006 7 3.62007 7.0545 3.72703C7.10243 3.82111 7.17892 3.8976 7.273 3.94554C7.37996 4.00004 7.51997 4.00004 7.8 4.00004H9.86527M8 6.5H4M8 8.5H4M5 4.5H4M7 1H4.4C3.55992 1 3.13988 1 2.81901 1.16349C2.53677 1.3073 2.3073 1.53677 2.16349 1.81901C2 2.13988 2 2.55992 2 3.4V8.6C2 9.44008 2 9.86012 2.16349 10.181C2.3073 10.4632 2.53677 10.6927 2.81901 10.8365C3.13988 11 3.55992 11 4.4 11H7.6C8.44008 11 8.86012 11 9.18099 10.8365C9.46323 10.6927 9.6927 10.4632 9.83651 10.181C10 9.86012 10 9.44008 10 8.6V4L7 1Z" stroke="var(--Text-White-00, #FDFDFD)" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
<div className="flex-1 justify-start text-Text-Dark-950 text-sm font-medium font-['Inter'] leading-tight">{file.name}</div>
</div>
<div onClick={() => removeFile(index)} className="cursor-pointer">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 4L4 12M4 4L12 12" stroke="var(--Icon-Gray-400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
</div>
))}
</div>
);
};
const renderChatInterface = () => {
if (state.messages.length === 0) {
return (
<div className="w-[736px] flex-1 max-w-[736px] pt-48 flex flex-col justify-between items-center">
<div className="self-stretch flex flex-col justify-start items-center gap-6">
<div className="justify-start text-Text-Gray-800 text-2xl font-medium font-['Neue_Montreal'] leading-normal">What would you like to understand?</div>
<div className="p-1 bg-Neutrals-NeutralSlate100 rounded-xl inline-flex justify-start items-center gap-1">
{categories.map((category) => (
<div
key={category}
onClick={() => setSelectedCategory(category)}
className={`px-3 py-1.5 rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden cursor-pointer ${selectedCategory === category ? 'bg-white' : ''
}`}
>
<div className="px-0.5 flex justify-center items-center">
<div className={`justify-start text-xs font-medium font-['Inter'] leading-none ${selectedCategory === category ? 'text-Neutrals-NeutralSlate900' : 'text-Neutrals-NeutralSlate600'
}`}>{category}</div>
</div>
</div>
))}
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="self-stretch inline-flex justify-start items-center gap-3">
{questionStarters.map((question, index) => (
<div
key={index}
onClick={() => handleQuestionClick(question)}
className="flex-1 h-48 px-3 py-4 bg-Main-BG-Gray-50 rounded-2xl inline-flex flex-col justify-between items-start overflow-hidden cursor-pointer hover:bg-Main-BG-Gray-100"
>
<div>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19557)">
<path d="M7.57496 7.5013C7.77088 6.94436 8.15759 6.47472 8.66659 6.17558C9.17559 5.87643 9.77404 5.76708 10.3559 5.8669C10.9378 5.96671 11.4656 6.26924 11.8459 6.72091C12.2261 7.17258 12.4342 7.74424 12.4333 8.33464C12.4333 10.0013 9.93329 10.8346 9.93329 10.8346M9.99996 14.168H10.0083M18.3333 10.0013C18.3333 14.6037 14.6023 18.3346 9.99996 18.3346C5.39759 18.3346 1.66663 14.6037 1.66663 10.0013C1.66663 5.39893 5.39759 1.66797 9.99996 1.66797C14.6023 1.66797 18.3333 5.39893 18.3333 10.0013Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_818_19557">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
</div>
<div className="self-stretch justify-start text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">{question}</div>
</div>
))}
</div>
</div>
</div>
{renderChatInput()}
</div>
);
}
return (
<div className="w-[736px] flex-1 max-w-[736px] flex flex-col">
<div className="flex-1 overflow-y-auto py-6">
{state.messages.map((message) => (
<div key={message.id} className={`mb-4 flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div className={`max-w-[80%] p-4 rounded-2xl ${message.role === 'user'
? 'bg-Brand-Orange text-white'
: 'bg-Main-BG-Gray-50 text-Text-Gray-800'
}`}>
{message.content}
</div>
</div>
))}
{state.isLoading && (
<div className="flex justify-start mb-4">
<div className="bg-Main-BG-Gray-50 text-Text-Gray-800 p-4 rounded-2xl">
<div className="flex space-x-1">
<div className="w-2 h-2 bg-Text-Gray-500 rounded-full animate-bounce"></div>
<div className="w-2 h-2 bg-Text-Gray-500 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div>
<div className="w-2 h-2 bg-Text-Gray-500 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div>
</div>
</div>
</div>
)}
</div>
{renderChatInput()}
</div>
);
};
const renderChatInput = () => {
return (
<div className="self-stretch pl-5 pr-3 pt-5 pb-3 relative bg-Main-BG-Gray-50 rounded-3xl flex flex-col justify-start items-start gap-4">
{renderUploadedFiles()}
<div className="self-stretch justify-start text-Text-Gray-500 text-base font-normal font-['Inter'] leading-normal">
{currentInput || "Ask anything, use @ to tag staff and ask questions."}
</div>
<div className="self-stretch inline-flex justify-between items-center">
<div className="flex justify-start items-center gap-4">
<div onClick={() => fileInputRef.current?.click()} className="cursor-pointer">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.6271 9.08442L10.1141 16.5974C8.40556 18.306 5.63546 18.306 3.92692 16.5974C2.21837 14.8889 2.21837 12.1188 3.92692 10.4102L11.4399 2.89724C12.579 1.75821 14.4257 1.75821 15.5647 2.89724C16.7037 4.03627 16.7037 5.883 15.5647 7.02203L8.34633 14.2404C7.77682 14.8099 6.85345 14.8099 6.28394 14.2404C5.71442 13.6709 5.71442 12.7475 6.28394 12.178L12.6184 5.84352" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div onClick={() => fileInputRef.current?.click()} className="cursor-pointer">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5 17.5H5.77614C5.2713 17.5 5.01887 17.5 4.90199 17.4002C4.80056 17.3135 4.74674 17.1836 4.75721 17.0506C4.76927 16.8974 4.94776 16.7189 5.30474 16.3619L12.3905 9.27614C12.7205 8.94613 12.8855 8.78112 13.0758 8.7193C13.2432 8.66492 13.4235 8.66492 13.5908 8.7193C13.7811 8.78112 13.9461 8.94613 14.2761 9.27614L17.5 12.5V13.5M13.5 17.5C14.9001 17.5 15.6002 17.5 16.135 17.2275C16.6054 16.9878 16.9878 16.6054 17.2275 16.135C17.5 15.6002 17.5 14.9001 17.5 13.5M13.5 17.5H6.5C5.09987 17.5 4.3998 17.5 3.86502 17.2275C3.39462 16.9878 3.01217 16.6054 2.77248 16.135C2.5 15.6002 2.5 14.9001 2.5 13.5V6.5C2.5 5.09987 2.5 4.3998 2.77248 3.86502C3.01217 3.39462 3.39462 3.01217 3.86502 2.77248C4.3998 2.5 5.09987 2.5 6.5 2.5H13.5C14.9001 2.5 15.6002 2.5 16.135 2.77248C16.6054 3.01217 16.9878 3.39462 17.2275 3.86502C17.5 4.3998 17.5 5.09987 17.5 6.5V13.5M8.75 7.08333C8.75 8.00381 8.00381 8.75 7.08333 8.75C6.16286 8.75 5.41667 8.00381 5.41667 7.08333C5.41667 6.16286 6.16286 5.41667 7.08333 5.41667C8.00381 5.41667 8.75 6.16286 8.75 7.08333Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="cursor-pointer">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19694)">
<path d="M13.3334 6.66745V10.8341C13.3334 11.4972 13.5968 12.133 14.0657 12.6019C14.5345 13.0707 15.1704 13.3341 15.8334 13.3341C16.4965 13.3341 17.1324 13.0707 17.6012 12.6019C18.07 12.133 18.3334 11.4972 18.3334 10.8341V10.0008C18.3333 8.11998 17.6969 6.29452 16.5278 4.82123C15.3587 3.34794 13.7256 2.31347 11.894 1.88603C10.0624 1.45859 8.14003 1.66332 6.43955 2.46692C4.73906 3.27053 3.36042 4.62575 2.5278 6.31222C1.69519 7.99869 1.45756 9.91723 1.85356 11.7559C2.24956 13.5945 3.2559 15.2451 4.70895 16.4393C6.16199 17.6335 7.97628 18.3011 9.85681 18.3334C11.7373 18.3657 13.5735 17.761 15.0668 16.6175M13.3334 10.0008C13.3334 11.8417 11.841 13.3341 10.0001 13.3341C8.15914 13.3341 6.66676 11.8417 6.66676 10.0008C6.66676 8.15984 8.15914 6.66745 10.0001 6.66745C11.841 6.66745 13.3334 8.15984 13.3334 10.0008Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_818_19694">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
</div>
</div>
<div
onClick={handleSendMessage}
className={`p-2.5 rounded-[999px] flex justify-start items-center gap-2.5 overflow-hidden cursor-pointer ${currentInput.trim() || state.uploadedFiles.length > 0
? 'bg-Main-BG-Gray-800'
: 'bg-Text-Gray-300'
}`}
>
<div>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 13.3346V2.66797M8 2.66797L4 6.66797M8 2.66797L12 6.66797" stroke="var(--Text-White-00, #FDFDFD)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
</div>
{renderEmployeeMenu()}
<textarea
ref={inputRef}
value={currentInput}
onChange={handleInputChange}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSendMessage();
}
}}
className="absolute inset-0 w-full h-full opacity-0 resize-none outline-none"
placeholder=""
/>
<input
ref={fileInputRef}
type="file"
multiple
onChange={handleFileUpload}
className="hidden"
accept=".pdf,.doc,.docx,.txt,.png,.jpg,.jpeg"
/>
</div>
);
};
return (
<div className="w-[1440px] h-[810px] p-4 bg-Neutrals-NeutralSlate200 inline-flex justify-start items-start overflow-hidden">
<div className="flex-1 self-stretch rounded-3xl shadow-[0px_0px_15px_0px_rgba(0,0,0,0.08)] flex justify-between items-start overflow-hidden">
<Sidebar companyName="Zitlac Media" />
<div className="flex-1 self-stretch py-6 bg-Neutrals-NeutralSlate0 inline-flex flex-col justify-center items-center gap-2.5">
{renderChatInterface()}
</div>
</div>
</div>
);
};
export default ChatNew;

View File

@@ -1,33 +1,69 @@
import React, { useEffect, useState } from 'react';
import { useOrg } from '../contexts/OrgContext';
import { Card, Button } from '../components/UiKit';
import { FigmaAlert } from '../components/figma/FigmaAlert';
import { CompanyReport } from '../types';
import RadarPerformanceChart from '../components/charts/RadarPerformanceChart';
import { CompanyWikiManager } from '../components/CompanyWiki';
const CompanyWiki: React.FC = () => {
const { org, employees, getFullCompanyReportHistory, generateCompanyWiki } = useOrg();
const [isGenerating, setIsGenerating] = useState(false);
const [companyReport, setCompanyReport] = useState<CompanyReport | null>(null);
const [error, setError] = useState<string | null>(null);
const [onboardingProgress, setOnboardingProgress] = useState(60);
useEffect(() => {
(async () => {
try {
const history = await getFullCompanyReportHistory();
if (history.length) setCompanyReport(history[0]);
if (history.length) {
setCompanyReport(history[0]);
}
} catch (e) {
console.error('Failed loading company report history', e);
}
})();
}, [getFullCompanyReportHistory]);
const generateReport = async () => {
// Determine wiki state based on company data
const wikiState = companyReport ? 'completed' : 'empty';
// Create Q&A items from company report or org data
const qaItems = companyReport ? [
{
question: "What is the mission of your company?",
answer: org?.mission || "To empower small businesses with AI-driven automation tools that increase efficiency and reduce operational overhead."
},
{
question: "How has your mission evolved in the last 13 years?",
answer: org?.evolution || "We shifted from general SaaS tools to vertical-specific solutions, with deeper integrations and onboarding support."
},
{
question: "What is your 5-year vision for the company?",
answer: org?.vision || "To become the leading AI operations platform for SMBs in North America, serving over 100,000 customers."
},
{
question: "What are your company's top 3 strategic advantages?",
answer: org?.advantages || "Fast product iteration enabled by in-house AI capabilities\nDeep customer understanding from vertical specialization\nHigh customer retention due to integrated onboarding"
},
{
question: "What are your biggest vulnerabilities or threats?",
answer: org?.vulnerabilities || "Dependence on a single marketing channel, weak middle management, and rising customer acquisition costs."
}
] : undefined;
// Convert employees to suggested format for invitations
const suggestedEmployees = employees?.map(emp => ({
id: emp.id,
name: emp.name || emp.email,
email: emp.email
})) || [];
const handleCompleteOnboarding = async () => {
setIsGenerating(true);
setError(null);
try {
const report = await generateCompanyWiki();
setCompanyReport(report);
setOnboardingProgress(100);
} catch (e: any) {
console.error(e);
setError('Failed to generate company wiki');
@@ -37,296 +73,22 @@ const CompanyWiki: React.FC = () => {
};
return (
<div className="p-6 max-w-6xl mx-auto">
<div className="mb-6">
<h1 className="text-3xl font-bold text-[--text-primary]">Company Wiki</h1>
<p className="text-[--text-secondary] mt-1">
Organization overview and insights
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
<Card>
<h3 className="text-lg font-semibold text-[--text-primary] mb-3">Company Info</h3>
<div className="space-y-2">
<div>
<span className="text-sm text-[--text-secondary]">Name:</span>
<div className="font-medium text-[--text-primary]">{org?.name}</div>
</div>
<div>
<span className="text-sm text-[--text-secondary]">Industry:</span>
<div className="font-medium text-[--text-primary]">{org?.industry}</div>
</div>
<div>
<span className="text-sm text-[--text-secondary]">Size:</span>
<div className="font-medium text-[--text-primary]">{org?.size}</div>
</div>
</div>
</Card>
<Card>
<h3 className="text-lg font-semibold text-[--text-primary] mb-3">Team Stats</h3>
<div className="space-y-2">
<div>
<span className="text-sm text-[--text-secondary]">Total Employees:</span>
<div className="font-medium text-[--text-primary]">{employees.length}</div>
</div>
<div>
<span className="text-sm text-[--text-secondary]">Departments:</span>
<div className="font-medium text-[--text-primary]">
{[...new Set(employees.map(e => e.department))].length}
</div>
</div>
<div>
<span className="text-sm text-[--text-secondary]">Roles:</span>
<div className="font-medium text-[--text-primary]">
{[...new Set(employees.map(e => e.role))].length}
</div>
</div>
</div>
</Card>
<Card>
<h3 className="text-lg font-semibold text-[--text-primary] mb-3">Quick Actions</h3>
<div className="space-y-3">
<Button onClick={generateReport} disabled={isGenerating} className="w-full">
{isGenerating ? 'Generating...' : companyReport ? 'Regenerate Company Wiki' : 'Generate Company Wiki'}
</Button>
{error && <FigmaAlert type="error" message={error} />}
{!companyReport && !isGenerating && (
<FigmaAlert type="info" message="No company wiki generated yet. Use the button above to create one." />
)}
<Button variant="secondary" className="w-full" disabled={!companyReport}>
Export Data
</Button>
</div>
</Card>
</div>
{companyReport && (
<div className="space-y-6">
<Card>
<h3 className="text-xl font-semibold text-[--text-primary] mb-4">Executive Summary</h3>
<p className="text-[--text-secondary] whitespace-pre-line mb-4">{companyReport.executiveSummary}</p>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="text-center p-4 bg-[--background-secondary] rounded-lg">
<div className="text-2xl font-bold text-blue-500">{companyReport.overview.totalEmployees}</div>
<div className="text-sm text-[--text-secondary]">Employees</div>
</div>
<div className="text-center p-4 bg-[--background-secondary] rounded-lg">
<div className="text-2xl font-bold text-green-500">{companyReport.overview?.departmentBreakdown?.length || 0}</div>
<div className="text-sm text-[--text-secondary]">Departments</div>
</div>
<div className="text-center p-4 bg-[--background-secondary] rounded-lg">
<div className="text-2xl font-bold text-purple-500">{companyReport.organizationalStrengths?.length || 0}</div>
<div className="text-sm text-[--text-secondary]">Strength Areas</div>
</div>
<div className="text-center p-4 bg-[--background-secondary] rounded-lg">
<div className="text-2xl font-bold text-orange-500">{companyReport.organizationalRisks?.length || 0}</div>
<div className="text-sm text-[--text-secondary]">Risks</div>
</div>
</div>
{(Array.isArray(companyReport.gradingOverview) && companyReport.gradingOverview.length > 0) && (
<div className="mt-6 p-4 bg-[--background-tertiary] rounded-lg">
<RadarPerformanceChart
title="Organizational Grading"
data={companyReport.gradingOverview.map((g: any) => ({
label: g.category || g.department || g.subject || 'Metric',
value: g.value ?? g.averageScore ?? 0
}))}
/>
</div>
)}
</Card>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<Card>
<h4 className="text-lg font-semibold text-[--text-primary] mb-3">Strengths</h4>
<ul className="space-y-2">
{(companyReport.organizationalStrengths || []).map((s: any, i) => <li key={i} className="text-[--text-secondary] text-sm"> {s.area || s}</li>)}
</ul>
</Card>
<Card>
<h4 className="text-lg font-semibold text-[--text-primary] mb-3">Risks</h4>
<ul className="space-y-2">
{(companyReport.organizationalRisks || []).map((r, i) => <li key={i} className="text-[--text-secondary] text-sm"> {r}</li>)}
</ul>
</Card>
<Card>
<h4 className="text-lg font-semibold text-[--text-primary] mb-3">Forward Plan</h4>
<div>
<h5 className="font-medium text-[--text-primary] text-sm mb-1">Goals</h5>
<ul className="mb-2 list-disc list-inside text-[--text-secondary] text-sm space-y-1">
{(companyReport.operatingPlan?.nextQuarterGoals || companyReport.forwardOperatingPlan?.quarterlyGoals || []).map((g: string, i: number) => <li key={i}>{g}</li>)}
</ul>
<h5 className="font-medium text-[--text-primary] text-sm mb-1">Resource Needs</h5>
<ul className="mb-2 list-disc list-inside text-[--text-secondary] text-sm space-y-1">
{(companyReport.operatingPlan?.resourceNeeds || companyReport.forwardOperatingPlan?.resourceNeeds || []).map((g: string, i: number) => <li key={i}>{g}</li>)}
</ul>
<h5 className="font-medium text-[--text-primary] text-sm mb-1">Risk Mitigation</h5>
<ul className="list-disc list-inside text-[--text-secondary] text-sm space-y-1">
{(companyReport.operatingPlan?.riskMitigation || companyReport.forwardOperatingPlan?.riskMitigation || []).map((g: string, i: number) => <li key={i}>{g}</li>)}
</ul>
</div>
</Card>
</div>
<div className="flex-1 self-stretch bg-Neutrals-NeutralSlate0 rounded-tr-3xl rounded-br-3xl inline-flex flex-col justify-start items-start">
{error && (
<div className="self-stretch p-4 bg-red-50 border-l-4 border-red-400 text-red-700 text-sm">
{error}
</div>
)}
{/* Company Profile - Q&A Format from Onboarding */}
<div className="mt-6">
<h3 className="text-2xl font-semibold text-[--text-primary] mb-6">Company Profile</h3>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{org?.mission && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What is your company's mission?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.mission}</p>
</div>
</div>
</Card>
)}
{org?.vision && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What is your company's vision?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.vision}</p>
</div>
</div>
</Card>
)}
{org?.evolution && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">How has your company evolved over time?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.evolution}</p>
</div>
</div>
</Card>
)}
{org?.advantages && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What are your competitive advantages?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.advantages}</p>
</div>
</div>
</Card>
)}
{org?.vulnerabilities && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What are your key vulnerabilities?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.vulnerabilities}</p>
</div>
</div>
</Card>
)}
{org?.shortTermGoals && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What are your short-term goals?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.shortTermGoals}</p>
</div>
</div>
</Card>
)}
{org?.longTermGoals && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What are your long-term goals?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.longTermGoals}</p>
</div>
</div>
</Card>
)}
{org?.cultureDescription && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">How would you describe your company culture?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.cultureDescription}</p>
</div>
</div>
</Card>
)}
{org?.workEnvironment && (
<Card className="p-4">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">What is your work environment like?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.workEnvironment}</p>
</div>
</div>
</Card>
)}
{org?.additionalContext && (
<Card className="p-4 lg:col-span-2">
<div className="space-y-3">
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Question:</h4>
<p className="text-[--text-primary] font-medium">Any additional context about your company?</p>
</div>
<div>
<h4 className="text-sm font-medium text-[--text-secondary] mb-1">Answer:</h4>
<p className="text-[--text-primary] text-sm leading-relaxed">{org.additionalContext}</p>
</div>
</div>
</Card>
)}
</div>
</div>
{org?.description && (
<Card className="mt-6">
<h3 className="text-lg font-semibold text-[--text-primary] mb-3">About</h3>
<p className="text-[--text-secondary]">{org.description}</p>
</Card>
)}
<CompanyWikiManager
initialState={wikiState}
onboardingProgress={onboardingProgress}
onCompleteOnboarding={handleCompleteOnboarding}
qaItems={qaItems}
suggestedEmployees={suggestedEmployees}
/>
</div>
);
};
export default CompanyWiki;
export default CompanyWiki;

101
pages/EmployeeFormNew.tsx Normal file
View File

@@ -0,0 +1,101 @@
import React, { useState } from 'react';
const EmployeeFormNew: React.FC = () => {
const [currentStep, setCurrentStep] = useState(1);
return (
<div className="w-[1440px] bg-white 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">
<div className="w-12 h-12 relative bg-Brand-Orange rounded-xl outline outline-2 outline-offset-[-2px] outline-blue-400 overflow-hidden">
<div className="w-12 h-12 left-0 top-0 absolute bg-gradient-to-b from-white/0 to-white/10" />
<div className="left-[12px] top-[9.33px] absolute">
<svg width="24" height="30" viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M2.57408 17.8138C3.11835 18.3649 3.11834 19.2585 2.57406 19.8097L2.54619 19.8379C2.00191 20.389 1.11946 20.389 0.57519 19.8379C0.030919 19.2867 0.0309274 18.3931 0.575208 17.842L0.603083 17.8137C1.14736 17.2626 2.02981 17.2626 2.57408 17.8138Z" fill="url(#paint0_linear_981_10577)" />
<path opacity="0.7" fillRule="evenodd" clipRule="evenodd" d="M9.12583 18.2374C9.66912 18.7896 9.66752 19.6832 9.12226 20.2333L5.2617 24.1286C4.71644 24.6787 3.83399 24.6771 3.2907 24.125C2.74741 23.5728 2.74901 22.6792 3.29427 22.1291L7.15483 18.2338C7.70009 17.6837 8.58254 17.6853 9.12583 18.2374Z" fill="url(#paint1_linear_981_10577)" />
<defs>
<linearGradient id="paint0_linear_981_10577" x1="1.57463" y1="17.4004" x2="1.57463" y2="20.2513" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
<linearGradient id="paint1_linear_981_10577" x1="6.20827" y1="17.8223" x2="6.20827" y2="24.5401" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
</defs>
</svg>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="self-stretch justify-start text-Neutrals-NeutralSlate950 text-2xl font-semibold font-['Inter'] leading-8">Welcome to the Auditly Employee Assessment</div>
<div className="self-stretch justify-start text-Neutrals-NeutralSlate500 text-base font-normal font-['Inter'] leading-normal">Let's learn about your role, contribution and help us get a better understand of how you work best.</div>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-8">
<div className="self-stretch flex flex-col justify-start items-start gap-6">
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight">Your Role & Output</div>
</div>
<div className="self-stretch justify-start text-Neutrals-NeutralSlate500 text-sm font-normal font-['Inter'] leading-tight">Tell us about your current role and what you work on</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">Your Name</div>
<div className="justify-start text-Brand-Orange text-sm font-medium font-['Inter'] leading-tight">*</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<input
type="text"
className="flex-1 bg-transparent text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight placeholder:text-Neutrals-NeutralSlate500 outline-none"
placeholder="Enter your full name"
/>
</div>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">What is your role at the company?</div>
<div className="justify-start text-Brand-Orange text-sm font-medium font-['Inter'] leading-tight">*</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<input
type="text"
className="flex-1 bg-transparent text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight placeholder:text-Neutrals-NeutralSlate500 outline-none"
placeholder="e.g. Software Engineer, Marketing Manager"
/>
</div>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">What department do you work in?</div>
<div className="justify-start text-Brand-Orange text-sm font-medium font-['Inter'] leading-tight">*</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<input
type="text"
className="flex-1 bg-transparent text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight placeholder:text-Neutrals-NeutralSlate500 outline-none"
placeholder="e.g. Engineering, Sales, Marketing"
/>
</div>
</div>
</div>
</div>
<div className="self-stretch inline-flex justify-start items-center gap-3">
<button className="flex-1 px-6 py-3.5 bg-Brand-Orange rounded-[999px] inline-flex justify-center items-center gap-2 overflow-hidden">
<div className="justify-center text-Neutrals-NeutralSlate0 text-base font-medium font-['Inter'] leading-normal">Continue</div>
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default EmployeeFormNew;

File diff suppressed because it is too large Load Diff

133
pages/HelpNew.tsx Normal file
View File

@@ -0,0 +1,133 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import Sidebar from '../components/figma/Sidebar';
interface FAQItem {
question: string;
answer: string;
isOpen: boolean;
}
const HelpNew: React.FC = () => {
const { user } = useAuth();
const navigate = useNavigate();
const [faqItems, setFaqItems] = useState<FAQItem[]>([
{
question: "What is the process for submitting a support ticket?",
answer: "Team members will undergo evaluations every three months, focusing on their performance, teamwork, and communication skills. Role advancements will be considered at these intervals.",
isOpen: true
},
{
question: "How can I reset my password?",
answer: "To reset your password, click on the 'Forgot Password' link on the login page and follow the instructions sent to your email address.",
isOpen: false
},
{
question: "What are the criteria for performance reviews?",
answer: "Performance reviews are based on multiple factors including goal achievement, collaboration, innovation, and adherence to company values. Reviews are conducted quarterly with detailed feedback sessions.",
isOpen: false
},
{
question: "How can I access the company's training resources?",
answer: "Training resources are available through our internal learning portal. You can access them from the main dashboard under the 'Learning & Development' section.",
isOpen: false
},
{
question: "What should I do if I encounter a technical issue?",
answer: "For technical issues, first check our troubleshooting guide. If the issue persists, contact our IT support team through the help desk or email support@company.com.",
isOpen: false
},
{
question: "How do I provide feedback on team projects?",
answer: "Feedback can be provided through our project management system or during regular team meetings. We encourage constructive feedback that helps improve project outcomes.",
isOpen: false
}
]);
const toggleFAQ = (index: number) => {
setFaqItems(prev => prev.map((item, i) => ({
...item,
isOpen: i === index ? !item.isOpen : item.isOpen
})));
};
const handleContactUs = () => {
// In a real app, this would open a contact form or support chat
alert('Contact functionality would be implemented here');
};
if (!user) {
navigate('/login');
return null;
}
return (
<div className="w-[1440px] h-[840px] p-4 bg-Neutrals-NeutralSlate200 inline-flex justify-start items-start overflow-hidden">
<div className="flex-1 self-stretch rounded-3xl shadow-[0px_0px_15px_0px_rgba(0,0,0,0.08)] flex justify-between items-start overflow-hidden">
<Sidebar companyName="Zitlac Media" />
<div className="flex-1 self-stretch pt-8 pb-6 bg-Neutrals-NeutralSlate0 inline-flex flex-col justify-start items-center gap-6">
<div className="w-[680px] justify-start text-Text-Gray-800 text-2xl font-medium font-['Neue_Montreal'] leading-normal">Help & Support</div>
<div className="w-[680px] flex flex-col justify-start items-start gap-4">
{faqItems.map((item, index) => (
<div
key={index}
className="self-stretch p-3 bg-Text-Gray-100 rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1 overflow-hidden"
>
<div
onClick={() => toggleFAQ(index)}
className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2 cursor-pointer"
>
<div className="flex-1 justify-start text-Text-Dark-950 text-base font-medium font-['Inter'] leading-normal">
{item.question}
</div>
<div>
{item.isOpen ? (
<svg width="12" height="2" viewBox="0 0 12 2" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 1L1 1" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
) : (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.99996 4.16797V15.8346M4.16663 10.0013H15.8333" stroke="var(--Text-Gray-400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
</div>
<div className="w-5 h-5 opacity-0 border border-zinc-800" />
</div>
{item.isOpen && (
<div className="self-stretch p-6 bg-Neutrals-NeutralSlate0 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Neutrals-NeutralSlate200 flex flex-col justify-start items-start gap-4">
<div className="self-stretch justify-start text-Neutrals-NeutralSlate800 text-base font-normal font-['Inter'] leading-normal">
{item.answer}
</div>
</div>
)}
</div>
))}
</div>
<div className="w-[680px] px-5 py-4 bg-Text-Gray-800 rounded-2xl backdrop-blur-blur inline-flex justify-center items-center gap-12 overflow-hidden">
<div className="flex-1 inline-flex flex-col justify-center items-start gap-2">
<div className="self-stretch justify-start text-Text-White-00 text-base font-medium font-['Inter'] leading-normal">Still have questions?</div>
<div className="self-stretch justify-start text-Text-Gray-400 text-sm font-normal font-['Inter'] leading-tight">We are available for 24/7</div>
</div>
<div
onClick={handleContactUs}
className="px-3 py-2.5 bg-Brand-Orange rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden cursor-pointer hover:bg-Brand-Orange/90"
>
<div>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.58685 5.90223C6.05085 6.86865 6.68337 7.77441 7.48443 8.57546C8.28548 9.37651 9.19124 10.009 10.1577 10.473C10.2408 10.5129 10.2823 10.5329 10.3349 10.5482C10.5218 10.6027 10.7513 10.5636 10.9096 10.4502C10.9542 10.4183 10.9923 10.3802 11.0685 10.304C11.3016 10.071 11.4181 9.95443 11.5353 9.87824C11.9772 9.59091 12.5469 9.59091 12.9889 9.87824C13.106 9.95443 13.2226 10.071 13.4556 10.304L13.5856 10.4339C13.9398 10.7882 14.117 10.9654 14.2132 11.1556C14.4046 11.534 14.4046 11.9809 14.2132 12.3592C14.117 12.5495 13.9399 12.7266 13.5856 13.0809L13.4805 13.186C13.1274 13.5391 12.9508 13.7156 12.7108 13.8505C12.4445 14.0001 12.0308 14.1077 11.7253 14.1068C11.45 14.1059 11.2619 14.0525 10.8856 13.9457C8.86333 13.3718 6.95509 12.2888 5.36311 10.6968C3.77112 9.10479 2.68814 7.19655 2.11416 5.17429C2.00735 4.79799 1.95395 4.60984 1.95313 4.33455C1.95222 4.02906 2.0598 3.6154 2.20941 3.34907C2.34424 3.10904 2.52078 2.9325 2.87386 2.57942L2.97895 2.47433C3.33325 2.12004 3.5104 1.94289 3.70065 1.84666C4.07903 1.65528 4.52587 1.65528 4.90424 1.84666C5.0945 1.94289 5.27164 2.12004 5.62594 2.47433L5.75585 2.60424C5.98892 2.83732 6.10546 2.95385 6.18165 3.07104C6.46898 3.51296 6.46898 4.08268 6.18165 4.52461C6.10546 4.6418 5.98892 4.75833 5.75585 4.9914C5.67964 5.06761 5.64154 5.10571 5.60965 5.15026C5.4963 5.30854 5.45717 5.53805 5.51165 5.72495C5.52698 5.77754 5.54694 5.81911 5.58685 5.90223Z" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Contact Us</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default HelpNew;

View File

@@ -1,266 +1,403 @@
import React, { useState, useEffect } from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import { useOrg } from '../contexts/OrgContext';
import { Card, Button } from '../components/UiKit';
import { Button } from '../components/UiKit';
const Login: React.FC = () => {
type AuthStep = 'email' | 'otp' | 'password-fallback';
const ModernLogin: React.FC = () => {
const navigate = useNavigate();
const location = useLocation();
const { inviteCode: routeInviteCode } = useParams<{ inviteCode: string }>();
const [email, setEmail] = useState('demo@auditly.com');
const [password, setPassword] = useState('demo123');
// Auth state
const { signInWithGoogle, signInWithEmail, signUpWithEmail, user, loading, sendOTP: authSendOTP, verifyOTP: authVerifyOTP } = useAuth();
// Form state
const [step, setStep] = useState<AuthStep>('email');
const [email, setEmail] = useState('');
const [otp, setOtp] = useState('');
const [password, setPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [inviteCode, setInviteCode] = useState<string | null>(null);
const { signInWithGoogle, signInWithEmail, signUpWithEmail, user, loading } = useAuth();
const { consumeInvite, org } = useOrg();
const [resendCooldown, setResendCooldown] = useState(0);
const [demoOTP, setDemoOTP] = useState<string | null>(null);
// Extract invite code from URL
useEffect(() => {
// Check for invite code in route params first, then fallback to query params
if (routeInviteCode) {
console.log('Invite code from route params:', routeInviteCode);
setInviteCode(routeInviteCode);
// Clear demo credentials for invite flow
setEmail('');
setPassword('');
} else {
// Extract query params from hash-based URL
const hashSearch = location.hash.includes('?') ? location.hash.split('?')[1] : '';
const searchParams = new URLSearchParams(hashSearch);
const queryInvite = searchParams.get('invite');
if (queryInvite) {
console.log('Invite code from query params:', queryInvite);
setInviteCode(queryInvite);
// Clear demo credentials for invite flow
setEmail('');
setPassword('');
}
}
}, [routeInviteCode, location]);
const handleSuccessfulLogin = async () => {
if (inviteCode) {
// Invite flow - redirect to org selection with invite code
navigate(`/org-selection?invite=${inviteCode}`, { replace: true });
} else {
// Regular login - redirect to org selection to choose/create org
navigate('/org-selection', { replace: true });
}
};
// Handle successful authentication
useEffect(() => {
if (user && !loading) {
handleSuccessfulLogin();
}
}, [user, loading]);
const handleEmailLogin = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError('');
try {
if (inviteCode) {
// For invites, try to create account first since they're new users
console.log('Invite flow: attempting to create account for', email);
await signUpWithEmail(email, password, email.split('@')[0]);
navigate(`/org-selection?invite=${inviteCode}`, { replace: true });
} else {
// Regular login
await signInWithEmail(email, password);
}
// Success will be handled by the useEffect hook
} catch (error) {
console.error('Auth failed:', error);
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
if (inviteCode) {
// For invite flow, if account creation failed, try login instead
if (errorMessage.includes('User already exists') || errorMessage.includes('already-exists')) {
try {
console.log('Account exists, trying login instead...');
await signInWithEmail(email, password);
} catch (loginError) {
console.error('Login also failed:', loginError);
setError(`Account exists but password is incorrect. Please check your password or contact your administrator.`);
setIsLoading(false);
}
} else {
setError(`Failed to create account: ${errorMessage}. Please try a different email or contact your administrator.`);
setIsLoading(false);
}
} else {
// Regular login flow - try signup if user not found
if (errorMessage.includes('User not found')) {
try {
console.log('User not found, attempting sign-up...');
await signUpWithEmail(email, password, email.split('@')[0]);
// Success will be handled by the useEffect hook
} catch (signUpError) {
console.error('Sign-up also failed:', signUpError);
setError(`Failed to create account: ${signUpError instanceof Error ? signUpError.message : 'Unknown error'}`);
setIsLoading(false);
}
} else {
setError(`Login failed: ${errorMessage}`);
setIsLoading(false);
}
navigate('/org-selection', { replace: true });
}
}
};
}, [user, loading, navigate, inviteCode]);
const handleGoogleLogin = async () => {
setIsLoading(true);
setError('');
// Resend cooldown timer
useEffect(() => {
if (resendCooldown > 0) {
const timer = setTimeout(() => setResendCooldown(resendCooldown - 1), 1000);
return () => clearTimeout(timer);
}
}, [resendCooldown]);
const sendOTP = async (emailAddress: string) => {
try {
await signInWithGoogle();
// Success will be handled by the useEffect hook
} catch (error) {
console.error('Google login failed:', error);
setError(`Google login failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
setIsLoading(true);
setError('');
setDemoOTP(null);
// Call auth context method
const response = await authSendOTP(emailAddress, inviteCode || undefined);
// If OTP is returned in response (demo mode), display it
if (response.otp) {
setDemoOTP(response.otp);
}
setStep('otp');
setResendCooldown(60); // 60 second cooldown
} catch (err) {
console.error('OTP send error:', err);
setError(err instanceof Error ? err.message : 'Failed to send verification code. Please try again.');
} finally {
setIsLoading(false);
}
}; const verifyOTP = async () => {
try {
setIsLoading(true);
setError('');
// Call auth context method
await authVerifyOTP(email, otp, inviteCode || undefined);
// Success - user will be set in auth context and useEffect will handle navigation
} catch (err) {
console.error('OTP verification error:', err);
setError(err instanceof Error ? err.message : 'Invalid verification code. Please try again.');
} finally {
setIsLoading(false);
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-[--background-primary] py-12 px-4 sm:px-6 lg:px-8">
<Card className="max-w-md w-full space-y-8" padding="lg">
<div className="text-center">
<div className="w-16 h-16 bg-blue-500 rounded-full flex items-center justify-center font-bold text-white text-2xl mx-auto mb-4">
A
</div>
<h2 className="text-3xl font-bold text-[--text-primary]">Welcome to Auditly</h2>
<p className="text-[--text-secondary] mt-2">
{inviteCode ? 'Complete your profile to join the team survey' : 'Sign in to your account'}
</p>
{inviteCode && (
<div className="mt-3 p-3 bg-blue-100 dark:bg-blue-900 rounded-lg">
<p className="text-sm text-blue-800 dark:text-blue-200">
<EFBFBD> <strong>Employee Survey Invitation</strong><br />
No account needed! Just create a password to secure your responses and start the questionnaire.
</p>
</div>
)}
{error && (
<div className="mt-3 p-3 bg-red-100 dark:bg-red-900 rounded-lg">
<p className="text-sm text-red-800 dark:text-red-200">
{error}
</p>
</div>
)}
</div>
const handleEmailSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email.trim()) return;
<form onSubmit={handleEmailLogin} className="space-y-6">
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Email {inviteCode && <span className="text-gray-500 dark:text-gray-400">(use your work email)</span>}
</label>
await sendOTP(email);
};
const handleOTPSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!otp.trim()) return;
await verifyOTP();
};
const handlePasswordFallback = async (e: React.FormEvent) => {
e.preventDefault();
if (!password.trim()) return;
try {
setIsLoading(true);
setError('');
// Try login first, then signup if user doesn't exist
try {
await signInWithEmail(email, password);
} catch (loginError) {
// If login fails, try creating account
await signUpWithEmail(email, password, email.split('@')[0]);
}
} catch (err) {
console.error('Password auth error:', err);
setError(err instanceof Error ? err.message : 'Authentication failed');
} finally {
setIsLoading(false);
}
};
const handleGoogleAuth = async () => {
try {
setIsLoading(true);
setError('');
await signInWithGoogle();
} catch (err) {
console.error('Google auth error:', err);
setError('Google authentication failed. Please try again.');
} finally {
setIsLoading(false);
}
};
const renderEmailStep = () => (
<div className="w-full max-w-md mx-auto bg-white rounded-xl shadow-lg p-8">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-white text-2xl font-bold">A</span>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">
{inviteCode ? 'Join Organization' : 'Welcome to Auditly'}
</h1>
<p className="text-gray-600">
{inviteCode
? 'Enter your email to join the organization'
: 'Enter your email to get started'
}
</p>
</div>
<form onSubmit={handleEmailSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Email Address
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.66675 5.83325L8.47085 10.5961C9.02182 10.9818 9.29731 11.1746 9.59697 11.2493C9.86166 11.3153 10.1385 11.3153 10.4032 11.2493C10.7029 11.1746 10.9783 10.9818 11.5293 10.5961L18.3334 5.83325M5.66675 16.6666H14.3334C15.7335 16.6666 16.4336 16.6666 16.9684 16.3941C17.4388 16.1544 17.8212 15.772 18.0609 15.3016C18.3334 14.7668 18.3334 14.0667 18.3334 12.6666V7.33325C18.3334 5.93312 18.3334 5.23306 18.0609 4.69828C17.8212 4.22787 17.4388 3.84542 16.9684 3.60574C16.4336 3.33325 15.7335 3.33325 14.3334 3.33325H5.66675C4.26662 3.33325 3.56655 3.33325 3.03177 3.60574C2.56137 3.84542 2.17892 4.22787 1.93923 4.69828C1.66675 5.23306 1.66675 5.93312 1.66675 7.33325V12.6666C1.66675 14.0667 1.66675 14.7668 1.93923 15.3016C2.17892 15.772 2.56137 16.1544 3.03177 16.3941C3.56655 16.6666 4.26662 16.6666 5.66675 16.6666Z" stroke="#718096" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:placeholder-gray-400"
placeholder="Enter your email"
className="w-full pl-12 pr-4 py-3.5 bg-gray-50 border text-gray-700 border-gray-200 rounded-full focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
required
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Password {inviteCode && <span className="text-gray-500 dark:text-gray-400">(create a new password)</span>}
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:placeholder-gray-400"
required
/>
{inviteCode && (
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
Choose a secure password for your new account
</p>
)}
</div>
<Button
type="submit"
className="w-full"
disabled={isLoading}
>
{isLoading ? 'Processing...' : (inviteCode ? 'Create Account & Join Team' : 'Sign In')}
</Button>
</form>
<div className="text-center">
<p className="text-sm text-gray-500 dark:text-gray-400 mb-4">Or continue with</p>
<Button
variant="secondary"
className="w-full"
onClick={handleGoogleLogin}
disabled={isLoading}
>
Sign in with Google
</Button>
</div>
{/* Manual invite code entry - only show if no invite code in URL */}
{!inviteCode && (
<div className="border-t border-[--border-color] pt-6">
<div className="text-center mb-4">
<h3 className="text-sm font-medium text-[--text-primary] mb-2">Employee? Use Your Invite Code</h3>
<p className="text-xs text-[--text-secondary]">
Skip account creation - employees can go directly to their questionnaire
</p>
</div>
<div className="flex space-x-3">
<input
type="text"
placeholder="Enter your invite code"
className="flex-1 px-3 py-2 border border-[--input-border] rounded-lg bg-[--input-bg] text-[--text-primary] placeholder-[--input-placeholder] focus:outline-none focus:ring-2 focus:ring-[--accent] focus:border-[--accent]"
onKeyDown={(e) => {
if (e.key === 'Enter') {
const code = (e.target as HTMLInputElement).value.trim();
if (code) {
window.location.href = `#/invite/${code}`;
} else {
alert('Please enter an invite code');
}
}
}}
/>
<Button
variant="secondary"
onClick={() => {
const input = document.querySelector('input[placeholder="Enter your invite code"]') as HTMLInputElement;
const code = input?.value.trim();
if (code) {
window.location.href = `#/invite/${code}`;
} else {
alert('Please enter an invite code');
}
}}
>
Start Survey
</Button>
</div>
<p className="text-xs text-[--text-secondary] mt-2 text-center">
No account needed - just answer questions and submit
</p>
{error && (
<div className="text-red-600 text-sm bg-red-50 border border-red-200 p-3 rounded-lg">
{error}
</div>
)}
<div className="text-center">
<p className="text-xs text-[--text-secondary]">
{inviteCode ?
'Demo mode: Enter any email and password to create your account.' :
'Demo mode: No Firebase configuration detected.\nUse any email/password to continue.'
}
</p>
<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white py-3.5 rounded-full font-medium transition-all transform hover:scale-[1.02]"
disabled={isLoading || !email.trim()}
>
{isLoading ? 'Sending...' : 'Continue with Email'}
</Button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-200" />
</div>
<div className="relative flex justify-center text-sm">
<span className="px-3 bg-white text-gray-500">or</span>
</div>
</div>
</Card>
<Button
type="button"
variant="secondary"
className="w-full border-gray-200 py-3.5 rounded-full transition-colors"
onClick={handleGoogleAuth}
disabled={isLoading}
>
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" />
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" />
</svg>
Continue with Google
</Button>
<div className="text-center mt-6">
<button
type="button"
onClick={() => setStep('password-fallback')}
className="text-sm text-blue-600 hover:text-blue-800 transition-colors"
>
Use password instead
</button>
</div>
</form>
</div>
);
const renderOTPStep = () => (
<div className="w-full max-w-md mx-auto bg-white rounded-xl shadow-lg p-8">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-gradient-to-br from-green-500 to-emerald-600 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">Check your email</h1>
<p className="text-gray-600">
We sent a verification code to <br />
<strong className="text-gray-900">{email}</strong>
</p>
</div>
<form onSubmit={handleOTPSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2 text-center">
Verification Code
</label>
<input
type="text"
value={otp}
onChange={(e) => setOtp(e.target.value.replace(/\D/g, '').slice(0, 6))}
placeholder="000000"
className="w-full px-4 py-4 bg-gray-50 border border-gray-200 text-gray-700 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent text-center text-3xl tracking-[0.5em] font-mono outline-none transition-all"
maxLength={6}
required
/>
</div>
{demoOTP && (
<div className="bg-gradient-to-r from-yellow-50 to-orange-50 border border-yellow-200 rounded-xl p-4">
<div className="text-yellow-800 text-sm text-center">
<div className="flex items-center justify-center mb-2">
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
<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>
<strong>Demo Mode</strong>
</div>
Your verification code is <strong className="text-2xl font-mono bg-yellow-100 px-2 py-1 rounded">{demoOTP}</strong>
</div>
</div>
)}
{error && (
<div className="text-red-600 text-sm bg-red-50 border border-red-200 p-3 rounded-lg">
{error}
</div>
)}
<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white py-4 rounded-xl font-medium transition-all transform hover:scale-[1.02]"
disabled={isLoading || otp.length !== 6}
>
{isLoading ? 'Verifying...' : 'Verify Code'}
</Button>
<div className="text-center space-y-3">
<button
type="button"
onClick={() => sendOTP(email)}
disabled={resendCooldown > 0 || isLoading}
className="text-sm text-blue-600 hover:text-blue-800 disabled:text-gray-400 transition-colors"
>
{resendCooldown > 0
? `Resend code in ${resendCooldown}s`
: 'Resend code'
}
</button>
<div>
<button
type="button"
onClick={() => { setStep('email'); setError(''); setOtp(''); }}
className="text-sm text-gray-600 hover:text-gray-800 transition-colors"
>
Change email address
</button>
</div>
</div>
</form>
</div>
);
const renderPasswordStep = () => (
<div className="w-full max-w-md mx-auto bg-white rounded-xl shadow-lg p-8">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-600 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">Sign in with password</h1>
<p className="text-gray-600">
Enter your password for <br />
<strong className="text-gray-900">{email}</strong>
</p>
</div>
<form onSubmit={handlePasswordFallback} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Password
</label>
<div className="relative">
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-full focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
required
/>
</div>
</div>
{error && (
<div className="text-red-600 text-sm bg-red-50 border border-red-200 p-3 rounded-lg">
{error}
</div>
)}
<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white py-3.5 rounded-full font-medium transition-all transform hover:scale-[1.02]"
disabled={isLoading || !password.trim()}
>
{isLoading ? 'Signing in...' : 'Sign In'}
</Button>
<div className="text-center">
<button
type="button"
onClick={() => { setStep('email'); setError(''); setPassword(''); }}
className="text-sm text-blue-600 hover:text-blue-800 transition-colors"
>
Back to email verification
</button>
</div>
</form>
</div>
);
if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
</div>
);
}
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 flex items-center justify-center p-4">
{step === 'email' && renderEmailStep()}
{step === 'otp' && renderOTPStep()}
{step === 'password-fallback' && renderPasswordStep()}
</div>
);
};
export default Login;
export default ModernLogin;

90
pages/LoginNew.tsx Normal file
View File

@@ -0,0 +1,90 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
const LoginNew: React.FC = () => {
const [email, setEmail] = useState('');
const [isLoading, setIsLoading] = useState(false);
const { login } = useAuth();
const navigate = useNavigate();
const handleLogin = async () => {
if (!email) return;
setIsLoading(true);
try {
await login(email);
navigate('/company-wiki');
} catch (error) {
console.error('Login failed:', error);
} finally {
setIsLoading(false);
}
};
return (
<div className="w-[1440px] h-[810px] bg-Neutrals-NeutralSlate0 inline-flex justify-start items-end overflow-hidden">
<div className="flex-1 self-stretch px-32 py-48 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-6">
<div className="w-12 h-12 relative bg-Brand-Orange rounded-xl outline outline-2 outline-offset-[-2px] outline-blue-400 overflow-hidden">
<div className="w-12 h-12 left-0 top-0 absolute bg-gradient-to-b from-white/0 to-white/10" />
<div className="left-[12px] top-[9.33px] absolute">
<svg width="24" height="30" viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M2.57425 17.8128C3.11852 18.3639 3.11851 19.2575 2.57423 19.8087L2.54635 19.8369C2.00207 20.3881 1.11963 20.3881 0.575357 19.8369C0.0310869 19.2857 0.0310953 18.3921 0.575376 17.841L0.603251 17.8128C1.14753 17.2616 2.02998 17.2616 2.57425 17.8128Z" fill="url(#paint0_linear_710_14140)" />
<path opacity="0.7" fillRule="evenodd" clipRule="evenodd" d="M9.12599 18.2379C9.66928 18.7901 9.66769 19.6837 9.12243 20.2338L5.26187 24.1291C4.71661 24.6792 3.83416 24.6776 3.29087 24.1255C2.74758 23.5733 2.74918 22.6797 3.29444 22.1296L7.155 18.2343C7.70026 17.6842 8.5827 17.6858 9.12599 18.2379Z" fill="url(#paint1_linear_710_14140)" />
<defs>
<linearGradient id="paint0_linear_710_14140" x1="1.5748" y1="17.3994" x2="1.5748" y2="20.2503" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
<linearGradient id="paint1_linear_710_14140" x1="6.20843" y1="17.8228" x2="6.20843" y2="24.5406" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
</defs>
</svg>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="self-stretch justify-start text-Neutrals-NeutralSlate950 text-2xl font-semibold font-['Inter'] leading-8">Welcome to Auditly</div>
<div className="self-stretch justify-start text-Neutrals-NeutralSlate500 text-base font-normal font-['Inter'] leading-normal">Sign in to your account to continue</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">Email Address</div>
<div className="justify-start text-Brand-Orange text-sm font-medium font-['Inter'] leading-tight">*</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="flex-1 bg-transparent text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight placeholder:text-Neutrals-NeutralSlate500 outline-none"
placeholder="Enter your email address"
onKeyPress={(e) => e.key === 'Enter' && handleLogin()}
/>
</div>
</div>
</div>
<button
onClick={handleLogin}
disabled={!email || isLoading}
className="self-stretch px-6 py-3.5 bg-Brand-Orange rounded-[999px] inline-flex justify-center items-center gap-2 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="justify-center text-Neutrals-NeutralSlate0 text-base font-medium font-['Inter'] leading-normal">
{isLoading ? 'Signing in...' : 'Sign In'}
</div>
</button>
<div className="self-stretch text-center text-Neutrals-NeutralSlate500 text-sm font-normal font-['Inter'] leading-tight">
Don't have an account? Contact your administrator.
</div>
</div>
</div>
</div>
</div>
);
};
export default LoginNew;

View File

@@ -1,403 +0,0 @@
import React, { useState, useEffect } from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import { Button } from '../components/UiKit';
type AuthStep = 'email' | 'otp' | 'password-fallback';
const ModernLogin: React.FC = () => {
const navigate = useNavigate();
const location = useLocation();
const { inviteCode: routeInviteCode } = useParams<{ inviteCode: string }>();
// Auth state
const { signInWithGoogle, signInWithEmail, signUpWithEmail, user, loading, sendOTP: authSendOTP, verifyOTP: authVerifyOTP } = useAuth();
// Form state
const [step, setStep] = useState<AuthStep>('email');
const [email, setEmail] = useState('');
const [otp, setOtp] = useState('');
const [password, setPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [inviteCode, setInviteCode] = useState<string | null>(null);
const [resendCooldown, setResendCooldown] = useState(0);
const [demoOTP, setDemoOTP] = useState<string | null>(null);
// Extract invite code from URL
useEffect(() => {
if (routeInviteCode) {
setInviteCode(routeInviteCode);
} else {
const hashSearch = location.hash.includes('?') ? location.hash.split('?')[1] : '';
const searchParams = new URLSearchParams(hashSearch);
const queryInvite = searchParams.get('invite');
if (queryInvite) {
setInviteCode(queryInvite);
}
}
}, [routeInviteCode, location]);
// Handle successful authentication
useEffect(() => {
if (user && !loading) {
if (inviteCode) {
navigate(`/org-selection?invite=${inviteCode}`, { replace: true });
} else {
navigate('/org-selection', { replace: true });
}
}
}, [user, loading, navigate, inviteCode]);
// Resend cooldown timer
useEffect(() => {
if (resendCooldown > 0) {
const timer = setTimeout(() => setResendCooldown(resendCooldown - 1), 1000);
return () => clearTimeout(timer);
}
}, [resendCooldown]);
const sendOTP = async (emailAddress: string) => {
try {
setIsLoading(true);
setError('');
setDemoOTP(null);
// Call auth context method
const response = await authSendOTP(emailAddress, inviteCode || undefined);
// If OTP is returned in response (demo mode), display it
if (response.otp) {
setDemoOTP(response.otp);
}
setStep('otp');
setResendCooldown(60); // 60 second cooldown
} catch (err) {
console.error('OTP send error:', err);
setError(err instanceof Error ? err.message : 'Failed to send verification code. Please try again.');
} finally {
setIsLoading(false);
}
}; const verifyOTP = async () => {
try {
setIsLoading(true);
setError('');
// Call auth context method
await authVerifyOTP(email, otp, inviteCode || undefined);
// Success - user will be set in auth context and useEffect will handle navigation
} catch (err) {
console.error('OTP verification error:', err);
setError(err instanceof Error ? err.message : 'Invalid verification code. Please try again.');
} finally {
setIsLoading(false);
}
};
const handleEmailSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email.trim()) return;
await sendOTP(email);
};
const handleOTPSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!otp.trim()) return;
await verifyOTP();
};
const handlePasswordFallback = async (e: React.FormEvent) => {
e.preventDefault();
if (!password.trim()) return;
try {
setIsLoading(true);
setError('');
// Try login first, then signup if user doesn't exist
try {
await signInWithEmail(email, password);
} catch (loginError) {
// If login fails, try creating account
await signUpWithEmail(email, password, email.split('@')[0]);
}
} catch (err) {
console.error('Password auth error:', err);
setError(err instanceof Error ? err.message : 'Authentication failed');
} finally {
setIsLoading(false);
}
};
const handleGoogleAuth = async () => {
try {
setIsLoading(true);
setError('');
await signInWithGoogle();
} catch (err) {
console.error('Google auth error:', err);
setError('Google authentication failed. Please try again.');
} finally {
setIsLoading(false);
}
};
const renderEmailStep = () => (
<div className="w-full max-w-md mx-auto bg-white rounded-xl shadow-lg p-8">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-white text-2xl font-bold">A</span>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">
{inviteCode ? 'Join Organization' : 'Welcome to Auditly'}
</h1>
<p className="text-gray-600">
{inviteCode
? 'Enter your email to join the organization'
: 'Enter your email to get started'
}
</p>
</div>
<form onSubmit={handleEmailSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Email Address
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.66675 5.83325L8.47085 10.5961C9.02182 10.9818 9.29731 11.1746 9.59697 11.2493C9.86166 11.3153 10.1385 11.3153 10.4032 11.2493C10.7029 11.1746 10.9783 10.9818 11.5293 10.5961L18.3334 5.83325M5.66675 16.6666H14.3334C15.7335 16.6666 16.4336 16.6666 16.9684 16.3941C17.4388 16.1544 17.8212 15.772 18.0609 15.3016C18.3334 14.7668 18.3334 14.0667 18.3334 12.6666V7.33325C18.3334 5.93312 18.3334 5.23306 18.0609 4.69828C17.8212 4.22787 17.4388 3.84542 16.9684 3.60574C16.4336 3.33325 15.7335 3.33325 14.3334 3.33325H5.66675C4.26662 3.33325 3.56655 3.33325 3.03177 3.60574C2.56137 3.84542 2.17892 4.22787 1.93923 4.69828C1.66675 5.23306 1.66675 5.93312 1.66675 7.33325V12.6666C1.66675 14.0667 1.66675 14.7668 1.93923 15.3016C2.17892 15.772 2.56137 16.1544 3.03177 16.3941C3.56655 16.6666 4.26662 16.6666 5.66675 16.6666Z" stroke="#718096" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
className="w-full pl-12 pr-4 py-3.5 bg-gray-50 border text-gray-700 border-gray-200 rounded-full focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
required
/>
</div>
</div>
{error && (
<div className="text-red-600 text-sm bg-red-50 border border-red-200 p-3 rounded-lg">
{error}
</div>
)}
<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white py-3.5 rounded-full font-medium transition-all transform hover:scale-[1.02]"
disabled={isLoading || !email.trim()}
>
{isLoading ? 'Sending...' : 'Continue with Email'}
</Button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-200" />
</div>
<div className="relative flex justify-center text-sm">
<span className="px-3 bg-white text-gray-500">or</span>
</div>
</div>
<Button
type="button"
variant="secondary"
className="w-full border-gray-200 py-3.5 rounded-full transition-colors"
onClick={handleGoogleAuth}
disabled={isLoading}
>
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" />
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" />
</svg>
Continue with Google
</Button>
<div className="text-center mt-6">
<button
type="button"
onClick={() => setStep('password-fallback')}
className="text-sm text-blue-600 hover:text-blue-800 transition-colors"
>
Use password instead
</button>
</div>
</form>
</div>
);
const renderOTPStep = () => (
<div className="w-full max-w-md mx-auto bg-white rounded-xl shadow-lg p-8">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-gradient-to-br from-green-500 to-emerald-600 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">Check your email</h1>
<p className="text-gray-600">
We sent a verification code to <br />
<strong className="text-gray-900">{email}</strong>
</p>
</div>
<form onSubmit={handleOTPSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2 text-center">
Verification Code
</label>
<input
type="text"
value={otp}
onChange={(e) => setOtp(e.target.value.replace(/\D/g, '').slice(0, 6))}
placeholder="000000"
className="w-full px-4 py-4 bg-gray-50 border border-gray-200 text-gray-700 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent text-center text-3xl tracking-[0.5em] font-mono outline-none transition-all"
maxLength={6}
required
/>
</div>
{demoOTP && (
<div className="bg-gradient-to-r from-yellow-50 to-orange-50 border border-yellow-200 rounded-xl p-4">
<div className="text-yellow-800 text-sm text-center">
<div className="flex items-center justify-center mb-2">
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
<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>
<strong>Demo Mode</strong>
</div>
Your verification code is <strong className="text-2xl font-mono bg-yellow-100 px-2 py-1 rounded">{demoOTP}</strong>
</div>
</div>
)}
{error && (
<div className="text-red-600 text-sm bg-red-50 border border-red-200 p-3 rounded-lg">
{error}
</div>
)}
<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white py-4 rounded-xl font-medium transition-all transform hover:scale-[1.02]"
disabled={isLoading || otp.length !== 6}
>
{isLoading ? 'Verifying...' : 'Verify Code'}
</Button>
<div className="text-center space-y-3">
<button
type="button"
onClick={() => sendOTP(email)}
disabled={resendCooldown > 0 || isLoading}
className="text-sm text-blue-600 hover:text-blue-800 disabled:text-gray-400 transition-colors"
>
{resendCooldown > 0
? `Resend code in ${resendCooldown}s`
: 'Resend code'
}
</button>
<div>
<button
type="button"
onClick={() => { setStep('email'); setError(''); setOtp(''); }}
className="text-sm text-gray-600 hover:text-gray-800 transition-colors"
>
Change email address
</button>
</div>
</div>
</form>
</div>
);
const renderPasswordStep = () => (
<div className="w-full max-w-md mx-auto bg-white rounded-xl shadow-lg p-8">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-600 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">Sign in with password</h1>
<p className="text-gray-600">
Enter your password for <br />
<strong className="text-gray-900">{email}</strong>
</p>
</div>
<form onSubmit={handlePasswordFallback} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Password
</label>
<div className="relative">
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-full focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
required
/>
</div>
</div>
{error && (
<div className="text-red-600 text-sm bg-red-50 border border-red-200 p-3 rounded-lg">
{error}
</div>
)}
<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white py-3.5 rounded-full font-medium transition-all transform hover:scale-[1.02]"
disabled={isLoading || !password.trim()}
>
{isLoading ? 'Signing in...' : 'Sign In'}
</Button>
<div className="text-center">
<button
type="button"
onClick={() => { setStep('email'); setError(''); setPassword(''); }}
className="text-sm text-blue-600 hover:text-blue-800 transition-colors"
>
Back to email verification
</button>
</div>
</form>
</div>
);
if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
</div>
);
}
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 flex items-center justify-center p-4">
{step === 'email' && renderEmailStep()}
{step === 'otp' && renderOTPStep()}
{step === 'password-fallback' && renderPasswordStep()}
</div>
);
};
export default ModernLogin;

122
pages/OTPVerification.tsx Normal file
View File

@@ -0,0 +1,122 @@
import React, { useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
const OTPVerification: React.FC = () => {
const [otp, setOtp] = useState(['', '', '', '', '', '']);
const [isLoading, setIsLoading] = useState(false);
const { verifyOTP } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const email = location.state?.email || '';
const handleOtpChange = (index: number, value: string) => {
if (value.length <= 1) {
const newOtp = [...otp];
newOtp[index] = value;
setOtp(newOtp);
// Auto-focus next input
if (value && index < 5) {
const nextInput = document.getElementById(`otp-${index + 1}`);
nextInput?.focus();
}
}
};
const handleKeyDown = (index: number, e: React.KeyboardEvent) => {
if (e.key === 'Backspace' && !otp[index] && index > 0) {
const prevInput = document.getElementById(`otp-${index - 1}`);
prevInput?.focus();
}
};
const handleVerify = async () => {
const otpCode = otp.join('');
if (otpCode.length !== 6) return;
setIsLoading(true);
try {
await verifyOTP(email, otpCode);
navigate('/company-wiki');
} catch (error) {
console.error('OTP verification failed:', error);
// Reset OTP on error
setOtp(['', '', '', '', '', '']);
document.getElementById('otp-0')?.focus();
} finally {
setIsLoading(false);
}
};
return (
<div className="w-[1440px] h-[810px] bg-Neutrals-NeutralSlate0 inline-flex justify-start items-end overflow-hidden">
<div className="flex-1 self-stretch px-32 py-48 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-6">
<div className="w-12 h-12 relative bg-Brand-Orange rounded-xl outline outline-2 outline-offset-[-2px] outline-blue-400 overflow-hidden">
<div className="w-12 h-12 left-0 top-0 absolute bg-gradient-to-b from-white/0 to-white/10" />
<div className="left-[12px] top-[9.33px] absolute">
<svg width="24" height="30" viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M2.57425 17.8128C3.11852 18.3639 3.11851 19.2575 2.57423 19.8087L2.54635 19.8369C2.00207 20.3881 1.11963 20.3881 0.575357 19.8369C0.0310869 19.2857 0.0310953 18.3921 0.575376 17.841L0.603251 17.8128C1.14753 17.2616 2.02998 17.2616 2.57425 17.8128Z" fill="url(#paint0_linear_710_14140)" />
<path opacity="0.7" fillRule="evenodd" clipRule="evenodd" d="M9.12599 18.2379C9.66928 18.7901 9.66769 19.6837 9.12243 20.2338L5.26187 24.1291C4.71661 24.6792 3.83416 24.6776 3.29087 24.1255C2.74758 23.5733 2.74918 22.6797 3.29444 22.1296L7.155 18.2343C7.70026 17.6842 8.5827 17.6858 9.12599 18.2379Z" fill="url(#paint1_linear_710_14140)" />
<defs>
<linearGradient id="paint0_linear_710_14140" x1="1.5748" y1="17.3994" x2="1.5748" y2="20.2503" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
<linearGradient id="paint1_linear_710_14140" x1="6.20843" y1="17.8228" x2="6.20843" y2="24.5406" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
</defs>
</svg>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="self-stretch justify-start text-Neutrals-NeutralSlate950 text-2xl font-semibold font-['Inter'] leading-8">Verify your email</div>
<div className="self-stretch justify-start text-Neutrals-NeutralSlate500 text-base font-normal font-['Inter'] leading-normal">
Enter the 6-digit code sent to {email}
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">Verification Code</div>
<div className="justify-start text-Brand-Orange text-sm font-medium font-['Inter'] leading-tight">*</div>
</div>
<div className="self-stretch flex justify-center items-center gap-3">
{otp.map((digit, index) => (
<input
key={index}
id={`otp-${index}`}
type="text"
value={digit}
onChange={(e) => handleOtpChange(index, e.target.value)}
onKeyDown={(e) => handleKeyDown(index, e)}
className="w-12 h-12 bg-Neutrals-NeutralSlate100 rounded-xl text-center text-Neutrals-NeutralSlate950 text-lg font-semibold font-['Inter'] outline-none focus:bg-Neutrals-NeutralSlate200 focus:outline-2 focus:outline-Brand-Orange"
maxLength={1}
/>
))}
</div>
</div>
<button
onClick={handleVerify}
disabled={otp.join('').length !== 6 || isLoading}
className="self-stretch px-6 py-3.5 bg-Brand-Orange rounded-[999px] inline-flex justify-center items-center gap-2 overflow-hidden disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="justify-center text-Neutrals-NeutralSlate0 text-base font-medium font-['Inter'] leading-normal">
{isLoading ? 'Verifying...' : 'Verify Code'}
</div>
</button>
<div className="self-stretch text-center text-Neutrals-NeutralSlate500 text-sm font-normal font-['Inter'] leading-tight">
Didn't receive the code? <button className="text-Brand-Orange font-medium">Resend</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default OTPVerification;

View File

@@ -1,47 +1,41 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useOrg } from '../contexts/OrgContext';
import { Card, Button } from '../components/UiKit';
import { FigmaProgress } from '../components/figma/FigmaProgress';
import { FigmaInput } from '../components/figma/FigmaInput';
import { FigmaAlert } from '../components/figma/FigmaAlert';
import { EnhancedFigmaQuestion, FigmaQuestionCard, EnhancedFigmaInput } from '../components/figma/EnhancedFigmaQuestion';
import { FigmaInput, FigmaSelect } from '../components/figma/FigmaInput';
import { FigmaMultipleChoice } from '../components/figma/FigmaMultipleChoice';
interface OnboardingData {
// Step 1: Company Basics
// Step 0: Company Details
companyName: string;
industry: string;
size: string;
description: string;
yourName: string;
// Step 2: Mission & Vision
// Step 1: Company Size
companySize: string;
// Step 2: Mission
mission: string;
// Later steps
industry: string;
description: string;
vision: string;
values: string[];
// Step 3: Company Evolution & History
foundingYear: string;
evolution: string;
majorMilestones: string;
// Step 4: Competitive Landscape
advantages: string;
vulnerabilities: string;
competitors: string;
marketPosition: string;
// Step 5: Current Challenges & Goals
currentChallenges: string[];
shortTermGoals: string;
longTermGoals: string;
keyMetrics: string;
// Step 6: Team & Culture
cultureDescription: string;
workEnvironment: string;
leadershipStyle: string;
communicationStyle: string;
// Step 7: Final Review
additionalContext: string;
}
@@ -59,10 +53,11 @@ const Onboarding: React.FC = () => {
const [isGeneratingReport, setIsGeneratingReport] = useState(false);
const [formData, setFormData] = useState<OnboardingData>({
companyName: org?.name || '',
industry: '',
size: '',
description: '',
yourName: '',
companySize: '',
mission: '',
industry: '',
description: '',
vision: '',
values: [],
foundingYear: '',
@@ -85,20 +80,28 @@ const Onboarding: React.FC = () => {
const steps = [
{
title: 'Company Basics',
description: 'Tell us about your company fundamentals'
title: 'Company Details',
description: 'Basic information about your company'
},
{
title: 'Mission & Vision',
description: 'Define your purpose and direction'
title: 'Company Size',
description: 'How many people work at your company'
},
{
title: 'Evolution & History',
description: 'Share your company\'s journey'
title: 'Mission Statement',
description: 'What is the mission of your company'
},
{
title: 'Competitive Position',
description: 'Understand your market position'
title: 'Vision & Values',
description: 'Your company\'s vision and core values'
},
{
title: 'Company History',
description: 'How your company has evolved'
},
{
title: 'Market Position',
description: 'Your competitive landscape'
},
{
title: 'Goals & Challenges',
@@ -106,16 +109,11 @@ const Onboarding: React.FC = () => {
},
{
title: 'Team & Culture',
description: 'Describe your work environment'
},
{
title: 'Final Review',
description: 'Complete your company profile'
description: 'Your work environment and culture'
}
];
const handleNext = async () => {
// Prevent re-entry during generation
if (isGeneratingReport) return;
if (step < steps.length - 1) {
@@ -125,12 +123,11 @@ const Onboarding: React.FC = () => {
// Final step: persist org & generate report
setIsGeneratingReport(true);
console.log('Starting onboarding completion...', { step });
try {
const newOrgData = {
name: formData.companyName,
industry: formData.industry,
size: formData.size,
size: formData.companySize,
description: formData.description,
mission: formData.mission,
vision: formData.vision,
@@ -154,24 +151,14 @@ const Onboarding: React.FC = () => {
onboardingCompleted: true
};
console.log('Saving org data...', newOrgData);
await upsertOrg(newOrgData);
console.log('Org data saved successfully');
console.log('Generating company wiki...');
await generateCompanyWiki({ ...newOrgData, orgId: org!.orgId });
console.log('Company wiki generated successfully');
// Small delay to ensure states are updated, then redirect
console.log('Redirecting to reports...');
setTimeout(() => {
console.log('Navigation executing...');
navigate('/reports', { replace: true });
console.log('Navigation called successfully');
}, 100);
} catch (error) {
console.error('Error completing onboarding:', error);
// Show detailed error to user for debugging
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
alert(`There was an error completing the setup: ${errorMessage}. Please check the console for more details and try again.`);
} finally {
@@ -183,462 +170,160 @@ const Onboarding: React.FC = () => {
if (step > 0) setStep(step - 1);
};
const addToArray = (field: 'values' | 'currentChallenges', value: string) => {
if (value.trim()) {
setFormData(prev => ({
...prev,
[field]: [...prev[field], value.trim()]
}));
const updateFormData = (field: keyof OnboardingData, value: string) => {
setFormData(prev => ({ ...prev, [field]: value }));
};
const canProceed = () => {
switch (step) {
case 0: // Company Details
return formData.companyName.trim().length > 0 && formData.yourName.trim().length > 0;
case 1: // Company Size
return formData.companySize.length > 0;
case 2: // Mission
return formData.mission.trim().length > 0;
case 3: // Vision & Values
return formData.vision.trim().length > 0;
case 4: // History
return formData.evolution.trim().length > 0;
case 5: // Market Position
return formData.advantages.trim().length > 0;
case 6: // Goals
return formData.shortTermGoals.trim().length > 0;
case 7: // Culture
return formData.cultureDescription.trim().length > 0;
default:
return false;
}
};
const removeFromArray = (field: 'values' | 'currentChallenges', index: number) => {
setFormData(prev => ({
...prev,
[field]: prev[field].filter((_, i) => i !== index)
}));
};
const renderStep = () => {
const renderStepContent = () => {
switch (step) {
case 0:
case 0: // Company Details
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Company Name *
</label>
<input
type="text"
value={formData.companyName}
onChange={(e) => setFormData(prev => ({ ...prev, companyName: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Enter your company name"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Industry *
</label>
<select
value={formData.industry}
onChange={(e) => setFormData(prev => ({ ...prev, industry: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Select industry</option>
<option value="Technology">Technology</option>
<option value="Healthcare">Healthcare</option>
<option value="Finance">Finance</option>
<option value="Manufacturing">Manufacturing</option>
<option value="Retail">Retail</option>
<option value="Professional Services">Professional Services</option>
<option value="Education">Education</option>
<option value="Media & Entertainment">Media & Entertainment</option>
<option value="Other">Other</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Company Size *
</label>
<select
value={formData.size}
onChange={(e) => setFormData(prev => ({ ...prev, size: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Select size</option>
<option value="1-10">1-10 employees</option>
<option value="11-50">11-50 employees</option>
<option value="51-200">51-200 employees</option>
<option value="201-1000">201-1000 employees</option>
<option value="1000+">1000+ employees</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Company Description *
</label>
<textarea
value={formData.description}
onChange={(e) => setFormData(prev => ({ ...prev, description: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="Describe what your company does, its products/services, and target market"
/>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-6">
<FigmaInput
label="Your Name"
placeholder="John Doe"
value={formData.yourName}
onChange={(e) => updateFormData('yourName', e.target.value)}
required
/>
<FigmaInput
label="Company Name"
placeholder="Doe Enterprises"
value={formData.companyName}
onChange={(e) => updateFormData('companyName', e.target.value)}
required
/>
</div>
);
case 1:
case 1: // Company Size
return (
<FigmaMultipleChoice
options={['1-10', '10-25', '25-50', '50-100', '100+']}
selectedValue={formData.companySize}
onSelect={(value) => updateFormData('companySize', value)}
/>
);
case 2: // Mission
return (
<FigmaQuestionCard
question="What is the mission of your company?"
description="Description about the question"
>
<EnhancedFigmaInput
placeholder="Type your answer...."
value={formData.mission}
onChange={(value) => updateFormData('mission', value)}
multiline
rows={6}
/>
</FigmaQuestionCard>
);
case 3: // Vision & Values
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Mission Statement *
</label>
<textarea
value={formData.mission}
onChange={(e) => setFormData(prev => ({ ...prev, mission: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="What is your company's purpose? Why does it exist?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Vision Statement *
</label>
<textarea
<FigmaQuestionCard
question="What is your company's vision?"
description="Where do you see your company in the future?"
>
<EnhancedFigmaInput
placeholder="Type your answer...."
value={formData.vision}
onChange={(e) => setFormData(prev => ({ ...prev, vision: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="Where do you see your company in the future? What impact do you want to make?"
onChange={(value) => updateFormData('vision', value)}
multiline
rows={4}
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Core Values
</label>
<div className="space-y-2">
{formData.values.map((value, index) => (
<div key={index} className="flex items-center space-x-2">
<span className="flex-1 px-3 py-2 bg-[--background-tertiary] rounded-lg text-[--text-primary]">
{value}
</span>
<Button
size="sm"
variant="danger"
onClick={() => removeFromArray('values', index)}
>
Remove
</Button>
</div>
))}
<div className="flex space-x-2">
<input
type="text"
className="flex-1 px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Add a core value"
onKeyPress={(e) => {
if (e.key === 'Enter') {
addToArray('values', e.currentTarget.value);
e.currentTarget.value = '';
}
}}
/>
<Button
size="sm"
onClick={(e) => {
const input = (e.target as HTMLElement).parentElement?.querySelector('input');
if (input) {
addToArray('values', input.value);
input.value = '';
}
}}
>
Add
</Button>
</div>
</div>
</div>
</FigmaQuestionCard>
</div>
);
case 2:
case 4: // History
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Founding Year
</label>
<input
type="text"
value={formData.foundingYear}
onChange={(e) => setFormData(prev => ({ ...prev, foundingYear: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="When was your company founded?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Company Evolution *
</label>
<textarea
value={formData.evolution}
onChange={(e) => setFormData(prev => ({ ...prev, evolution: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="How has your company evolved since its founding? What major changes or pivots have occurred?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Major Milestones
</label>
<textarea
value={formData.majorMilestones}
onChange={(e) => setFormData(prev => ({ ...prev, majorMilestones: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="List key achievements, product launches, funding rounds, or other significant milestones"
/>
</div>
</div>
<FigmaQuestionCard
question="How has your company evolved?"
description="Tell us about your company's journey and evolution"
>
<EnhancedFigmaInput
placeholder="Type your answer...."
value={formData.evolution}
onChange={(value) => updateFormData('evolution', value)}
multiline
rows={6}
/>
</FigmaQuestionCard>
);
case 3:
case 5: // Market Position
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Competitive Advantages *
</label>
<textarea
value={formData.advantages}
onChange={(e) => setFormData(prev => ({ ...prev, advantages: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="What gives your company a competitive edge? What are your unique strengths?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Vulnerabilities & Weaknesses *
</label>
<textarea
value={formData.vulnerabilities}
onChange={(e) => setFormData(prev => ({ ...prev, vulnerabilities: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="What are your company's current weaknesses or areas of vulnerability?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Key Competitors
</label>
<textarea
value={formData.competitors}
onChange={(e) => setFormData(prev => ({ ...prev, competitors: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="Who are your main competitors? How do you differentiate from them?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Market Position
</label>
<textarea
value={formData.marketPosition}
onChange={(e) => setFormData(prev => ({ ...prev, marketPosition: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="How do you position yourself in the market? What's your market share or standing?"
/>
</div>
</div>
<FigmaQuestionCard
question="What are your competitive advantages?"
description="What gives your company a competitive edge?"
>
<EnhancedFigmaInput
placeholder="Type your answer...."
value={formData.advantages}
onChange={(value) => updateFormData('advantages', value)}
multiline
rows={6}
/>
</FigmaQuestionCard>
);
case 4:
case 6: // Goals
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Current Challenges
</label>
<div className="space-y-2">
{formData.currentChallenges.map((challenge, index) => (
<div key={index} className="flex items-center space-x-2">
<span className="flex-1 px-3 py-2 bg-[--background-tertiary] rounded-lg text-[--text-primary]">
{challenge}
</span>
<Button
size="sm"
variant="danger"
onClick={() => removeFromArray('currentChallenges', index)}
>
Remove
</Button>
</div>
))}
<div className="flex space-x-2">
<input
type="text"
className="flex-1 px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Add a current challenge"
onKeyPress={(e) => {
if (e.key === 'Enter') {
addToArray('currentChallenges', e.currentTarget.value);
e.currentTarget.value = '';
}
}}
/>
<Button
size="sm"
onClick={(e) => {
const input = (e.target as HTMLElement).parentElement?.querySelector('input');
if (input) {
addToArray('currentChallenges', input.value);
input.value = '';
}
}}
>
Add
</Button>
</div>
</div>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Short-term Goals (6-12 months) *
</label>
<textarea
value={formData.shortTermGoals}
onChange={(e) => setFormData(prev => ({ ...prev, shortTermGoals: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="What are your immediate priorities and goals for the next 6-12 months?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Long-term Goals (1-3 years) *
</label>
<textarea
value={formData.longTermGoals}
onChange={(e) => setFormData(prev => ({ ...prev, longTermGoals: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="What are your strategic objectives for the next 1-3 years?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Key Metrics & Success Indicators
</label>
<textarea
value={formData.keyMetrics}
onChange={(e) => setFormData(prev => ({ ...prev, keyMetrics: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="How do you measure success? What are your key performance indicators?"
/>
</div>
</div>
<FigmaQuestionCard
question="What are your short-term goals?"
description="What are your priorities for the next 6-12 months?"
>
<EnhancedFigmaInput
placeholder="Type your answer...."
value={formData.shortTermGoals}
onChange={(value) => updateFormData('shortTermGoals', value)}
multiline
rows={6}
/>
</FigmaQuestionCard>
);
case 5:
case 7: // Culture
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Company Culture *
</label>
<textarea
value={formData.cultureDescription}
onChange={(e) => setFormData(prev => ({ ...prev, cultureDescription: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="Describe your company culture. What's it like to work at your company?"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Work Environment *
</label>
<select
value={formData.workEnvironment}
onChange={(e) => setFormData(prev => ({ ...prev, workEnvironment: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Select work environment</option>
<option value="Remote">Fully Remote</option>
<option value="Hybrid">Hybrid (Remote + Office)</option>
<option value="In-office">In-office</option>
<option value="Flexible">Flexible/Varies by role</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Leadership Style *
</label>
<textarea
value={formData.leadershipStyle}
onChange={(e) => setFormData(prev => ({ ...prev, leadershipStyle: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="Describe the leadership approach and management style in your organization"
/>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Communication Style *
</label>
<textarea
value={formData.communicationStyle}
onChange={(e) => setFormData(prev => ({ ...prev, communicationStyle: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="How does your team communicate? What tools and processes do you use?"
/>
</div>
</div>
);
case 6:
return (
<div className="space-y-6">
<div className="text-center mb-6">
<div className="text-4xl mb-4">📋</div>
<h3 className="text-xl font-semibold text-[--text-primary] mb-2">
Review Your Information
</h3>
<p className="text-[--text-secondary]">
Please review the information below and add any additional context
</p>
</div>
<div className="bg-[--background-tertiary] p-4 rounded-lg space-y-3">
<div><strong>Company:</strong> {formData.companyName}</div>
<div><strong>Industry:</strong> {formData.industry}</div>
<div><strong>Size:</strong> {formData.size}</div>
<div><strong>Mission:</strong> {formData.mission.substring(0, 100)}{formData.mission.length > 100 ? '...' : ''}</div>
</div>
<div>
<label className="block text-sm font-medium text-[--text-primary] mb-2">
Additional Context
</label>
<textarea
value={formData.additionalContext}
onChange={(e) => setFormData(prev => ({ ...prev, additionalContext: e.target.value }))}
className="w-full px-3 py-2 border border-[--border-color] rounded-lg bg-[--background-secondary] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="Is there anything else important about your company that Auditly should know to provide better insights?"
/>
</div>
<div className="text-center pt-4">
<div className="text-4xl mb-4">🎉</div>
<h3 className="text-xl font-semibold text-[--text-primary]">
Ready to Complete Setup!
</h3>
<p className="text-[--text-secondary]">
{isGeneratingReport
? 'Generating your personalized company insights...'
: 'Once you complete this step, you\'ll have access to all Auditly features and your personalized company wiki will be generated.'
}
</p>
{isGeneratingReport && (
<div className="mt-4 flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
<span className="ml-3 text-[--text-secondary]">Creating your company profile...</span>
</div>
)}
</div>
</div>
<FigmaQuestionCard
question="Describe your company culture"
description="What's it like to work at your company?"
>
<EnhancedFigmaInput
placeholder="Type your answer...."
value={formData.cultureDescription}
onChange={(value) => updateFormData('cultureDescription', value)}
multiline
rows={6}
/>
</FigmaQuestionCard>
);
default:
@@ -646,79 +331,43 @@ const Onboarding: React.FC = () => {
}
};
const canProceed = () => {
// Question text for each step
const getQuestionText = () => {
switch (step) {
case 0:
return formData.companyName.trim().length > 0 && formData.industry && formData.size && formData.description.trim().length > 0;
case 1:
return formData.mission.trim().length > 0 && formData.vision.trim().length > 0;
case 2:
return formData.evolution.trim().length > 0;
case 3:
return formData.advantages.trim().length > 0 && formData.vulnerabilities.trim().length > 0;
case 4:
return formData.shortTermGoals.trim().length > 0 && formData.longTermGoals.trim().length > 0;
case 5:
return formData.cultureDescription.trim().length > 0 && formData.workEnvironment && formData.leadershipStyle.trim().length > 0 && formData.communicationStyle.trim().length > 0;
case 6:
return true;
default:
return false;
case 0: return 'Company Details';
case 1: return `How many people work at ${formData.companyName || '[Company Name]'}?`;
case 2: return 'What is the mission of your company?';
case 3: return 'What is your company\'s vision?';
case 4: return 'How has your company evolved?';
case 5: return 'What are your competitive advantages?';
case 6: return 'What are your short-term goals?';
case 7: return 'Describe your company culture';
default: return 'Onboarding';
}
};
return (
<div className="min-h-screen bg-[--background-primary] flex items-center justify-center p-4">
<div className="max-w-4xl w-full">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-[--text-primary] mb-2">
Welcome to Auditly
</h1>
<p className="text-[--text-secondary]">
Let's build a comprehensive profile of your organization to provide the best insights
</p>
</div>
{/* Progress indicator */}
<div className="mb-8">
<FigmaProgress
currentStep={step + 1}
steps={steps.map((s, i) => ({ number: i + 1, title: s.title }))}
/>
</div>
<Card className="max-w-none">
<div className="mb-6">
<h2 className="text-xl font-semibold text-[--text-primary] mb-2">
{steps[step].title}
</h2>
<p className="text-[--text-secondary]">
{steps[step].description}
</p>
</div>
{renderStep()}
<div className="flex justify-between mt-8">
<Button
variant="secondary"
onClick={handleBack}
disabled={step === 0}
>
Back
</Button>
<Button
onClick={handleNext}
disabled={!canProceed() || isGeneratingReport}
>
{isGeneratingReport
? 'Generating Wiki...'
: step === steps.length - 1 ? 'Complete Setup & Generate Wiki' : 'Next'
}
</Button>
</div>
</Card>
</div>
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] flex items-center justify-center">
<EnhancedFigmaQuestion
question={getQuestionText()}
currentStep={step + 1}
totalSteps={steps.length}
stepTitle={steps[step].title}
onBack={handleBack}
onNext={handleNext}
nextDisabled={!canProceed() || isGeneratingReport}
backDisabled={step === 0}
showBackButton={step > 0}
nextText={
isGeneratingReport
? 'Generating...'
: step === steps.length - 1
? 'Complete Setup'
: 'Next'
}
>
{renderStepContent()}
</EnhancedFigmaQuestion>
</div>
);
};

304
pages/SettingsNew.tsx Normal file
View File

@@ -0,0 +1,304 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import Sidebar from '../components/figma/Sidebar';
interface UserProfile {
fullName: string;
email: string;
profilePicture?: string;
}
type ThemeMode = 'system' | 'light' | 'dark';
const SettingsNew: React.FC = () => {
const { user } = useAuth();
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState<'general' | 'billing'>('general');
const [userProfile, setUserProfile] = useState<UserProfile>({
fullName: 'John Doe',
email: 'Johndoe1234@gmail.com'
});
const [selectedTheme, setSelectedTheme] = useState<ThemeMode>('light');
const handleProfileUpdate = (field: keyof UserProfile, value: string) => {
setUserProfile(prev => ({
...prev,
[field]: value
}));
};
const handlePhotoUpload = () => {
// In a real app, this would open a file picker
alert('Photo upload functionality would be implemented here');
};
const handleSaveChanges = () => {
// In a real app, this would save to backend
alert('Settings saved successfully!');
};
const handleReset = () => {
setUserProfile({
fullName: 'John Doe',
email: 'Johndoe1234@gmail.com'
});
setSelectedTheme('light');
};
if (!user) {
navigate('/login');
return null;
}
return (
<div className="w-[1440px] h-[840px] p-4 bg-Neutrals-NeutralSlate200 inline-flex justify-start items-start overflow-hidden">
<div className="flex-1 self-stretch rounded-3xl shadow-[0px_0px_15px_0px_rgba(0,0,0,0.08)] flex justify-between items-start overflow-hidden">
<Sidebar companyName="Zitlac Media" />
<div className="flex-1 self-stretch bg-Neutrals-NeutralSlate0 inline-flex flex-col justify-start items-start">
{/* Tab Navigation */}
<div className="self-stretch px-6 pt-6 border-b border-Outline-Outline-Gray-200 flex flex-col justify-start items-end">
<div className="self-stretch inline-flex justify-start items-start gap-6">
<div
onClick={() => setActiveTab('general')}
className={`w-32 inline-flex flex-col justify-start items-start gap-3 cursor-pointer ${
activeTab === 'general' ? '' : 'opacity-60'
}`}
>
<div className={`self-stretch text-center justify-center text-base font-['Inter'] leading-normal ${
activeTab === 'general'
? 'text-Text-Gray-800 font-semibold'
: 'text-Text-Gray-500 font-normal'
}`}>
General Settings
</div>
{activeTab === 'general' && (
<div className="self-stretch h-0.5 bg-Text-Gray-800 rounded-tl-lg rounded-tr-lg" />
)}
</div>
<div
onClick={() => setActiveTab('billing')}
className={`inline-flex flex-col justify-start items-start gap-3 cursor-pointer ${
activeTab === 'billing' ? '' : 'opacity-60'
}`}
>
<div className={`text-center justify-center text-base font-['Inter'] leading-normal ${
activeTab === 'billing'
? 'text-Text-Gray-800 font-semibold'
: 'text-Text-Gray-500 font-normal'
}`}>
Plan & Billings
</div>
{activeTab === 'billing' && (
<div className="w-24 h-0.5 bg-Text-Gray-800 rounded-tl-lg rounded-tr-lg" />
)}
</div>
</div>
<div className="w-24 h-0.5 opacity-0 bg-Text-Gray-800 rounded-tl-lg rounded-tr-lg" />
</div>
{/* General Settings Content */}
{activeTab === 'general' && (
<>
{/* Profile Information Section */}
<div className="w-[1136px] h-72 p-6 flex flex-col justify-start items-start gap-6">
<div className="w-[584px] flex flex-col justify-start items-start gap-1">
<div className="self-stretch justify-start text-Text-Gray-800 text-lg font-semibold font-['Inter'] leading-7">Profile Information</div>
<div className="self-stretch justify-start text-Text-Gray-500 text-sm font-normal font-['Inter'] leading-tight">Update your personal details, and keep your profile up to date.</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-6">
{/* Profile Picture Section */}
<div className="w-[664px] px-3 py-2.5 bg-Text-White-00 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Text-Gray-200 inline-flex justify-between items-center">
<div className="flex-1 flex justify-start items-center gap-3">
<div className="w-14 h-14 relative bg-red-200 rounded-[999px]">
<div>
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_3786)">
<ellipse cx="28" cy="54.6008" rx="22.4" ry="16.8" fill="white" fillOpacity="0.72" />
<circle opacity="0.9" cx="28" cy="22.3992" r="11.2" fill="white" />
</g>
<defs>
<clipPath id="clip0_1042_3786">
<rect width="56" height="56" rx="28" fill="white" />
</clipPath>
</defs>
</svg>
</div>
</div>
<div className="flex-1 inline-flex flex-col justify-start items-start gap-1">
<div className="self-stretch justify-center text-Text-Gray-800 text-base font-semibold font-['Inter'] leading-normal">Profile Picture</div>
<div className="self-stretch justify-center text-Text-Gray-500 text-xs font-normal font-['Inter'] leading-none">PNG, JPEG, GIF Under 10MB</div>
</div>
</div>
<div
onClick={handlePhotoUpload}
className="px-3 py-2.5 bg-Neutrals-NeutralSlate100 rounded-[999px] flex justify-center items-center gap-1 overflow-hidden cursor-pointer hover:bg-Neutrals-NeutralSlate200"
>
<div>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66665 10.8282C1.86266 10.29 1.33331 9.37347 1.33331 8.33333C1.33331 6.77095 2.52765 5.48753 4.05314 5.34625C4.36519 3.44809 6.01348 2 7.99998 2C9.98648 2 11.6348 3.44809 11.9468 5.34625C13.4723 5.48753 14.6666 6.77095 14.6666 8.33333C14.6666 9.37347 14.1373 10.29 13.3333 10.8282M5.33331 10.6667L7.99998 8M7.99998 8L10.6666 10.6667M7.99998 8V14" stroke="var(--Text-Dark-950, #0A0D12)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">Upload Photo</div>
</div>
</div>
</div>
{/* Name and Email Fields */}
<div className="w-[664px] inline-flex justify-start items-center gap-4">
<div className="flex-1 inline-flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">Full Name</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<div>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.5C7.35828 12.5 5.00901 13.7755 3.51334 15.755C3.19143 16.181 3.03047 16.394 3.03574 16.6819C3.03981 16.9043 3.17948 17.1849 3.35448 17.3222C3.581 17.5 3.8949 17.5 4.5227 17.5H15.4773C16.1051 17.5 16.419 17.5 16.6455 17.3222C16.8205 17.1849 16.9602 16.9043 16.9643 16.6819C16.9695 16.394 16.8086 16.181 16.4867 15.755C14.991 13.7755 12.6417 12.5 10 12.5Z" stroke="var(--Text-Gray-600, #535862)" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round" strokeLinejoin="round" />
<path d="M10 10C12.0711 10 13.75 8.32107 13.75 6.25C13.75 4.17893 12.0711 2.5 10 2.5C7.92894 2.5 6.25001 4.17893 6.25001 6.25C6.25001 8.32107 7.92894 10 10 10Z" stroke="var(--Text-Gray-600, #535862)" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<input
type="text"
value={userProfile.fullName}
onChange={(e) => handleProfileUpdate('fullName', e.target.value)}
className="flex-1 bg-transparent text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight outline-none"
/>
</div>
</div>
</div>
<div className="flex-1 inline-flex flex-col justify-start items-start gap-2">
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate900 text-sm font-normal font-['Inter'] leading-tight">Email Address</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<div>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.66669 5.83203L8.47079 10.5949C9.02176 10.9806 9.29725 11.1734 9.59691 11.2481C9.8616 11.3141 10.1384 11.3141 10.4031 11.2481C10.7028 11.1734 10.9783 10.9806 11.5293 10.5949L18.3334 5.83203M5.66669 16.6654H14.3334C15.7335 16.6654 16.4336 16.6654 16.9683 16.3929C17.4387 16.1532 17.8212 15.7707 18.0609 15.3003C18.3334 14.7656 18.3334 14.0655 18.3334 12.6654V7.33203C18.3334 5.9319 18.3334 5.23183 18.0609 4.69705C17.8212 4.22665 17.4387 3.8442 16.9683 3.60451C16.4336 3.33203 15.7335 3.33203 14.3334 3.33203H5.66669C4.26656 3.33203 3.56649 3.33203 3.03171 3.60451C2.56131 3.8442 2.17885 4.22665 1.93917 4.69705C1.66669 5.23183 1.66669 5.9319 1.66669 7.33203V12.6654C1.66669 14.0655 1.66669 14.7656 1.93917 15.3003C2.17885 15.7707 2.56131 16.1532 3.03171 16.3929C3.56649 16.6654 4.26656 16.6654 5.66669 16.6654Z" stroke="var(--Text-Gray-600, #535862)" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<input
type="email"
value={userProfile.email}
onChange={(e) => handleProfileUpdate('email', e.target.value)}
className="flex-1 bg-transparent text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight outline-none"
/>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Divider */}
<div>
<svg width="1136" height="2" viewBox="0 0 1136 2" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 1H1136" stroke="var(--Text-Gray-200, #E9EAEB)" />
</svg>
</div>
{/* Theme Customization Section */}
<div className="w-[1170px] p-6 flex flex-col justify-start items-start gap-6">
<div className="w-[584px] flex flex-col justify-start items-start gap-1">
<div className="self-stretch justify-start text-Text-Gray-800 text-lg font-semibold font-['Inter'] leading-7">Theme Customization</div>
<div className="self-stretch justify-start text-Text-Gray-500 text-sm font-normal font-['Inter'] leading-tight">Personalize your interface with light or dark mode and enhance your visual experience.</div>
</div>
<div className="inline-flex justify-start items-start gap-3 flex-wrap content-start">
{/* System Preference */}
<div
onClick={() => setSelectedTheme('system')}
className={`max-w-60 inline-flex flex-col justify-start items-start gap-3 cursor-pointer ${
selectedTheme === 'system' ? 'opacity-100' : 'opacity-70'
}`}
>
<div className="inline-flex justify-start items-center">
<img className="w-24 h-28 rounded-tl-lg rounded-bl-lg" src="https://via.placeholder.com/94x107/f8f9fa/6c757d?text=Light" />
<img className="w-24 h-28 rounded-tr-lg rounded-br-lg" src="https://via.placeholder.com/96x107/212529/ffffff?text=Dark" />
</div>
<div className="self-stretch h-5 justify-start text-Text-Gray-800 text-sm font-normal font-['Inter'] leading-tight">System preference</div>
</div>
{/* Light Mode */}
<div
onClick={() => setSelectedTheme('light')}
className={`w-48 max-w-60 inline-flex flex-col justify-start items-start gap-3 cursor-pointer ${
selectedTheme === 'light' ? 'opacity-100' : 'opacity-70'
}`}
>
<div className="self-stretch h-28 relative bg-Text-White-00 rounded-lg overflow-hidden">
<div className={`w-48 h-28 left-0 top-0 absolute bg-Text-White-00 rounded-[10px] outline outline-1 outline-offset-[-1px] overflow-hidden ${
selectedTheme === 'light' ? 'outline-Brand-Orange' : 'outline-Text-Gray-200'
}`}>
<img className="w-48 h-28 left-0 top-0 absolute rounded-lg" src="https://via.placeholder.com/190x107/f8f9fa/6c757d?text=Light+Mode" />
</div>
</div>
<div className="self-stretch h-5 justify-start text-Text-Gray-800 text-sm font-normal font-['Inter'] leading-tight">Light Mode</div>
</div>
{/* Dark Mode */}
<div
onClick={() => setSelectedTheme('dark')}
className={`max-w-60 inline-flex flex-col justify-start items-start gap-3 cursor-pointer ${
selectedTheme === 'dark' ? 'opacity-100' : 'opacity-70'
}`}
>
<div className="w-48 h-28 relative bg-Text-White-00 rounded-lg overflow-hidden">
<div className={`w-48 h-28 left-0 top-0 absolute bg-Text-White-00 rounded-[10px] outline outline-1 outline-offset-[-1px] overflow-hidden ${
selectedTheme === 'dark' ? 'outline-Brand-Orange' : 'outline-Text-Gray-200'
}`}>
<img className="w-48 h-28 left-0 top-0 absolute rounded-lg" src="https://via.placeholder.com/190x107/212529/ffffff?text=Dark+Mode" />
</div>
</div>
<div className="self-stretch h-5 justify-start text-Text-Gray-800 text-sm font-normal font-['Inter'] leading-tight">Dark Mode</div>
</div>
</div>
</div>
{/* Another Divider */}
<div>
<svg width="1136" height="2" viewBox="0 0 1136 2" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 1H1136" stroke="var(--Text-Gray-200, #E9EAEB)" />
</svg>
</div>
{/* Action Buttons */}
<div className="w-[1175px] p-6 inline-flex justify-start items-center gap-2">
<div
onClick={handleReset}
className="px-3 py-2.5 bg-Neutrals-NeutralSlate100 rounded-[999px] flex justify-center items-center gap-1 overflow-hidden cursor-pointer hover:bg-Neutrals-NeutralSlate200"
>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">Reset</div>
</div>
</div>
<div
onClick={handleSaveChanges}
className="px-3 py-2.5 bg-Brand-Orange rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden cursor-pointer hover:bg-Brand-Orange/90"
>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Save Changes</div>
</div>
</div>
</div>
</>
)}
{/* Billing Content */}
{activeTab === 'billing' && (
<div className="flex-1 flex items-center justify-center">
<div className="text-center">
<h2 className="text-2xl font-semibold text-Text-Gray-800 mb-4">Plan & Billing</h2>
<p className="text-Text-Gray-500">Billing management features would be implemented here.</p>
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default SettingsNew;

View File

@@ -0,0 +1,223 @@
import React from 'react';
const ChatAIResponse: React.FC = () => {
return (
<div className="w-full h-[810px] p-4 bg-Neutrals-NeutralSlate200 inline-flex justify-start items-start overflow-hidden">
<div className="flex-1 self-stretch rounded-3xl shadow-[0px_0px_15px_0px_rgba(0,0,0,0.08)] flex justify-between items-start overflow-hidden">
{/* Sidebar */}
<div className="w-64 self-stretch 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">
<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="w-8 h-8 left-0 top-0 absolute bg-gradient-to-b from-white/0 to-white/10" />
<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_1042_694)">
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M4.34342 10.6855C4.66998 11.0162 4.66998 11.5524 4.34341 11.8831L4.32669 11.9C4.00012 12.2307 3.47065 12.2307 3.14409 11.9C2.81753 11.5693 2.81753 11.0331 3.1441 10.7024L3.16082 10.6855C3.48739 10.3548 4.01686 10.3548 4.34342 10.6855Z" fill="url(#paint0_linear_1042_694)" />
</g>
<defs>
<linearGradient id="paint0_linear_1042_694" x1="3.74376" y1="10.4375" x2="3.74376" y2="12.148" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="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">Zitlac Media</div>
</div>
</div>
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.83325 12.4987L9.99992 16.6654L14.1666 12.4987M5.83325 7.4987L9.99992 3.33203L14.1666 7.4987" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
{/* Navigation Menu */}
<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">
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 17.5016V11.3349C7.5 10.8682 7.5 10.6348 7.59083 10.4566C7.67072 10.2998 7.79821 10.1723 7.95501 10.0924C8.13327 10.0016 8.36662 10.0016 8.83333 10.0016H11.1667C11.6334 10.0016 11.8667 10.0016 12.045 10.0924C12.2018 10.1723 12.3293 10.2998 12.4092 10.4566C12.5 10.6348 12.5 10.8682 12.5 11.3349V17.5016M9.18141 2.30492L3.52949 6.70086C3.15168 6.99471 2.96278 7.14163 2.82669 7.32563C2.70614 7.48862 2.61633 7.67224 2.56169 7.86746C2.5 8.08785 2.5 8.32717 2.5 8.8058V14.8349C2.5 15.7683 2.5 16.235 2.68166 16.5916C2.84144 16.9052 3.09641 17.1601 3.41002 17.3199C3.76654 17.5016 4.23325 17.5016 5.16667 17.5016H14.8333C15.7668 17.5016 16.2335 17.5016 16.59 17.3199C16.9036 17.1601 17.1586 16.9052 17.3183 16.5916C17.5 16.235 17.5 15.7683 17.5 14.8349V8.8058C17.5 8.32717 17.5 8.08785 17.4383 7.86746C17.3837 7.67224 17.2939 7.48862 17.1733 7.32563C17.0372 7.14163 16.8483 6.99471 16.4705 6.70086L10.8186 2.30492C10.5258 2.07721 10.3794 1.96335 10.2178 1.91959C10.0752 1.88097 9.92484 1.88097 9.78221 1.91959C9.62057 1.96335 9.47418 2.07721 9.18141 2.30492Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Company Wiki</div>
</div>
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6666 9.16797H6.66659M8.33325 12.5013H6.66659M13.3333 5.83464H6.66659M16.6666 5.66797V14.3346C16.6666 15.7348 16.6666 16.4348 16.3941 16.9696C16.1544 17.44 15.772 17.8225 15.3016 18.0622C14.7668 18.3346 14.0667 18.3346 12.6666 18.3346H7.33325C5.93312 18.3346 5.23306 18.3346 4.69828 18.0622C4.22787 17.8225 3.84542 17.44 3.60574 16.9696C3.33325 16.4348 3.33325 15.7348 3.33325 14.3346V5.66797C3.33325 4.26784 3.33325 3.56777 3.60574 3.03299C3.84542 2.56259 4.22787 2.18014 4.69828 1.94045C5.23306 1.66797 5.93312 1.66797 7.33325 1.66797H12.6666C14.0667 1.66797 14.7668 1.66797 15.3016 1.94045C15.772 2.18014 16.1544 2.56259 16.3941 3.03299C16.6666 3.56777 16.6666 4.26784 16.6666 5.66797Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Submissions</div>
</div>
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_720)">
<path d="M10.0001 1.66797C11.0944 1.66797 12.1781 1.88352 13.1891 2.30231C14.2002 2.7211 15.1188 3.33493 15.8926 4.10875C16.6665 4.88257 17.2803 5.80123 17.6991 6.81228C18.1179 7.82332 18.3334 8.90696 18.3334 10.0013M10.0001 1.66797V10.0013M10.0001 1.66797C5.39771 1.66797 1.66675 5.39893 1.66675 10.0013C1.66675 14.6037 5.39771 18.3346 10.0001 18.3346C14.6025 18.3346 18.3334 14.6037 18.3334 10.0013M10.0001 1.66797C14.6025 1.66797 18.3334 5.39893 18.3334 10.0013M18.3334 10.0013L10.0001 10.0013M18.3334 10.0013C18.3334 11.3164 18.0222 12.6128 17.4251 13.7846C16.8281 14.9563 15.9622 15.9701 14.8983 16.7431L10.0001 10.0013" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_1042_720">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Reports</div>
</div>
{/* Active Chat Item */}
<div className="w-60 px-4 py-2.5 bg-Neutrals-NeutralSlate100 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.4996 9.58333C17.4996 13.4953 14.3283 16.6667 10.4163 16.6667C9.51896 16.6667 8.66061 16.4998 7.87057 16.1954C7.72612 16.1398 7.6539 16.112 7.59647 16.0987C7.53998 16.0857 7.49908 16.0803 7.44116 16.0781C7.38226 16.0758 7.31764 16.0825 7.18841 16.0958L2.92089 16.537C2.51402 16.579 2.31059 16.6001 2.19058 16.5269C2.08606 16.4631 2.01487 16.3566 1.99592 16.2356C1.97416 16.0968 2.07138 15.9168 2.2658 15.557L3.62885 13.034C3.7411 12.8262 3.79723 12.7223 3.82265 12.6225C3.84776 12.5238 3.85383 12.4527 3.8458 12.3512C3.83766 12.2484 3.79258 12.1147 3.70241 11.8472C3.46281 11.1363 3.33294 10.375 3.33294 9.58333C3.33294 5.67132 6.50426 2.5 10.4163 2.5C14.3283 2.5 17.4996 5.67132 17.4996 9.58333Z" stroke="var(--Brand-Orange, #3399FF)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">Chat</div>
</div>
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_728)">
<path d="M7.57508 7.5013C7.771 6.94436 8.15771 6.47472 8.66671 6.17558C9.17571 5.87643 9.77416 5.76708 10.3561 5.8669C10.938 5.96671 11.4658 6.26924 11.846 6.72091C12.2262 7.17258 12.4343 7.74424 12.4334 8.33464C12.4334 10.0013 9.93342 10.8346 9.93342 10.8346M10.0001 14.168H10.0084M18.3334 10.0013C18.3334 14.6037 14.6025 18.3346 10.0001 18.3346C5.39771 18.3346 1.66675 14.6037 1.66675 10.0013C1.66675 5.39893 5.39771 1.66797 10.0001 1.66797C14.6025 1.66797 18.3334 5.39893 18.3334 10.0013Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Help</div>
</div>
</div>
</div>
</div>
{/* Bottom Section */}
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_733)">
<path d="M10.0001 12.5013C11.3808 12.5013 12.5001 11.382 12.5001 10.0013C12.5001 8.62059 11.3808 7.5013 10.0001 7.5013C8.61937 7.5013 7.50008 8.62059 7.50008 10.0013C7.50008 11.382 8.61937 12.5013 10.0001 12.5013Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="flex-1 justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Settings</div>
</div>
{/* Company 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 h-32 left-0 top-[-0.50px] absolute bg-gradient-to-b from-black to-black/0" />
<div className="w-60 p-3 left-[18.12px] top-[42.52px] absolute 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-NeutralSlate200 inline-flex flex-col justify-start items-start gap-3 overflow-hidden" />
<div className="w-60 p-3 left-[31.44px] top-[22px] absolute 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-NeutralSlate200 inline-flex flex-col justify-start items-start gap-3 overflow-hidden" />
</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-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">
<div className="flex-1 px-3 py-1.5 bg-Button-Secondary rounded-[999px] flex justify-center items-center gap-0.5 overflow-hidden">
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">Invite</div>
</div>
<div className="relative">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.99992 3.33203V12.6654M3.33325 7.9987H12.6666" stroke="var(--Neutrals-NeutralSlate950, #0A0D12)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
<div className="flex-1 px-3 py-1.5 bg-Brand-Orange rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
<div className="relative">
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.97179 12.2442L8.02898 13.1871C6.72723 14.4888 4.61668 14.4888 3.31493 13.1871C2.01319 11.8853 2.01319 9.77476 3.31493 8.47301L4.25774 7.5302M12.743 8.47301L13.6858 7.5302C14.9876 6.22845 14.9876 4.1179 13.6858 2.81615C12.3841 1.51441 10.2735 1.51441 8.97179 2.81615L8.02898 3.75896M6.16705 10.3349L10.8337 5.66826" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Copy</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Main Chat Area */}
<div className="flex-1 self-stretch py-6 bg-Neutrals-NeutralSlate0 inline-flex flex-col justify-center items-center gap-2.5">
<div className="w-[736px] flex-1 max-w-[736px] pt-48 flex flex-col justify-start items-center gap-6">
<div className="self-stretch flex flex-col justify-start items-end gap-4">
{/* User Question */}
<div className="px-4 py-3 bg-Main-BG-Gray-100 rounded-2xl inline-flex justify-start items-center gap-3 overflow-hidden">
<div className="justify-start text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">What are the main characteristics?</div>
<div className="pl-1.5 pr-2 py-0.5 bg-Text-Gray-300 rounded-2xl flex justify-start items-center gap-1.5">
<div className="relative">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_20157)">
<path d="M9.33318 4.66761V7.58427C9.33318 8.0484 9.51755 8.49352 9.84574 8.82171C10.1739 9.1499 10.619 9.33427 11.0832 9.33427C11.5473 9.33427 11.9924 9.1499 12.3206 8.82171C12.6488 8.49352 12.8332 8.0484 12.8332 7.58427V7.00094C12.8331 5.68437 12.3876 4.40655 11.5693 3.37525C10.7509 2.34395 9.60767 1.61982 8.32555 1.32061C7.04343 1.02141 5.6978 1.16471 4.50746 1.72724C3.31712 2.28976 2.35207 3.23841 1.76924 4.41895C1.18641 5.59948 1.02007 6.94245 1.29727 8.22951C1.57447 9.51656 2.27891 10.672 3.29604 11.5079C4.31317 12.3439 5.58318 12.8111 6.89955 12.8338C8.21592 12.8564 9.50124 12.4331 10.5465 11.6326M9.33318 7.00094C9.33318 8.2896 8.28851 9.33427 6.99984 9.33427C5.71118 9.33427 4.66651 8.2896 4.66651 7.00094C4.66651 5.71228 5.71118 4.66761 6.99984 4.66761C8.28851 4.66761 9.33318 5.71228 9.33318 7.00094Z" stroke="var(--Text-Gray-600, #535862)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="text-center justify-start text-Text-Gray-600 text-sm font-medium font-['Inter'] leading-tight">Alex Green</div>
</div>
</div>
{/* AI Response */}
<div className="self-stretch justify-start">
<span className="text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">Main characteristics refer to the most important features or qualities that define or distinguish something. These can be physical, emotional, mental, or moral attributes that help identify and differentiate a person, object, or concept. <br />Elaboration:<br /></span>
<span className="text-Text-Gray-800 text-base font-medium font-['Inter'] leading-normal">Physical Characteristics:</span>
<span className="text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal"> These relate to the outward appearance of something, such as its shape, size, color, or material. For example, the physical characteristics of a chair might include its height, the material it's made of (wood, metal, etc.), and its color. <br /></span>
<span className="text-Text-Gray-800 text-base font-medium font-['Inter'] leading-normal">Emotional Characteristics:</span>
<span className="text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal"> These describe how someone or something responds to situations or experiences. Examples include being happy, sad, angry, or calm. <br /></span>
<span className="text-Text-Gray-800 text-base font-medium font-['Inter'] leading-normal">Mental Characteristics:</span>
<span className="text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal"> These relate to a person's cognitive abilities and thinking patterns. Examples include intelligence, creativity, and curiosity. <br /></span>
<span className="text-Text-Gray-800 text-base font-medium font-['Inter'] leading-normal">Moral Characteristics:</span>
<span className="text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal"> These describe a person's ethical or value-based behavior. Examples include kindness, honesty, and generosity. </span>
</div>
</div>
{/* Chat Input */}
<div className="self-stretch pl-5 pr-3 pt-5 pb-3 bg-Main-BG-Gray-50 rounded-3xl flex flex-col justify-start items-start gap-4">
<div className="self-stretch justify-start text-Text-Gray-500 text-base font-normal font-['Inter'] leading-normal">Ask anything, use @ to tag staff and ask questions.</div>
<div className="self-stretch inline-flex justify-between items-center">
<div className="flex justify-start items-center gap-4">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.6271 9.08442L10.1141 16.5974C8.40556 18.306 5.63546 18.306 3.92692 16.5974C2.21837 14.8889 2.21837 12.1188 3.92692 10.4102L11.4399 2.89724C12.579 1.75821 14.4257 1.75821 15.5647 2.89724C16.7037 4.03627 16.7037 5.883 15.5647 7.02203L8.34633 14.2404C7.77682 14.8099 6.85345 14.8099 6.28394 14.2404C5.71442 13.6709 5.71442 12.7475 6.28394 12.178L12.6184 5.84352" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5 17.5H5.77614C5.2713 17.5 5.01887 17.5 4.90199 17.4002C4.80056 17.3135 4.74674 17.1836 4.75721 17.0506C4.76927 16.8974 4.94776 16.7189 5.30474 16.3619L12.3905 9.27614C12.7205 8.94613 12.8855 8.78112 13.0758 8.7193C13.2432 8.66492 13.4235 8.66492 13.5908 8.7193C13.7811 8.78112 13.9461 8.94613 14.2761 9.27614L17.5 12.5V13.5M13.5 17.5C14.9001 17.5 15.6002 17.5 16.135 17.2275C16.6054 16.9878 16.9878 16.6054 17.2275 16.135C17.5 15.6002 17.5 14.9001 17.5 13.5M13.5 17.5H6.5C5.09987 17.5 4.3998 17.5 3.86502 17.2275C3.39462 16.9878 3.01217 16.6054 2.77248 16.135C2.5 15.6002 2.5 14.9001 2.5 13.5V6.5C2.5 5.09987 2.5 4.3998 2.77248 3.86502C3.01217 3.39462 3.39462 3.01217 3.86502 2.77248C4.3998 2.5 5.09987 2.5 6.5 2.5H13.5C14.9001 2.5 15.6002 2.5 16.135 2.77248C16.6054 3.01217 16.9878 3.39462 17.2275 3.86502C17.5 4.3998 17.5 5.09987 17.5 6.5V13.5M8.75 7.08333C8.75 8.00381 8.00381 8.75 7.08333 8.75C6.16286 8.75 5.41667 8.00381 5.41667 7.08333C5.41667 6.16286 6.16286 5.41667 7.08333 5.41667C8.00381 5.41667 8.75 6.16286 8.75 7.08333Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_20047)">
<path d="M13.3334 6.66745V10.8341C13.3334 11.4972 13.5968 12.133 14.0657 12.6019C14.5345 13.0707 15.1704 13.3341 15.8334 13.3341C16.4965 13.3341 17.1324 13.0707 17.6012 12.6019C18.07 12.133 18.3334 11.4972 18.3334 10.8341V10.0008C18.3333 8.11998 17.6969 6.29452 16.5278 4.82123C15.3587 3.34794 13.7256 2.31347 11.894 1.88603C10.0624 1.45859 8.14003 1.66332 6.43955 2.46692C4.73906 3.27053 3.36042 4.62575 2.5278 6.31222C1.69519 7.99869 1.45756 9.91723 1.85356 11.7559C2.24956 13.5945 3.2559 15.2451 4.70895 16.4393C6.16199 17.6335 7.97628 18.3011 9.85681 18.3334C11.7373 18.3657 13.5735 17.761 15.0668 16.6175M13.3334 10.0008C13.3334 11.8417 11.841 13.3341 10.0001 13.3341C8.15914 13.3341 6.66676 11.8417 6.66676 10.0008C6.66676 8.15984 8.15914 6.66745 10.0001 6.66745C11.841 6.66745 13.3334 8.15984 13.3334 10.0008Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
</div>
<div className="p-2.5 bg-Text-Gray-300 rounded-[999px] flex justify-start items-center gap-2.5 overflow-hidden">
<div className="relative">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 13.3346V2.66797M8 2.66797L4 6.66797M8 2.66797L12 6.66797" stroke="var(--Text-White-00, #FDFDFD)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default ChatAIResponse;

256
pages/figma/ChatLight.tsx Normal file
View File

@@ -0,0 +1,256 @@
import React from 'react';
const ChatLight: React.FC = () => {
return (
<div className="w-full h-[810px] p-4 bg-Neutrals-NeutralSlate200 inline-flex justify-start items-start overflow-hidden">
<div className="flex-1 self-stretch rounded-3xl shadow-[0px_0px_15px_0px_rgba(0,0,0,0.08)] flex justify-between items-start overflow-hidden">
{/* Sidebar */}
<div className="w-64 self-stretch 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">
<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="w-8 h-8 left-0 top-0 absolute bg-gradient-to-b from-white/0 to-white/10" />
<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_1042_1443)">
<path opacity="0.5" fillRule="evenodd" clipRule="evenodd" d="M4.34347 10.6855C4.67003 11.0162 4.67003 11.5524 4.34346 11.8831L4.32674 11.9C4.00017 12.2307 3.4707 12.2307 3.14414 11.9C2.81758 11.5693 2.81758 11.0331 3.14415 10.7024L3.16087 10.6855C3.48744 10.3548 4.01691 10.3548 4.34347 10.6855Z" fill="url(#paint0_linear_1042_1443)" />
</g>
<defs>
<linearGradient id="paint0_linear_1042_1443" x1="3.7438" y1="10.4375" x2="3.7438" y2="12.148" gradientUnits="userSpaceOnUse">
<stop stopColor="white" stopOpacity="0.8" />
<stop offset="1" stopColor="white" stopOpacity="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">Zitlac Media</div>
</div>
</div>
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.83333 12.4987L9.99999 16.6654L14.1667 12.4987M5.83333 7.4987L9.99999 3.33203L14.1667 7.4987" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
{/* Navigation Menu */}
<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">
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 17.5016V11.3349C7.5 10.8682 7.5 10.6348 7.59083 10.4566C7.67072 10.2998 7.79821 10.1723 7.95501 10.0924C8.13327 10.0016 8.36662 10.0016 8.83333 10.0016H11.1667C11.6334 10.0016 11.8667 10.0016 12.045 10.0924C12.2018 10.1723 12.3293 10.2998 12.4092 10.4566C12.5 10.6348 12.5 10.8682 12.5 11.3349V17.5016M9.18141 2.30492L3.52949 6.70086C3.15168 6.99471 2.96278 7.14163 2.82669 7.32563C2.70614 7.48862 2.61633 7.67224 2.56169 7.86746C2.5 8.08785 2.5 8.32717 2.5 8.8058V14.8349C2.5 15.7683 2.5 16.235 2.68166 16.5916C2.84144 16.9052 3.09641 17.1601 3.41002 17.3199C3.76654 17.5016 4.23325 17.5016 5.16667 17.5016H14.8333C15.7668 17.5016 16.2335 17.5016 16.59 17.3199C16.9036 17.1601 17.1586 16.9052 17.3183 16.5916C17.5 16.235 17.5 15.7683 17.5 14.8349V8.8058C17.5 8.32717 17.5 8.08785 17.4383 7.86746C17.3837 7.67224 17.2939 7.48862 17.1733 7.32563C17.0372 7.14163 16.8483 6.99471 16.4705 6.70086L10.8186 2.30492C10.5258 2.07721 10.3794 1.96335 10.2178 1.91959C10.0752 1.88097 9.92484 1.88097 9.78221 1.91959C9.62057 1.96335 9.47418 2.07721 9.18141 2.30492Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Company Wiki</div>
</div>
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6667 9.16797H6.66667M8.33333 12.5013H6.66667M13.3333 5.83464H6.66667M16.6667 5.66797V14.3346C16.6667 15.7348 16.6667 16.4348 16.3942 16.9696C16.1545 17.44 15.772 17.8225 15.3016 18.0622C14.7669 18.3346 14.0668 18.3346 12.6667 18.3346H7.33333C5.9332 18.3346 5.23314 18.3346 4.69836 18.0622C4.22795 17.8225 3.8455 17.44 3.60582 16.9696C3.33333 16.4348 3.33333 15.7348 3.33333 14.3346V5.66797C3.33333 4.26784 3.33333 3.56777 3.60582 3.03299C3.8455 2.56259 4.22795 2.18014 4.69836 1.94045C5.23314 1.66797 5.9332 1.66797 7.33333 1.66797H12.6667C14.0668 1.66797 14.7669 1.66797 15.3016 1.94045C15.772 2.18014 16.1545 2.56259 16.3942 3.03299C16.6667 3.56777 16.6667 4.26784 16.6667 5.66797Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Submissions</div>
</div>
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_1469)">
<path d="M10 1.66797C11.0943 1.66797 12.178 1.88352 13.189 2.30231C14.2001 2.7211 15.1187 3.33493 15.8926 4.10875C16.6664 4.88257 17.2802 5.80123 17.699 6.81228C18.1178 7.82332 18.3333 8.90696 18.3333 10.0013M10 1.66797V10.0013M10 1.66797C5.39763 1.66797 1.66667 5.39893 1.66667 10.0013C1.66667 14.6037 5.39763 18.3346 10 18.3346C14.6024 18.3346 18.3333 14.6037 18.3333 10.0013M10 1.66797C14.6024 1.66797 18.3333 5.39893 18.3333 10.0013M18.3333 10.0013L10 10.0013M18.3333 10.0013C18.3333 11.3164 18.0221 12.6128 17.4251 13.7846C16.828 14.9563 15.9621 15.9701 14.8982 16.7431L10 10.0013" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Reports</div>
</div>
{/* Active Chat Item */}
<div className="w-60 px-4 py-2.5 bg-Neutrals-NeutralSlate100 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.4997 9.58333C17.4997 13.4953 14.3284 16.6667 10.4164 16.6667C9.51904 16.6667 8.66069 16.4998 7.87065 16.1954C7.7262 16.1398 7.65398 16.112 7.59655 16.0987C7.54006 16.0857 7.49917 16.0803 7.44124 16.0781C7.38234 16.0758 7.31772 16.0825 7.18849 16.0958L2.92097 16.537C2.5141 16.579 2.31067 16.6001 2.19067 16.5269C2.08614 16.4631 2.01495 16.3566 1.996 16.2356C1.97425 16.0968 2.07146 15.9168 2.26588 15.557L3.62893 13.034C3.74118 12.8262 3.79731 12.7223 3.82273 12.6225C3.84784 12.5238 3.85391 12.4527 3.84588 12.3512C3.83775 12.2484 3.79266 12.1147 3.7025 11.8472C3.46289 11.1363 3.33302 10.375 3.33302 9.58333C3.33302 5.67132 6.50434 2.5 10.4164 2.5C14.3284 2.5 17.4997 5.67132 17.4997 9.58333Z" stroke="var(--Brand-Orange, #3399FF)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">Chat</div>
</div>
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_1477)">
<path d="M7.575 7.5013C7.77092 6.94436 8.15763 6.47472 8.66663 6.17558C9.17563 5.87643 9.77408 5.76708 10.356 5.8669C10.9379 5.96671 11.4657 6.26924 11.8459 6.72091C12.2261 7.17258 12.4342 7.74424 12.4333 8.33464C12.4333 10.0013 9.93333 10.8346 9.93333 10.8346M10 14.168H10.0083M18.3333 10.0013C18.3333 14.6037 14.6024 18.3346 10 18.3346C5.39763 18.3346 1.66667 14.6037 1.66667 10.0013C1.66667 5.39893 5.39763 1.66797 10 1.66797C14.6024 1.66797 18.3333 5.39893 18.3333 10.0013Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Help</div>
</div>
</div>
</div>
</div>
{/* Bottom Section */}
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="w-60 px-4 py-2.5 rounded-[34px] inline-flex justify-start items-center gap-2">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1042_1482)">
<path d="M10 12.5013C11.3807 12.5013 12.5 11.382 12.5 10.0013C12.5 8.62059 11.3807 7.5013 10 7.5013C8.61929 7.5013 7.5 8.62059 7.5 10.0013C7.5 11.382 8.61929 12.5013 10 12.5013Z" stroke="var(--Neutrals-NeutralSlate400, #A4A7AE)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="flex-1 justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">Settings</div>
</div>
{/* Company 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 h-32 left-0 top-[-0.50px] absolute bg-gradient-to-b from-black to-black/0" />
<div className="w-60 p-3 left-[18.12px] top-[42.52px] absolute 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-NeutralSlate200 inline-flex flex-col justify-start items-start gap-3 overflow-hidden" />
<div className="w-60 p-3 left-[31.44px] top-[22px] absolute 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-NeutralSlate200 inline-flex flex-col justify-start items-start gap-3 overflow-hidden" />
</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-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">
<div className="flex-1 px-3 py-1.5 bg-Button-Secondary rounded-[999px] flex justify-center items-center gap-0.5 overflow-hidden">
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">Invite</div>
</div>
<div className="relative">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00004 3.33398V12.6673M3.33337 8.00065H12.6667" stroke="var(--Neutrals-NeutralSlate950, #0A0D12)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
<div className="flex-1 px-3 py-1.5 bg-Brand-Orange rounded-[999px] outline outline-1 outline-offset-[-1px] outline-blue-400 flex justify-center items-center gap-0.5 overflow-hidden">
<div className="relative">
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.97167 12.2423L8.02886 13.1851C6.72711 14.4868 4.61656 14.4868 3.31481 13.1851C2.01306 11.8834 2.01306 9.7728 3.31481 8.47106L4.25762 7.52825M12.7429 8.47106L13.6857 7.52825C14.9875 6.2265 14.9875 4.11595 13.6857 2.8142C12.384 1.51245 10.2734 1.51245 8.97167 2.8142L8.02886 3.75701M6.16693 10.333L10.8336 5.6663" stroke="var(--Other-White, white)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Copy</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Main Chat Area */}
<div className="flex-1 self-stretch py-6 bg-Neutrals-NeutralSlate0 inline-flex flex-col justify-center items-center gap-2.5">
<div className="w-[736px] flex-1 max-w-[736px] pt-48 flex flex-col justify-between items-center">
<div className="self-stretch flex flex-col justify-start items-center gap-6">
<div className="justify-start text-Text-Gray-800 text-2xl font-medium font-['Neue_Montreal'] leading-normal">What would you like to understand?</div>
<div className="p-1 bg-Neutrals-NeutralSlate100 rounded-xl inline-flex justify-start items-center gap-1">
<div className="px-3 py-1.5 bg-white rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden">
<div className="px-0.5 flex justify-center items-center">
<div className="justify-start text-Neutrals-NeutralSlate900 text-xs font-medium font-['Inter'] leading-none">Accountability</div>
</div>
</div>
<div className="px-3 py-1.5 rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden">
<div className="px-0.5 flex justify-center items-center">
<div className="justify-start text-Neutrals-NeutralSlate600 text-xs font-medium font-['Inter'] leading-none">Employee Growth</div>
</div>
</div>
<div className="px-3 py-1.5 rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden">
<div className="px-0.5 flex justify-center items-center">
<div className="justify-start text-Neutrals-NeutralSlate600 text-xs font-medium font-['Inter'] leading-none">Customer Focus</div>
</div>
</div>
<div className="px-3 py-1.5 rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden">
<div className="px-0.5 flex justify-center items-center">
<div className="justify-start text-Neutrals-NeutralSlate600 text-xs font-medium font-['Inter'] leading-none">Teamwork</div>
</div>
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="self-stretch inline-flex justify-start items-center gap-3">
<div className="flex-1 h-48 px-3 py-4 bg-Main-BG-Gray-50 rounded-2xl inline-flex flex-col justify-between items-start overflow-hidden">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19218)">
<path d="M7.57499 7.5013C7.77091 6.94436 8.15762 6.47472 8.66662 6.17558C9.17562 5.87643 9.77407 5.76708 10.356 5.8669C10.9379 5.96671 11.4657 6.26924 11.8459 6.72091C12.2261 7.17258 12.4342 7.74424 12.4333 8.33464C12.4333 10.0013 9.93332 10.8346 9.93332 10.8346M9.99999 14.168H10.0083M18.3333 10.0013C18.3333 14.6037 14.6024 18.3346 9.99999 18.3346C5.39762 18.3346 1.66666 14.6037 1.66666 10.0013C1.66666 5.39893 5.39762 1.66797 9.99999 1.66797C14.6024 1.66797 18.3333 5.39893 18.3333 10.0013Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="self-stretch justify-start text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">How can the company serve them better?</div>
</div>
<div className="flex-1 h-48 px-3 py-4 bg-Main-BG-Gray-50 rounded-2xl inline-flex flex-col justify-between items-start overflow-hidden">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19221)">
<path d="M7.57502 7.5013C7.77094 6.94436 8.15765 6.47472 8.66665 6.17558C9.17565 5.87643 9.7741 5.76708 10.356 5.8669C10.9379 5.96671 11.4657 6.26924 11.8459 6.72091C12.2261 7.17258 12.4342 7.74424 12.4334 8.33464C12.4334 10.0013 9.93335 10.8346 9.93335 10.8346M10 14.168H10.0084M18.3334 10.0013C18.3334 14.6037 14.6024 18.3346 10 18.3346C5.39765 18.3346 1.66669 14.6037 1.66669 10.0013C1.66669 5.39893 5.39765 1.66797 10 1.66797C14.6024 1.66797 18.3334 5.39893 18.3334 10.0013Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="self-stretch justify-start text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">How can the company serve them better?</div>
</div>
<div className="flex-1 h-48 px-3 py-4 bg-Main-BG-Gray-50 rounded-2xl inline-flex flex-col justify-between items-start overflow-hidden">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19224)">
<path d="M7.57502 7.5013C7.77094 6.94436 8.15765 6.47472 8.66665 6.17558C9.17565 5.87643 9.7741 5.76708 10.356 5.8669C10.9379 5.96671 11.4657 6.26924 11.8459 6.72091C12.2261 7.17258 12.4342 7.74424 12.4334 8.33464C12.4334 10.0013 9.93335 10.8346 9.93335 10.8346M10 14.168H10.0084M18.3334 10.0013C18.3334 14.6037 14.6024 18.3346 10 18.3346C5.39765 18.3346 1.66669 14.6037 1.66669 10.0013C1.66669 5.39893 5.39765 1.66797 10 1.66797C14.6024 1.66797 18.3334 5.39893 18.3334 10.0013Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="self-stretch justify-start text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">How can the company serve them better?</div>
</div>
<div className="flex-1 h-48 px-3 py-4 bg-Main-BG-Gray-50 rounded-2xl inline-flex flex-col justify-between items-start overflow-hidden">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19227)">
<path d="M7.57502 7.5013C7.77094 6.94436 8.15765 6.47472 8.66665 6.17558C9.17565 5.87643 9.7741 5.76708 10.356 5.8669C10.9379 5.96671 11.4657 6.26924 11.8459 6.72091C12.2261 7.17258 12.4342 7.74424 12.4334 8.33464C12.4334 10.0013 9.93335 10.8346 9.93335 10.8346M10 14.168H10.0084M18.3334 10.0013C18.3334 14.6037 14.6024 18.3346 10 18.3346C5.39765 18.3346 1.66669 14.6037 1.66669 10.0013C1.66669 5.39893 5.39765 1.66797 10 1.66797C14.6024 1.66797 18.3334 5.39893 18.3334 10.0013Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
<div className="self-stretch justify-start text-Text-Gray-800 text-base font-normal font-['Inter'] leading-normal">How can the company serve them better?</div>
</div>
</div>
</div>
</div>
<div className="self-stretch pl-5 pr-3 pt-5 pb-3 bg-Main-BG-Gray-50 rounded-3xl flex flex-col justify-start items-start gap-4">
<div className="self-stretch justify-start text-Text-Gray-500 text-base font-normal font-['Inter'] leading-normal">Ask anything, use @ to tag staff and ask questions.</div>
<div className="self-stretch inline-flex justify-between items-center">
<div className="flex justify-start items-center gap-4">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.6271 9.08442L10.1141 16.5974C8.40553 18.306 5.63543 18.306 3.92688 16.5974C2.21834 14.8889 2.21834 12.1188 3.92688 10.4102L11.4399 2.89724C12.5789 1.75821 14.4257 1.75821 15.5647 2.89724C16.7037 4.03627 16.7037 5.883 15.5647 7.02203L8.3463 14.2404C7.77679 14.8099 6.85342 14.8099 6.28391 14.2404C5.71439 13.6709 5.71439 12.7475 6.28391 12.178L12.6184 5.84352" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5 17.5H5.77614C5.2713 17.5 5.01887 17.5 4.90199 17.4002C4.80056 17.3135 4.74674 17.1836 4.75721 17.0506C4.76927 16.8974 4.94776 16.7189 5.30474 16.3619L12.3905 9.27614C12.7205 8.94613 12.8855 8.78112 13.0758 8.7193C13.2432 8.66492 13.4235 8.66492 13.5908 8.7193C13.7811 8.78112 13.9461 8.94613 14.2761 9.27614L17.5 12.5V13.5M13.5 17.5C14.9001 17.5 15.6002 17.5 16.135 17.2275C16.6054 16.9878 16.9878 16.6054 17.2275 16.135C17.5 15.6002 17.5 14.9001 17.5 13.5M13.5 17.5H6.5C5.09987 17.5 4.3998 17.5 3.86502 17.2275C3.39462 16.9878 3.01217 16.6054 2.77248 16.135C2.5 15.6002 2.5 14.9001 2.5 13.5V6.5C2.5 5.09987 2.5 4.3998 2.77248 3.86502C3.01217 3.39462 3.39462 3.01217 3.86502 2.77248C4.3998 2.5 5.09987 2.5 6.5 2.5H13.5C14.9001 2.5 15.6002 2.5 16.135 2.77248C16.6054 3.01217 16.9878 3.39462 17.2275 3.86502C17.5 4.3998 17.5 5.09987 17.5 6.5V13.5M8.75 7.08333C8.75 8.00381 8.00381 8.75 7.08333 8.75C6.16286 8.75 5.41667 8.00381 5.41667 7.08333C5.41667 6.16286 6.16286 5.41667 7.08333 5.41667C8.00381 5.41667 8.75 6.16286 8.75 7.08333Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_818_19240)">
<path d="M13.3334 6.66745V10.8341C13.3334 11.4972 13.5968 12.133 14.0656 12.6019C14.5344 13.0707 15.1703 13.3341 15.8334 13.3341C16.4964 13.3341 17.1323 13.0707 17.6011 12.6019C18.07 12.133 18.3334 11.4972 18.3334 10.8341V10.0008C18.3332 8.11998 17.6969 6.29452 16.5278 4.82123C15.3586 3.34794 13.7255 2.31347 11.8939 1.88603C10.0623 1.45859 8.13997 1.66332 6.43949 2.46692C4.739 3.27053 3.36036 4.62575 2.52774 6.31222C1.69513 7.99869 1.4575 9.91723 1.8535 11.7559C2.2495 13.5945 3.25584 15.2451 4.70889 16.4393C6.16193 17.6335 7.97622 18.3011 9.85675 18.3334C11.7373 18.3657 13.5735 17.761 15.0667 16.6175M13.3334 10.0008C13.3334 11.8417 11.841 13.3341 10 13.3341C8.15908 13.3341 6.6667 11.8417 6.6667 10.0008C6.6667 8.15984 8.15908 6.66745 10 6.66745C11.841 6.66745 13.3334 8.15984 13.3334 10.0008Z" stroke="var(--Text-Gray-500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</g>
</svg>
</div>
</div>
<div className="p-2.5 bg-Text-Gray-300 rounded-[999px] flex justify-start items-center gap-2.5 overflow-hidden">
<div className="relative">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 13.3346V2.66797M8 2.66797L4 6.66797M8 2.66797L12 6.66797" stroke="var(--Text-White-00, #FDFDFD)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default ChatLight;