619 lines
36 KiB
TypeScript
619 lines
36 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { useNavigate, useLocation, useParams } from 'react-router-dom';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import { useOrg } from '../contexts/OrgContext';
|
|
import { EMPLOYEE_QUESTIONS, EmployeeSubmissionAnswers } from '../employeeQuestions';
|
|
import { API_URL } from '../constants';
|
|
import { FigmaRatingScale, FigmaTextArea, FigmaNavigationButtons } from '../components/figma/FigmaQuestion';
|
|
import { FigmaMultipleChoice } from '../components/figma/FigmaMultipleChoice';
|
|
|
|
// Icon SVG Component - From EmployeeFormsController
|
|
const AuditlyIcon: React.FC = () => (
|
|
<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>
|
|
);
|
|
|
|
// Section Intro Component - From EmployeeFormsController
|
|
const SectionIntro: React.FC<{
|
|
sectionNumber: string;
|
|
title: string;
|
|
description: string;
|
|
onStart: () => void;
|
|
imageUrl?: string;
|
|
}> = ({ sectionNumber, title, description, onStart, imageUrl = "https://placehold.co/560x682" }) => {
|
|
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">
|
|
<AuditlyIcon />
|
|
</div>
|
|
</div>
|
|
<div className="self-stretch flex flex-col justify-start items-start gap-4">
|
|
<div className="px-3 py-1.5 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">{sectionNumber}</div>
|
|
</div>
|
|
<div className="self-stretch justify-start text-Neutrals-NeutralSlate800 text-5xl font-medium font-['Neue_Montreal'] leading-[48px]">{title}</div>
|
|
<div className="self-stretch justify-center text-Neutrals-NeutralSlate500 text-base font-normal font-['Inter'] leading-normal">{description}</div>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={onStart}
|
|
className="self-stretch px-4 py-3.5 bg-Brand-Orange rounded-[999px] outline outline-2 outline-offset-[-2px] outline-blue-400 inline-flex justify-center items-center gap-1 overflow-hidden"
|
|
>
|
|
<div className="px-1 flex justify-center items-center">
|
|
<div className="justify-center text-Other-White text-sm font-medium font-['Inter'] leading-tight">Start</div>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 h-[810px] px-20 py-16 flex justify-center items-center gap-2.5 overflow-hidden">
|
|
<div className="flex-1 self-stretch origin-top-left rotate-180 rounded-3xl inline-flex flex-col justify-center items-center gap-2.5 overflow-hidden">
|
|
<img className="self-stretch flex-1" src={imageUrl} alt={title} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// Step 1: Welcome & Role Information - From EmployeeFormsController
|
|
const EmployeeFormStep1: React.FC<{ onNext: (data: any) => void }> = ({ onNext }) => {
|
|
const [formData, setFormData] = useState({
|
|
name: '',
|
|
role: '',
|
|
department: ''
|
|
});
|
|
|
|
const handleSubmit = () => {
|
|
onNext(formData);
|
|
};
|
|
|
|
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">
|
|
<AuditlyIcon />
|
|
</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"
|
|
value={formData.name}
|
|
onChange={(e) => setFormData({ ...formData, name: 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 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"
|
|
value={formData.role}
|
|
onChange={(e) => setFormData({ ...formData, role: 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="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"
|
|
value={formData.department}
|
|
onChange={(e) => setFormData({ ...formData, department: 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="e.g. Engineering, Sales, Marketing"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="self-stretch inline-flex justify-start items-center gap-3">
|
|
<button
|
|
onClick={handleSubmit}
|
|
disabled={!formData.name || !formData.role || !formData.department}
|
|
className="flex-1 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">Continue</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// Main Controller Component with Backend Integration - Merged Logic
|
|
const EmployeeQuestionnaire: React.FC = () => {
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const params = useParams();
|
|
const { user } = useAuth();
|
|
|
|
// Check if this is an invite-based flow (no auth/org needed)
|
|
const inviteCode = params.inviteCode;
|
|
const isInviteFlow = !!inviteCode;
|
|
|
|
// Only use org context for authenticated flows
|
|
let submitEmployeeAnswers, generateEmployeeReport, employees;
|
|
if (!isInviteFlow) {
|
|
const orgContext = useOrg();
|
|
({ submitEmployeeAnswers, generateEmployeeReport, employees } = orgContext);
|
|
} else {
|
|
// For invite flows, we don't need these functions from org context
|
|
submitEmployeeAnswers = null;
|
|
generateEmployeeReport = null;
|
|
employees = [];
|
|
}
|
|
|
|
const [currentStep, setCurrentStep] = useState(1);
|
|
const [formData, setFormData] = useState<any>({});
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [error, setError] = useState('');
|
|
const [inviteEmployee, setInviteEmployee] = useState<any>(null);
|
|
const [isLoadingInvite, setIsLoadingInvite] = useState(false);
|
|
|
|
// Load invite details if this is an invite flow
|
|
useEffect(() => {
|
|
if (inviteCode) {
|
|
loadInviteDetails(inviteCode);
|
|
}
|
|
}, [inviteCode]);
|
|
|
|
const loadInviteDetails = async (code: string) => {
|
|
setIsLoadingInvite(true);
|
|
try {
|
|
const response = await fetch(`${API_URL}/getInvitationStatus?code=${code}`);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
if (data.used) {
|
|
setError('This invitation has already been used');
|
|
} else if (data.employee) {
|
|
setInviteEmployee(data.employee);
|
|
setError('');
|
|
} else {
|
|
setError('Invalid invitation data');
|
|
}
|
|
} else {
|
|
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
setError(errorData.error || 'Invalid or expired invitation link');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error loading invite details:', err);
|
|
setError('Failed to load invitation details');
|
|
} finally {
|
|
setIsLoadingInvite(false);
|
|
}
|
|
};
|
|
|
|
// Get employee info from multiple sources
|
|
const invitedEmployee = location.state?.invitedEmployee;
|
|
|
|
// Determine current employee - for invite flow, use invite employee data
|
|
let currentEmployee;
|
|
if (isInviteFlow) {
|
|
currentEmployee = inviteEmployee;
|
|
} else {
|
|
// Original auth-based logic
|
|
currentEmployee = invitedEmployee || employees.find(emp => emp.email === user?.email);
|
|
|
|
if (!currentEmployee && user?.email) {
|
|
// Try case-insensitive email matching
|
|
currentEmployee = employees.find(emp =>
|
|
emp.email?.toLowerCase() === user.email?.toLowerCase()
|
|
);
|
|
|
|
if (!currentEmployee && invitedEmployee) {
|
|
currentEmployee = employees.find(emp =>
|
|
emp.name === invitedEmployee.name || emp.id === invitedEmployee.id
|
|
);
|
|
}
|
|
}
|
|
|
|
// Demo mode fallbacks
|
|
if (!currentEmployee && user?.email === 'demo@auditly.local' && employees.length > 0) {
|
|
currentEmployee = employees[employees.length - 1];
|
|
}
|
|
|
|
if (!currentEmployee && employees.length === 1) {
|
|
currentEmployee = employees[0];
|
|
}
|
|
}
|
|
|
|
const submitViaInvite = async (answers: EmployeeSubmissionAnswers, inviteCode: string) => {
|
|
try {
|
|
// First, consume the invite to mark it as used
|
|
const consumeResponse = await fetch(`${API_URL}/consumeInvitation`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ code: inviteCode })
|
|
});
|
|
|
|
if (!consumeResponse.ok) {
|
|
throw new Error('Failed to process invitation');
|
|
}
|
|
|
|
// Get orgId from the consume response
|
|
const consumeData = await consumeResponse.json();
|
|
const orgId = consumeData.orgId;
|
|
|
|
// Submit the questionnaire answers using Cloud Function
|
|
const submitResponse = await fetch(`${API_URL}/submitEmployeeAnswers`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
inviteCode: inviteCode,
|
|
answers: answers,
|
|
orgId: orgId
|
|
})
|
|
});
|
|
|
|
if (!submitResponse.ok) {
|
|
const errorData = await submitResponse.json();
|
|
throw new Error(errorData.error || 'Failed to submit questionnaire');
|
|
}
|
|
|
|
const result = await submitResponse.json();
|
|
return { success: true, reportGenerated: !!result.report };
|
|
} catch (error) {
|
|
console.error('Invite submission error:', error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
setIsSubmitting(true);
|
|
setError('');
|
|
|
|
try {
|
|
// Convert form data to EMPLOYEE_QUESTIONS format for backend
|
|
const answers: EmployeeSubmissionAnswers = {};
|
|
|
|
// Map form data to question IDs
|
|
if (formData.name) answers['full_name'] = formData.name;
|
|
if (formData.email) answers['email'] = formData.email;
|
|
if (formData.company) answers['company_department'] = formData.company;
|
|
if (formData.title_department) answers['title_department'] = formData.title_department;
|
|
|
|
// Add all other form data fields
|
|
Object.keys(formData).forEach(key => {
|
|
if (formData[key] && !answers[key]) {
|
|
answers[key] = formData[key];
|
|
}
|
|
});
|
|
|
|
// Submit answers - different logic for invite vs auth flow
|
|
let result;
|
|
if (isInviteFlow) {
|
|
// Direct API submission for invite flow (no auth needed)
|
|
result = await submitViaInvite(answers, inviteCode);
|
|
} else {
|
|
// Use org context for authenticated flow
|
|
if (!currentEmployee) {
|
|
// Enhanced fallback logic for authenticated users
|
|
if (employees.length > 0) {
|
|
let fallbackEmployee = employees.find(emp =>
|
|
emp.email?.toLowerCase().includes(user?.email?.toLowerCase().split('@')[0] || '')
|
|
);
|
|
|
|
if (!fallbackEmployee) {
|
|
const userDomain = user?.email?.split('@')[1];
|
|
fallbackEmployee = employees.find(emp =>
|
|
emp.email?.split('@')[1] === userDomain
|
|
) || employees[employees.length - 1];
|
|
}
|
|
|
|
const success = await submitEmployeeAnswers(fallbackEmployee.id, answers);
|
|
if (success) {
|
|
try {
|
|
const report = await generateEmployeeReport(fallbackEmployee);
|
|
console.log('Report generated successfully:', report);
|
|
} catch (reportError) {
|
|
console.error('Failed to generate report:', reportError);
|
|
}
|
|
|
|
// Navigate to completion
|
|
setCurrentStep(38); // Thank you page
|
|
return;
|
|
}
|
|
}
|
|
|
|
setError(`We couldn't match your account (${user?.email}) with an employee record. Please contact your administrator.`);
|
|
setIsSubmitting(false);
|
|
return;
|
|
}
|
|
|
|
result = await submitEmployeeAnswers(currentEmployee.id, answers);
|
|
}
|
|
|
|
if (result.success) {
|
|
// Show thank you page
|
|
setCurrentStep(38);
|
|
} else {
|
|
setError(result.message || 'Failed to submit questionnaire');
|
|
}
|
|
} catch (error) {
|
|
console.error('Submission error:', error);
|
|
setError('Failed to submit questionnaire. Please try again.');
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
};
|
|
|
|
const handleNext = (stepData?: any) => {
|
|
if (stepData) {
|
|
const newFormData = { ...formData, ...stepData };
|
|
setFormData(newFormData);
|
|
}
|
|
|
|
if (currentStep === 37) {
|
|
// Submit form data here
|
|
handleSubmit();
|
|
} else {
|
|
setCurrentStep(currentStep + 1);
|
|
}
|
|
};
|
|
|
|
const handleBack = () => {
|
|
setCurrentStep(currentStep - 1);
|
|
};
|
|
|
|
// Early return for invite flow loading state
|
|
if (isInviteFlow && isLoadingInvite) {
|
|
return (
|
|
<div className="min-h-screen bg-[--background-primary] py-8 px-4 flex items-center justify-center">
|
|
<div className="max-w-4xl mx-auto text-center">
|
|
<div className="w-16 h-16 bg-[--accent] rounded-full flex items-center justify-center font-bold text-white text-2xl mx-auto mb-4">
|
|
A
|
|
</div>
|
|
<h1 className="text-3xl font-bold text-[--text-primary] mb-4">Loading Your Invitation...</h1>
|
|
<p className="text-[--text-secondary]">Please wait while we verify your invitation.</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Early return for invite flow error state
|
|
if (isInviteFlow && error && currentStep === 1) {
|
|
return (
|
|
<div className="min-h-screen bg-[--background-primary] py-8 px-4 flex items-center justify-center">
|
|
<div className="max-w-4xl mx-auto text-center">
|
|
<div className="w-16 h-16 bg-red-500 rounded-full flex items-center justify-center font-bold text-white text-2xl mx-auto mb-4">
|
|
!
|
|
</div>
|
|
<h1 className="text-3xl font-bold text-[--text-primary] mb-4">Invitation Error</h1>
|
|
<p className="text-[--text-secondary] mb-6">{error}</p>
|
|
<button
|
|
onClick={() => window.location.href = '/'}
|
|
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
|
|
>
|
|
Return to Homepage
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const renderStep = () => {
|
|
// NOTE: Step components need to be imported from EmployeeFormsController
|
|
// For now, showing placeholder that preserves all 38 steps
|
|
switch (currentStep) {
|
|
case 1:
|
|
return <EmployeeFormStep1 onNext={handleNext} />;
|
|
case 2:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="1 of 7"
|
|
title="Personal Information"
|
|
description="Let's start by getting to know you better. We'll ask about your role and background."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 3:
|
|
return <div className="p-8 text-center"><h2>Step 3 - Personal Information Form</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 4:
|
|
return <div className="p-8 text-center"><h2>Step 4 - Email Validation</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 5:
|
|
return <div className="p-8 text-center"><h2>Step 5 - Department Details</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 6:
|
|
return <div className="p-8 text-center"><h2>Step 6 - Role Description</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 7:
|
|
return <div className="p-8 text-center"><h2>Step 7 - Experience Level</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 8:
|
|
return <div className="p-8 text-center"><h2>Step 8 - Skills Assessment</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 9:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="2 of 7"
|
|
title="Work Environment & Culture"
|
|
description="Let's explore your work environment and team dynamics."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 10:
|
|
return <div className="p-8 text-center"><h2>Step 10 - Team Dynamics</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 11:
|
|
return <div className="p-8 text-center"><h2>Step 11 - Communication Style</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 12:
|
|
return <div className="p-8 text-center"><h2>Step 12 - Work Preferences</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 13:
|
|
return <div className="p-8 text-center"><h2>Step 13 - Collaboration Rating</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 14:
|
|
return <div className="p-8 text-center"><h2>Step 14 - Remote Work</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 15:
|
|
return <div className="p-8 text-center"><h2>Step 15 - Work-Life Balance</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 16:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="3 of 7"
|
|
title="Performance & Goals"
|
|
description="Let's discuss your performance metrics and career goals."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 17:
|
|
return <div className="p-8 text-center"><h2>Step 17 - Goal Setting</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 18:
|
|
return <div className="p-8 text-center"><h2>Step 18 - Achievement Rating</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 19:
|
|
return <div className="p-8 text-center"><h2>Step 19 - Performance Metrics</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 20:
|
|
return <div className="p-8 text-center"><h2>Step 20 - Career Aspirations</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 21:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="4 of 7"
|
|
title="Training & Development"
|
|
description="Let's explore your learning preferences and development needs."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 22:
|
|
return <div className="p-8 text-center"><h2>Step 22 - Learning Style</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 23:
|
|
return <div className="p-8 text-center"><h2>Step 23 - Skill Development</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 24:
|
|
return <div className="p-8 text-center"><h2>Step 24 - Training Preferences</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 25:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="5 of 7"
|
|
title="Feedback & Recognition"
|
|
description="Let's discuss feedback mechanisms and recognition preferences."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 26:
|
|
return <div className="p-8 text-center"><h2>Step 26 - Feedback Style</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 27:
|
|
return <div className="p-8 text-center"><h2>Step 27 - Recognition Preferences</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 28:
|
|
return <div className="p-8 text-center"><h2>Step 28 - Performance Reviews</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 29:
|
|
return <div className="p-8 text-center"><h2>Step 29 - Manager Relationship</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 30:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="6 of 7"
|
|
title="Innovation & Problem Solving"
|
|
description="Let's explore your approach to innovation and problem-solving."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 31:
|
|
return <div className="p-8 text-center"><h2>Step 31 - Problem Solving</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 32:
|
|
return <div className="p-8 text-center"><h2>Step 32 - Innovation Rating</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 33:
|
|
return <div className="p-8 text-center"><h2>Step 33 - Creative Thinking</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 34:
|
|
return (
|
|
<SectionIntro
|
|
sectionNumber="7 of 7"
|
|
title="Leadership & Organizational Structure"
|
|
description="Now we'll explore your thoughts on our organizational structure and leadership effectiveness."
|
|
onStart={() => handleNext()}
|
|
/>
|
|
);
|
|
case 35:
|
|
return <div className="p-8 text-center"><h2>Step 35 - Leadership Style</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 36:
|
|
return <div className="p-8 text-center"><h2>Step 36 - Organizational Structure</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Next</button></div>;
|
|
case 37:
|
|
return <div className="p-8 text-center"><h2>Step 37 - Final Feedback</h2><button onClick={() => handleNext()} className="px-4 py-2 bg-blue-600 text-white rounded mt-4">Submit</button></div>;
|
|
case 38:
|
|
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">
|
|
<AuditlyIcon />
|
|
</div>
|
|
</div>
|
|
<div className="self-stretch flex flex-col justify-start items-start gap-4">
|
|
<div className="self-stretch justify-start text-Neutrals-NeutralSlate800 text-5xl font-medium font-['Neue_Montreal'] leading-[48px]">Thank you! Your assessment has been submitted!</div>
|
|
<div className="self-stretch justify-center text-Neutrals-NeutralSlate500 text-base font-normal font-['Inter'] leading-normal">Your responses have been recorded and your AI-powered performance report will be generated shortly.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 h-[810px] px-20 py-16 flex justify-center items-center gap-2.5 overflow-hidden">
|
|
<div className="flex-1 self-stretch origin-top-left rotate-180 rounded-3xl inline-flex flex-col justify-center items-center gap-2.5 overflow-hidden">
|
|
<img className="self-stretch flex-1" src="https://placehold.co/560x682" alt="Thank you" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
default:
|
|
return <div className="p-8 text-center">Form completed!</div>;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white">
|
|
{renderStep()}
|
|
{error && (
|
|
<div className="fixed bottom-4 right-4 bg-red-500 text-white p-4 rounded-lg">
|
|
{error}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default EmployeeQuestionnaire; |