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

@@ -0,0 +1,171 @@
import React, { useState, useEffect, useRef } from 'react';
import { useOrg } from '../../contexts/OrgContext';
import { Employee } from '../../types';
import ChatSidebar from './ChatSidebar';
import MessageThread from './MessageThread';
import FileUploadInput from './FileUploadInput';
interface Message {
id: string;
text: string;
isUser: boolean;
timestamp: number;
files?: string[];
}
interface ChatLayoutProps {
children?: React.ReactNode;
}
const ChatLayout: React.FC<ChatLayoutProps> = ({ children }) => {
const { employees } = useOrg();
const [selectedEmployees, setSelectedEmployees] = useState<Employee[]>([]);
const [messages, setMessages] = useState<Message[]>([]);
const [inputValue, setInputValue] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
const messagesEndRef = useRef<HTMLDivElement>(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToBottom();
}, [messages]);
const handleNavigation = (page: string) => {
// Handle navigation to different pages
console.log('Navigate to:', page);
};
const handleSendMessage = async () => {
if (!inputValue.trim() && uploadedFiles.length === 0) return;
const userMessage: Message = {
id: Date.now().toString(),
text: inputValue,
isUser: true,
timestamp: Date.now(),
files: uploadedFiles.length > 0 ? [...uploadedFiles] : undefined
};
setMessages(prev => [...prev, userMessage]);
setInputValue('');
setUploadedFiles([]);
setIsLoading(true);
// Simulate AI response
setTimeout(() => {
const aiMessage: Message = {
id: (Date.now() + 1).toString(),
text: "I understand you're asking about the employee data. Based on the information provided, I can help analyze the performance metrics and provide insights.\n\nHere are some key findings from your team's data:\n\n• **Performance Trends**: Overall team productivity has increased by 15% this quarter\n• **Cultural Health**: Employee satisfaction scores are above industry average\n• **Areas for Growth**: Communication and cross-team collaboration could be improved\n\nWould you like me to dive deeper into any of these areas?",
isUser: false,
timestamp: Date.now()
};
setMessages(prev => [...prev, aiMessage]);
setIsLoading(false);
}, 2000);
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSendMessage();
}
};
const handleRemoveFile = (index: number) => {
setUploadedFiles(prev => prev.filter((_, i) => i !== index));
};
const handleFilesSelected = (files: File[]) => {
// For demo purposes, we'll just add the file names
// In a real implementation, you'd upload the files and get URLs back
const fileNames = files.map(file => file.name);
setUploadedFiles(prev => [...prev, ...fileNames]);
};
const hasMessages = messages.length > 0;
return (
<div className="w-full h-screen bg-Neutrals-NeutralSlate0 inline-flex overflow-hidden">
{/* Sidebar */}
<ChatSidebar currentPage="chat" onNavigate={handleNavigation} />
{/* Main Content Area */}
<div className="flex-1 flex flex-col overflow-hidden">
{/* Header with Employee Selection */}
<div className="px-6 py-4 bg-Neutrals-NeutralSlate0 border-b border-Neutrals-NeutralSlate200 flex justify-between items-center">
<div className="flex items-center gap-3">
<h1 className="text-xl font-semibold text-Neutrals-NeutralSlate950">Chat</h1>
{selectedEmployees.length > 0 && (
<div className="flex items-center gap-2">
<span className="text-sm text-Neutrals-NeutralSlate500">Analyzing:</span>
<div className="flex items-center gap-1">
{selectedEmployees.slice(0, 3).map((emp, index) => (
<div key={emp.id} className="px-2 py-1 bg-Brand-Orange/10 rounded-full text-xs text-Brand-Orange">
{emp.name}
</div>
))}
{selectedEmployees.length > 3 && (
<div className="px-2 py-1 bg-Neutrals-NeutralSlate100 rounded-full text-xs text-Neutrals-NeutralSlate600">
+{selectedEmployees.length - 3} more
</div>
)}
</div>
</div>
)}
</div>
</div>
{/* Messages Area */}
<div className="flex-1 overflow-y-auto px-6 py-4">
{hasMessages ? (
<div className="max-w-4xl mx-auto">
<MessageThread
messages={messages}
isLoading={isLoading}
/>
<div ref={messagesEndRef} />
</div>
) : (
children
)}
</div>
{/* Input Area */}
<div className="px-6 py-4 bg-Neutrals-NeutralSlate0 border-t border-Neutrals-NeutralSlate200">
<div className="max-w-4xl mx-auto">
<div className="flex items-end gap-3">
<FileUploadInput
value={inputValue}
onChange={setInputValue}
onKeyDown={handleKeyPress}
placeholder="Ask about your team's performance, culture, or any insights..."
disabled={isLoading}
uploadedFiles={uploadedFiles}
onRemoveFile={handleRemoveFile}
onFilesSelected={handleFilesSelected}
/>
{/* Send Button */}
<button
onClick={handleSendMessage}
disabled={!inputValue.trim() && uploadedFiles.length === 0}
className="px-4 py-3 bg-Brand-Orange text-white rounded-xl hover:bg-orange-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex-shrink-0"
>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.3346 1.66797L9.16797 10.8346M18.3346 1.66797L12.5013 18.3346L9.16797 10.8346M18.3346 1.66797L1.66797 7.5013L9.16797 10.8346" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default ChatLayout;