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:
@@ -1,106 +1,225 @@
|
||||
import React from 'react';
|
||||
import { EmployeeQuestion } from '../../employeeQuestions';
|
||||
import { QuestionInput } from '../ui/QuestionInput';
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
interface EnhancedFigmaQuestionProps {
|
||||
questionNumber?: string | number;
|
||||
question: EmployeeQuestion;
|
||||
answer?: string;
|
||||
onAnswerChange?: (value: string) => void;
|
||||
interface FigmaQuestionProps {
|
||||
question: string;
|
||||
description?: string;
|
||||
children: ReactNode;
|
||||
onBack?: () => void;
|
||||
onNext?: () => void;
|
||||
showNavigation?: boolean;
|
||||
nextLabel?: string;
|
||||
backLabel?: string;
|
||||
nextDisabled?: boolean;
|
||||
backDisabled?: boolean;
|
||||
nextText?: string;
|
||||
backText?: string;
|
||||
showBackButton?: boolean;
|
||||
currentStep?: number;
|
||||
totalSteps?: number;
|
||||
stepTitle?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const EnhancedFigmaQuestion: React.FC<EnhancedFigmaQuestionProps> = ({
|
||||
questionNumber = 'Q',
|
||||
export const EnhancedFigmaQuestion: React.FC<FigmaQuestionProps> = ({
|
||||
question,
|
||||
answer = '',
|
||||
onAnswerChange,
|
||||
description,
|
||||
children,
|
||||
onBack,
|
||||
onNext,
|
||||
showNavigation = true,
|
||||
nextLabel = 'Next',
|
||||
backLabel = 'Back',
|
||||
className = ''
|
||||
nextDisabled = false,
|
||||
backDisabled = false,
|
||||
nextText = "Next",
|
||||
backText = "Back",
|
||||
showBackButton = true,
|
||||
currentStep = 1,
|
||||
totalSteps = 8,
|
||||
stepTitle = "Company Overview & Mission.",
|
||||
className = ""
|
||||
}) => {
|
||||
// Generate the progress indicator dots
|
||||
const renderProgressDots = () => {
|
||||
const dots = [];
|
||||
for (let i = 0; i < totalSteps; i++) {
|
||||
if (i < currentStep - 1) {
|
||||
// Completed steps - elongated orange
|
||||
dots.push(
|
||||
<div key={i} className="w-6 h-1 bg-Brand-Orange rounded-3xl" />
|
||||
);
|
||||
} else if (i === currentStep - 1) {
|
||||
// Current step - elongated orange
|
||||
dots.push(
|
||||
<div key={i} className="w-6 h-1 bg-Brand-Orange rounded-3xl" />
|
||||
);
|
||||
} else {
|
||||
// Future steps - small gray circles
|
||||
dots.push(
|
||||
<div key={i} data-svg-wrapper>
|
||||
<svg width="4" height="4" viewBox="0 0 4 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="4" height="4" rx="2" fill="var(--Neutrals-NeutralSlate300, #D5D7DA)" />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
return dots;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`w-[1440px] h-[810px] py-6 relative bg-Neutrals-NeutralSlate0 inline-flex flex-col justify-center items-center gap-9 ${className}`}>
|
||||
<div className="w-full max-w-[464px] min-w-[464px] flex flex-col justify-start items-start gap-12">
|
||||
<div className="self-stretch flex flex-col justify-start items-start gap-8">
|
||||
<div className="self-stretch text-center justify-start text-Neutrals-NeutralSlate950 text-2xl font-medium font-['Neue_Montreal'] leading-normal">
|
||||
{question}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
<div className="self-stretch inline-flex justify-start items-start gap-2">
|
||||
{showBackButton && (
|
||||
<div
|
||||
data-property-1="Secondary"
|
||||
data-show-icon-left="false"
|
||||
data-show-icon-right="false"
|
||||
data-show-text="true"
|
||||
data-size="Big"
|
||||
className={`h-12 px-8 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] flex justify-center items-center gap-1 overflow-hidden ${backDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-Neutrals-NeutralSlate200'}`}
|
||||
onClick={!backDisabled ? onBack : undefined}
|
||||
>
|
||||
<div className="px-1 flex justify-center items-center">
|
||||
<div className="justify-center text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">
|
||||
{backText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
data-property-1="Primiary"
|
||||
data-show-icon-left="false"
|
||||
data-show-icon-right="false"
|
||||
data-show-text="true"
|
||||
data-size="Big"
|
||||
className={`flex-1 h-12 px-4 py-3.5 bg-Brand-Orange rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 flex justify-center items-center gap-1 overflow-hidden ${nextDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:opacity-90'}`}
|
||||
onClick={!nextDisabled ? onNext : undefined}
|
||||
>
|
||||
<div className="px-1 flex justify-center items-center">
|
||||
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">
|
||||
{nextText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Step indicator - top left */}
|
||||
<div className="px-3 py-1.5 left-[24px] top-[24px] absolute bg-Neutrals-NeutralSlate100 rounded-[50px] inline-flex justify-center items-center gap-2 overflow-hidden">
|
||||
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] uppercase leading-none">
|
||||
{currentStep} of {totalSteps}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Skip button - top right */}
|
||||
<div className="px-3 py-1.5 left-[1363px] top-[24px] absolute bg-Neutrals-NeutralSlate100 rounded-[50px] inline-flex justify-center items-center gap-2 overflow-hidden cursor-pointer hover:bg-Neutrals-NeutralSlate200">
|
||||
<div className="justify-start text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-none">
|
||||
Skip
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress indicator and title - top center */}
|
||||
<div className="w-[464px] max-w-[464px] min-w-[464px] left-[488px] top-[24px] absolute flex flex-col justify-start items-center gap-4">
|
||||
<div className="p-4 bg-Neutrals-NeutralSlate100 rounded-[50px] inline-flex justify-center items-center gap-2 overflow-hidden">
|
||||
{renderProgressDots()}
|
||||
</div>
|
||||
<div className="self-stretch text-center justify-start text-Neutrals-NeutralSlate500 text-base font-medium font-['Neue_Montreal'] leading-normal">
|
||||
{stepTitle}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Question Card Component (for Q&A style layout)
|
||||
interface FigmaQuestionCardProps {
|
||||
question: string;
|
||||
description?: string;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const FigmaQuestionCard: React.FC<FigmaQuestionCardProps> = ({
|
||||
question,
|
||||
description,
|
||||
children,
|
||||
className = ""
|
||||
}) => {
|
||||
return (
|
||||
<div className={`w-full max-w-[600px] px-5 pt-5 pb-6 bg-white dark:bg-gray-800 rounded-2xl border border-gray-200 dark:border-gray-700 inline-flex flex-col justify-end items-end gap-4 ${className}`}>
|
||||
{/* Question Header */}
|
||||
<div className={`w-full px-5 pt-5 pb-6 bg-Other-White rounded-2xl outline outline-1 outline-offset-[-1px] outline-Neutrals-NeutralSlate200 inline-flex flex-col justify-end items-end gap-4 ${className}`}>
|
||||
<div className="self-stretch inline-flex justify-start items-start gap-3">
|
||||
<div className="justify-start text-gray-400 text-xl font-medium font-['Inter'] leading-loose">
|
||||
{questionNumber}
|
||||
</div>
|
||||
<div className="justify-start text-zinc-300 text-xl font-medium font-['Inter'] leading-loose">Q</div>
|
||||
<div className="flex-1 inline-flex flex-col justify-start items-start gap-2">
|
||||
<div className="self-stretch justify-start text-[--text-primary] text-xl font-semibold font-['Inter'] leading-loose">
|
||||
{question.prompt}
|
||||
</div>
|
||||
<div className="self-stretch justify-start text-[--text-secondary] text-sm font-normal font-['Inter'] leading-tight">
|
||||
{question.required ? 'Required' : 'Optional'} • {question.category}
|
||||
{question.type && ` • ${question.type}`}
|
||||
<div className="self-stretch justify-start text-Neutrals-NeutralSlate950 text-xl font-semibold font-['Inter'] leading-loose">
|
||||
{question}
|
||||
</div>
|
||||
{description && (
|
||||
<div className="self-stretch justify-start text-Neutrals-NeutralSlate500 text-sm font-normal font-['Inter'] leading-tight">
|
||||
{description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Separator */}
|
||||
<div className="self-stretch h-px bg-gray-200 dark:bg-gray-700"></div>
|
||||
|
||||
{/* Answer Section */}
|
||||
<div className="self-stretch inline-flex justify-start items-start gap-3">
|
||||
<div className="justify-start text-gray-400 text-xl font-medium font-['Inter'] leading-loose">A</div>
|
||||
<div className="self-stretch h-0 rotate-90 shadow-[0px_1.5px_1.5px_0px_rgba(255,255,255,1.00)] outline outline-1 outline-offset-[-0.50px] border-Neutrals-NeutralSlate200" />
|
||||
<div className="self-stretch inline-flex justify-start items-center gap-3">
|
||||
<div className="justify-start text-zinc-300 text-xl font-medium font-['Inter'] leading-loose">A</div>
|
||||
<div className="flex-1">
|
||||
<QuestionInput
|
||||
question={question}
|
||||
value={answer}
|
||||
onChange={onAnswerChange || (() => { })}
|
||||
className="border-0 bg-transparent focus:ring-0 p-0"
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
{/* Navigation */}
|
||||
{showNavigation && (
|
||||
<div className="inline-flex justify-start items-center gap-3">
|
||||
{onBack && (
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="px-4 py-3.5 bg-gray-100 dark:bg-gray-700 rounded-full flex justify-center items-center gap-1 overflow-hidden hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
<div className="relative">
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13 15L8 10L13 5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="px-1 flex justify-center items-center">
|
||||
<div className="justify-center text-[--text-primary] text-sm font-medium font-['Inter'] leading-tight">
|
||||
{backLabel}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
// Enhanced input that matches Figma designs
|
||||
interface EnhancedFigmaInputProps {
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
multiline?: boolean;
|
||||
rows?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
{onNext && (
|
||||
<button
|
||||
onClick={onNext}
|
||||
className="px-4 py-3.5 bg-blue-500 rounded-full border-2 border-blue-400 flex justify-center items-center gap-1 overflow-hidden hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
<div className="px-1 flex justify-center items-center">
|
||||
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">
|
||||
{nextLabel}
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 15L13 10L8 5" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
export const EnhancedFigmaInput: React.FC<EnhancedFigmaInputProps> = ({
|
||||
placeholder = "Type your answer....",
|
||||
value = "",
|
||||
onChange,
|
||||
multiline = false,
|
||||
rows = 4,
|
||||
className = ""
|
||||
}) => {
|
||||
const baseClasses = "self-stretch min-h-40 p-5 relative bg-Neutrals-NeutralSlate100 rounded-xl inline-flex justify-start items-start gap-2.5 overflow-hidden";
|
||||
const inputClasses = "flex-1 justify-start text-Neutrals-NeutralSlate500 text-base font-normal font-['Inter'] leading-normal bg-transparent border-none outline-none resize-none";
|
||||
|
||||
if (multiline) {
|
||||
return (
|
||||
<div className={`${baseClasses} ${className}`}>
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={(e) => onChange?.(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
rows={rows}
|
||||
className={inputClasses}
|
||||
/>
|
||||
<div className="w-3 h-3 absolute right-[18px] bottom-[18px]">
|
||||
<div className="w-2 h-2 left-[2px] top-[2px] absolute outline outline-1 outline-offset-[-0.50px] outline-Neutrals-NeutralSlate500" />
|
||||
<div className="w-1 h-1 left-[7px] top-[7px] absolute outline outline-1 outline-offset-[-0.50px] outline-Neutrals-NeutralSlate500" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${baseClasses} ${className}`}>
|
||||
<input
|
||||
value={value}
|
||||
onChange={(e) => onChange?.(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
className={inputClasses}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user