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:
118
components/chat/MessageThread.tsx
Normal file
118
components/chat/MessageThread.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import React from 'react';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
text: string;
|
||||
isUser: boolean;
|
||||
timestamp: number;
|
||||
files?: string[];
|
||||
}
|
||||
|
||||
interface MessageBubbleProps {
|
||||
message: Message;
|
||||
}
|
||||
|
||||
const MessageBubble: React.FC<MessageBubbleProps> = ({ message }) => {
|
||||
const formatTime = (timestamp: number) => {
|
||||
return new Date(timestamp).toLocaleTimeString('en-US', {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
if (message.isUser) {
|
||||
return (
|
||||
<div className="flex justify-end mb-4">
|
||||
<div className="max-w-[70%] flex flex-col items-end">
|
||||
<div className="bg-Brand-Orange text-white px-4 py-3 rounded-2xl rounded-br-md">
|
||||
{message.files && message.files.length > 0 && (
|
||||
<div className="mb-2 flex flex-wrap gap-2">
|
||||
{message.files.map((file, index) => (
|
||||
<div key={index} className="px-2 py-1 bg-white/20 rounded text-xs">
|
||||
📎 {file}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-sm leading-relaxed">{message.text}</div>
|
||||
</div>
|
||||
<div className="text-xs text-Neutrals-NeutralSlate400 mt-1">
|
||||
{formatTime(message.timestamp)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-start mb-4">
|
||||
<div className="max-w-[85%] flex items-start gap-3">
|
||||
{/* AI Avatar */}
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-Brand-Orange to-orange-600 rounded-full flex items-center justify-center flex-shrink-0 mt-1">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 2C8.73438 2 9.375 2.64062 9.375 3.375V4.5C9.375 5.23438 8.73438 5.875 8 5.875C7.26562 5.875 6.625 5.23438 6.625 4.5V3.375C6.625 2.64062 7.26562 2 8 2ZM8 10.125C8.73438 10.125 9.375 10.7656 9.375 11.5V12.625C9.375 13.3594 8.73438 14 8 14C7.26562 14 6.625 13.3594 6.625 12.625V11.5C6.625 10.7656 7.26562 10.125 8 10.125ZM12.625 6.625C13.3594 6.625 14 7.26562 14 8C14 8.73438 13.3594 9.375 12.625 9.375H11.5C10.7656 9.375 10.125 8.73438 10.125 8C10.125 7.26562 10.7656 6.625 11.5 6.625H12.625ZM5.875 8C5.875 8.73438 5.23438 9.375 4.5 9.375H3.375C2.64062 9.375 2 8.73438 2 8C2 7.26562 2.64062 6.625 3.375 6.625H4.5C5.23438 6.625 5.875 7.26562 5.875 8Z" fill="white" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<div className="bg-Neutrals-NeutralSlate100 text-Neutrals-NeutralSlate950 px-4 py-3 rounded-2xl rounded-bl-md">
|
||||
<div className="text-sm leading-relaxed whitespace-pre-wrap">{message.text}</div>
|
||||
</div>
|
||||
<div className="text-xs text-Neutrals-NeutralSlate400 mt-1">
|
||||
AI • {formatTime(message.timestamp)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface LoadingIndicatorProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({ className = '' }) => (
|
||||
<div className={`flex justify-start mb-4 ${className}`}>
|
||||
<div className="flex items-start gap-3">
|
||||
{/* AI Avatar */}
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-Brand-Orange to-orange-600 rounded-full flex items-center justify-center flex-shrink-0 mt-1">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 2C8.73438 2 9.375 2.64062 9.375 3.375V4.5C9.375 5.23438 8.73438 5.875 8 5.875C7.26562 5.875 6.625 5.23438 6.625 4.5V3.375C6.625 2.64062 7.26562 2 8 2ZM8 10.125C8.73438 10.125 9.375 10.7656 9.375 11.5V12.625C9.375 13.3594 8.73438 14 8 14C7.26562 14 6.625 13.3594 6.625 12.625V11.5C6.625 10.7656 7.26562 10.125 8 10.125ZM12.625 6.625C13.3594 6.625 14 7.26562 14 8C14 8.73438 13.3594 9.375 12.625 9.375H11.5C10.7656 9.375 10.125 8.73438 10.125 8C10.125 7.26562 10.7656 6.625 11.5 6.625H12.625ZM5.875 8C5.875 8.73438 5.23438 9.375 4.5 9.375H3.375C2.64062 9.375 2 8.73438 2 8C2 7.26562 2.64062 6.625 3.375 6.625H4.5C5.23438 6.625 5.875 7.26562 5.875 8Z" fill="white" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="bg-Neutrals-NeutralSlate100 px-4 py-3 rounded-2xl rounded-bl-md">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-Neutrals-NeutralSlate400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }} />
|
||||
<div className="w-2 h-2 bg-Neutrals-NeutralSlate400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }} />
|
||||
<div className="w-2 h-2 bg-Neutrals-NeutralSlate400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
interface MessageThreadProps {
|
||||
messages: Message[];
|
||||
isLoading?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const MessageThread: React.FC<MessageThreadProps> = ({
|
||||
messages,
|
||||
isLoading = false,
|
||||
className = ''
|
||||
}) => {
|
||||
return (
|
||||
<div className={`flex flex-col ${className}`}>
|
||||
{messages.map((message) => (
|
||||
<MessageBubble key={message.id} message={message} />
|
||||
))}
|
||||
|
||||
{isLoading && <LoadingIndicator />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageThread;
|
||||
export { MessageBubble, LoadingIndicator };
|
||||
Reference in New Issue
Block a user