fix: simplify EmployeeQuestionnaireNew to use invite-only flow
- Remove all authentication and org context dependencies - Simplify component to work only with invite codes from URL - Remove complex user/employee matching logic - Keep exact Figma UI components and styling - Use only submitViaInvite function for API submissions - Employees never need to log in, only use invite link
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
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 { useParams } from 'react-router-dom';
|
||||
import { EmployeeSubmissionAnswers } from '../employeeQuestions';
|
||||
import { API_URL } from '../constants';
|
||||
import {
|
||||
WelcomeScreen,
|
||||
@@ -15,39 +13,21 @@ import {
|
||||
} from '../components/figma/FigmaEmployeeForms';
|
||||
|
||||
/**
|
||||
* Enhanced Employee Questionnaire with Exact Figma Design Implementation
|
||||
* Employee Questionnaire with Invite-Only Flow
|
||||
*
|
||||
* Features:
|
||||
* - Exact Figma design system styling
|
||||
* - Invite-based flow (no authentication required)
|
||||
* - Company owner can invite employees with metadata
|
||||
* - LLM processing via cloud functions
|
||||
* - Report generation with company context
|
||||
* - Firestore storage for reports
|
||||
* - Company owner invites employees with metadata
|
||||
* - Employee uses invite code to access questionnaire
|
||||
* - LLM processing via cloud functions with company context
|
||||
* - Report generation and Firestore storage
|
||||
*/
|
||||
|
||||
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 = [];
|
||||
}
|
||||
|
||||
// Component state
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
const [formData, setFormData] = useState<any>({});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
@@ -55,10 +35,12 @@ const EmployeeQuestionnaire: React.FC = () => {
|
||||
const [inviteEmployee, setInviteEmployee] = useState<any>(null);
|
||||
const [isLoadingInvite, setIsLoadingInvite] = useState(false);
|
||||
|
||||
// Load invite details if this is an invite flow
|
||||
// Load invite details on component mount
|
||||
useEffect(() => {
|
||||
if (inviteCode) {
|
||||
loadInviteDetails(inviteCode);
|
||||
} else {
|
||||
setError('No invite code provided');
|
||||
}
|
||||
}, [inviteCode]);
|
||||
|
||||
@@ -94,39 +76,8 @@ const EmployeeQuestionnaire: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
// Get employee info from invite data
|
||||
const currentEmployee = inviteEmployee;
|
||||
|
||||
const submitViaInvite = async (answers: EmployeeSubmissionAnswers, inviteCode: string) => {
|
||||
try {
|
||||
@@ -176,7 +127,7 @@ const EmployeeQuestionnaire: React.FC = () => {
|
||||
setError('');
|
||||
|
||||
try {
|
||||
// Convert form data to EMPLOYEE_QUESTIONS format for backend
|
||||
// Convert form data to answers format for backend
|
||||
const answers: EmployeeSubmissionAnswers = {};
|
||||
|
||||
// Map form data to question IDs
|
||||
@@ -191,55 +142,14 @@ const EmployeeQuestionnaire: React.FC = () => {
|
||||
}
|
||||
});
|
||||
|
||||
// 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(999); // 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);
|
||||
}
|
||||
// Submit answers via invite flow
|
||||
const result = await submitViaInvite(answers, inviteCode!);
|
||||
|
||||
if (result.success) {
|
||||
// Show thank you page
|
||||
setCurrentStep(999);
|
||||
} else {
|
||||
setError(result.message || 'Failed to submit questionnaire');
|
||||
setError(result.error || 'Failed to submit questionnaire');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Submission error:', error);
|
||||
@@ -261,8 +171,8 @@ const EmployeeQuestionnaire: React.FC = () => {
|
||||
setCurrentStep(currentStep - 1);
|
||||
};
|
||||
|
||||
// Early return for invite flow loading state
|
||||
if (isInviteFlow && isLoadingInvite) {
|
||||
// Early return for loading state
|
||||
if (isLoadingInvite) {
|
||||
return (
|
||||
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
@@ -276,8 +186,8 @@ const EmployeeQuestionnaire: React.FC = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// Early return for invite flow error state
|
||||
if (isInviteFlow && error && currentStep === 1) {
|
||||
// Early return for error state
|
||||
if (error && currentStep === 1) {
|
||||
return (
|
||||
<div className="min-h-screen bg-[--Neutrals-NeutralSlate0] py-8 px-4 flex items-center justify-center">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
|
||||
Reference in New Issue
Block a user