Fix organization setup flow: redirect to onboarding for incomplete setup

This commit is contained in:
Ra
2025-08-18 10:33:45 -07:00
commit 557b113196
60 changed files with 16246 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
import React from 'react';
import { EmployeeQuestion } from '../../employeeQuestions';
import { QuestionInput } from '../ui/QuestionInput';
interface EnhancedFigmaQuestionProps {
questionNumber?: string | number;
question: EmployeeQuestion;
answer?: string;
onAnswerChange?: (value: string) => void;
onBack?: () => void;
onNext?: () => void;
showNavigation?: boolean;
nextLabel?: string;
backLabel?: string;
className?: string;
}
export const EnhancedFigmaQuestion: React.FC<EnhancedFigmaQuestionProps> = ({
questionNumber = 'Q',
question,
answer = '',
onAnswerChange,
onBack,
onNext,
showNavigation = true,
nextLabel = 'Next',
backLabel = 'Back',
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="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="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>
</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="flex-1">
<QuestionInput
question={question}
value={answer}
onChange={onAnswerChange || (() => { })}
className="border-0 bg-transparent focus:ring-0 p-0"
/>
</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>
)}
{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>
)}
</div>
)}
</div>
);
};
export default EnhancedFigmaQuestion;

View File

@@ -0,0 +1,50 @@
import React from 'react';
// Figma-based Alert component with proper CSS variables and styling
interface FigmaAlertProps {
title: string;
variant?: 'success' | 'error' | 'warning' | 'info';
children?: React.ReactNode;
onClose?: () => void;
className?: string;
}
export const FigmaAlert: React.FC<FigmaAlertProps> = ({
title,
variant = 'info',
children,
onClose,
className = ''
}) => {
const getBorderColor = () => {
switch (variant) {
case 'success': return 'bg-Other-Green';
case 'error': return 'bg-red-500';
case 'warning': return 'bg-yellow-500';
default: return 'bg-blue-500';
}
};
return (
<div className={`p-4 relative bg-Other-White rounded-lg shadow-[0px_2px_2px_-1px_rgba(10,13,18,0.04)] shadow-[0px_4px_6px_-2px_rgba(10,13,18,0.03)] shadow-[0px_12px_16px_-4px_rgba(10,13,18,0.08)] outline outline-1 outline-offset-[-1px] outline-Neutrals-NeutralSlate200 inline-flex justify-center items-center gap-2.5 overflow-hidden ${className}`}>
<div className="w-96 max-w-96 justify-start text-Neutrals-NeutralSlate950 text-sm font-medium font-['Inter'] leading-tight">
{title}
{children && <div className="mt-1 text-xs text-Neutrals-NeutralSlate600">{children}</div>}
</div>
{onClose && (
<button onClick={onClose} className="flex-shrink-0">
<div data-svg-wrapper className="relative">
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6663 5.83325L6.33301 14.1666M6.33301 5.83325L14.6663 14.1666" stroke="var(--Neutrals-NeutralSlate600, #535862)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</button>
)}
<div className={`w-2 h-32 left-[-4px] top-[-41px] absolute ${getBorderColor()}`} />
</div>
);
};
export default FigmaAlert;

View File

@@ -0,0 +1,76 @@
import React from 'react';
interface FigmaInputProps {
label?: string;
placeholder?: string;
type?: string;
value?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
icon?: React.ReactNode;
buttonText?: string;
onButtonClick?: () => void;
className?: string;
required?: boolean;
}
export const FigmaInput: React.FC<FigmaInputProps> = ({
label = 'Email',
placeholder = 'Enter your email',
type = 'text',
value,
onChange,
icon,
buttonText,
onButtonClick,
className = '',
required = false
}) => {
return (
<div className={`w-[464px] inline-flex flex-col justify-start items-start gap-2 ${className}`}>
{label && (
<div className="self-stretch inline-flex justify-start items-center gap-0.5">
<div className="justify-start text-Neutrals-NeutralSlate800 text-sm font-medium font-['Inter'] leading-tight">
{label} {required && <span className="text-red-500">*</span>}
</div>
</div>
)}
<div className="self-stretch inline-flex justify-start items-start gap-2">
<div className="flex-1 px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] flex justify-start items-center gap-2 overflow-hidden">
{icon && (
<div data-svg-wrapper className="relative">
{icon}
</div>
)}
<input
type={type}
value={value}
onChange={onChange}
placeholder={placeholder}
className="flex-1 bg-transparent outline-none text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight placeholder:text-Neutrals-NeutralSlate500"
/>
</div>
{buttonText && (
<button
onClick={onButtonClick}
className="w-32 max-w-32 px-4 py-3.5 bg-Neutrals-NeutralSlate100 rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-Neutrals-NeutralSlate200 transition-colors"
>
<div className="justify-center text-Neutrals-NeutralSlate500 text-sm font-medium font-['Inter'] leading-tight">
{buttonText}
</div>
</button>
)}
</div>
</div>
);
};
// Email icon component for convenience
export const EmailIcon: React.FC = () => (
<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="var(--Neutrals-NeutralSlate500, #717680)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
export default FigmaInput;

View File

@@ -0,0 +1,71 @@
import React from 'react';
interface ProgressStepProps {
number: number;
title: string;
isActive?: boolean;
isCompleted?: boolean;
}
interface FigmaProgressProps {
steps: ProgressStepProps[];
currentStep?: number;
className?: string;
}
const ProgressStep: React.FC<ProgressStepProps> = ({ number, title, isActive = false, isCompleted = false }) => {
const stepClasses = isActive
? "p-2 bg-Main-BG-Gray-50 rounded-[10px] shadow-[0px_1px_2px_0px_rgba(10,13,20,0.03)]"
: "p-2 bg-Other-White rounded-[10px]";
const numberClasses = isActive || isCompleted
? "h-5 p-0.5 bg-Brand-Orange rounded-[999px]"
: "h-5 p-0.5 bg-bg-white-0 rounded-[999px] outline outline-1 outline-offset-[-1px] outline-Neutrals-NeutralSlate200";
const numberTextClasses = isActive || isCompleted
? "w-4 text-center justify-start text-Neutrals-NeutralSlate0 text-xs font-medium font-['Inter'] leading-none"
: "w-4 text-center justify-start text-Neutrals-NeutralSlate600 text-xs font-medium font-['Inter'] leading-none";
const titleClasses = isActive
? "flex-1 justify-start text-Neutrals-NeutralSlate950 text-sm font-normal font-['Inter'] leading-tight"
: "flex-1 justify-start text-Neutrals-NeutralSlate600 text-sm font-normal font-['Inter'] leading-tight";
return (
<div className={`self-stretch inline-flex justify-start items-center gap-2.5 overflow-hidden ${stepClasses}`}>
<div className={`inline-flex flex-col justify-center items-center gap-0.5 overflow-hidden ${numberClasses}`}>
<div className={numberTextClasses}>{number}</div>
</div>
<div className={titleClasses}>{title}</div>
</div>
);
};
export const FigmaProgress: React.FC<FigmaProgressProps> = ({ steps, currentStep = 1, className = '' }) => {
return (
<div className={`self-stretch inline-flex flex-col justify-start items-start gap-2 ${className}`}>
{steps.map((step, index) => (
<ProgressStep
key={index}
number={step.number}
title={step.title}
isActive={step.number === currentStep}
isCompleted={step.number < currentStep}
/>
))}
</div>
);
};
// Default onboarding steps as shown in Figma
export const defaultOnboardingSteps: ProgressStepProps[] = [
{ number: 1, title: "Company Overview & Vision" },
{ number: 2, title: "Leadership & Organizational Structure" },
{ number: 3, title: "Operations & Execution" },
{ number: 4, title: "Culture & Team Health" },
{ number: 5, title: "Sales, Marketing & Growth" },
{ number: 6, title: "Financial Health & Metrics" },
{ number: 7, title: "Innovation & Product/Service Strategy" },
{ number: 8, title: "Personal Leadership & Risk" }
];
export default FigmaProgress;

View File

@@ -0,0 +1,127 @@
import React from 'react';
interface FigmaQuestionProps {
questionNumber?: string | number;
title: string;
description?: string;
answer?: string;
onAnswerChange?: (value: string) => void;
onBack?: () => void;
onNext?: () => void;
showNavigation?: boolean;
nextLabel?: string;
backLabel?: string;
className?: string;
}
export const FigmaQuestion: React.FC<FigmaQuestionProps> = ({
questionNumber = 'Q',
title,
description,
answer = '',
onAnswerChange,
onBack,
onNext,
showNavigation = true,
nextLabel = 'Next',
backLabel = 'Back',
className = ''
}) => {
return (
<div className={`w-[600px] 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}`}>
{/* Question Header */}
<div className="self-stretch inline-flex justify-start items-start gap-3">
<div className="justify-start text-zinc-300 text-xl font-medium font-['Inter'] leading-loose">
{questionNumber}
</div>
<div className="flex-1 inline-flex flex-col justify-start items-start gap-2">
<div className="self-stretch justify-start text-Neutrals-NeutralSlate950 text-xl font-semibold font-['Inter'] leading-loose">
{title}
</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 data-svg-wrapper>
<svg width="563" height="5" viewBox="0 0 563 5" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_37_3168)">
<path d="M1.5 1L561.5 1" stroke="var(--Neutrals-NeutralSlate200, #E9EAEB)" />
</g>
<defs>
<filter id="filter0_d_37_3168" x="0" y="0.5" width="563" height="4" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="1.5" />
<feGaussianBlur stdDeviation="0.75" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_3168" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_3168" result="shape" />
</filter>
</defs>
</svg>
</div>
{/* Answer Section */}
<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">
<textarea
value={answer}
onChange={(e) => onAnswerChange?.(e.target.value)}
placeholder="Type your answer...."
className="w-full bg-transparent outline-none resize-none text-Neutrals-NeutralSlate950 text-base font-normal font-['Inter'] leading-normal placeholder:text-Neutrals-NeutralSlate500 min-h-[100px]"
/>
</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-Neutrals-NeutralSlate100 rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-Neutrals-NeutralSlate200 transition-colors"
>
<div data-svg-wrapper 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="var(--Neutrals-NeutralSlate950, #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">
{backLabel}
</div>
</div>
</button>
)}
{onNext && (
<button
onClick={onNext}
className="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 hover:bg-orange-600 transition-colors"
>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">
{nextLabel}
</div>
</div>
<div data-svg-wrapper 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="var(--Neutrals-NeutralSlate0, #FDFDFD)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</button>
)}
</div>
)}
</div>
);
};
export default FigmaQuestion;