- 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
299 lines
11 KiB
TypeScript
299 lines
11 KiB
TypeScript
import React from 'react';
|
|
import { HashRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
|
import { ThemeProvider } from './contexts/ThemeContext';
|
|
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
|
import { UserOrganizationsProvider, useUserOrganizations } from './contexts/UserOrganizationsContext';
|
|
import { OrgProvider, useOrg } from './contexts/OrgContext';
|
|
import { Layout } from './components/UiKit';
|
|
import CompanyWiki from './pages/CompanyWiki';
|
|
import EmployeeData from './pages/EmployeeData';
|
|
import Chat from './pages/Chat';
|
|
import ChatNew from './pages/ChatNew';
|
|
import HelpNew from './pages/HelpNew';
|
|
import SettingsNew from './pages/SettingsNew';
|
|
import HelpAndSettings from './pages/HelpAndSettings';
|
|
import ModernLogin from './pages/Login';
|
|
import OrgSelection from './pages/OrgSelection';
|
|
import Onboarding from './pages/Onboarding';
|
|
import EmployeeQuestionnaire from './pages/EmployeeQuestionnaire';
|
|
import EmployeeQuestionnaireSteps from './pages/EmployeeQuestionnaireSteps';
|
|
import QuestionTypesDemo from './pages/QuestionTypesDemo';
|
|
import FormsDashboard from './pages/FormsDashboard';
|
|
import DebugEmployee from './pages/DebugEmployee';
|
|
import QuestionnaireComplete from './pages/QuestionnaireComplete';
|
|
import SubscriptionSetup from './pages/SubscriptionSetup';
|
|
|
|
const RequireAuth: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const { user, loading } = useAuth();
|
|
|
|
if (loading) return <div className="p-8">Loading...</div>;
|
|
if (!user) return <Navigate to="/login" replace />;
|
|
return <>{children}</>;
|
|
};
|
|
|
|
const RequireOrgSelection: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const { selectedOrgId, loading } = useUserOrganizations();
|
|
|
|
if (loading) return <div className="p-8">Loading your organizations...</div>;
|
|
if (!selectedOrgId) return <Navigate to="/org-selection" replace />;
|
|
return <>{children}</>;
|
|
};
|
|
|
|
const RequireOnboarding: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const { org } = useOrg();
|
|
const { user } = useAuth();
|
|
const { organizations, selectedOrgId } = useUserOrganizations();
|
|
|
|
if (!org) return <div className="p-8">Loading organization...</div>;
|
|
|
|
// Get the user's relationship to this organization
|
|
const userOrgRelation = organizations.find(o => o.orgId === selectedOrgId);
|
|
const isOrgOwner = userOrgRelation?.role === 'owner';
|
|
|
|
// SINGLE SOURCE OF TRUTH: Organization onboarding completion is the authoritative source
|
|
// User organization records are updated to reflect this, but org.onboardingCompleted is primary
|
|
const onboardingCompleted = org.onboardingCompleted === true;
|
|
|
|
console.log('RequireOnboarding check:', {
|
|
orgId: selectedOrgId,
|
|
orgOnboardingCompleted: org.onboardingCompleted,
|
|
userRole: userOrgRelation?.role,
|
|
finalDecision: onboardingCompleted
|
|
});
|
|
|
|
if (!onboardingCompleted) {
|
|
if (isOrgOwner) {
|
|
console.log('Redirecting owner to onboarding');
|
|
return <Navigate to="/onboarding" replace />;
|
|
} else {
|
|
// Non-owners should see a waiting message
|
|
return (
|
|
<div className="p-8 text-center">
|
|
<h2 className="text-xl font-semibold mb-4">Organization Setup In Progress</h2>
|
|
<p className="text-gray-600">
|
|
Your organization is currently being set up by the administrator.
|
|
Please check back later or contact your administrator for more information.
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
return <>{children}</>;
|
|
};
|
|
|
|
// Wrapper component that provides selected org to OrgProvider
|
|
const OrgProviderWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const { selectedOrgId } = useUserOrganizations();
|
|
|
|
if (!selectedOrgId) {
|
|
return <div className="p-8">No organization selected</div>;
|
|
}
|
|
|
|
return (
|
|
<OrgProvider selectedOrgId={selectedOrgId}>
|
|
{children}
|
|
</OrgProvider>
|
|
);
|
|
};
|
|
|
|
// Redirect invite URLs directly to employee questionnaire (no auth needed)
|
|
const InviteRedirect: React.FC = () => {
|
|
const { inviteCode } = useParams<{ inviteCode: string }>();
|
|
return <Navigate to={`/employee-form/${inviteCode}`} replace />;
|
|
};
|
|
|
|
function App() {
|
|
return (
|
|
<ThemeProvider>
|
|
<AuthProvider>
|
|
<UserOrganizationsProvider>
|
|
<HashRouter>
|
|
<Routes>
|
|
<Route path="/login" element={<ModernLogin />} />
|
|
<Route path="/login/:inviteCode" element={<ModernLogin />} />
|
|
<Route path="/invite/:inviteCode" element={<InviteRedirect />} />
|
|
|
|
{/* Employee questionnaire - no auth needed, uses invite code */}
|
|
<Route path="/employee-form/:inviteCode" element={<EmployeeQuestionnaire />} />
|
|
<Route path="/questionnaire/:inviteCode" element={<EmployeeQuestionnaire />} />
|
|
|
|
{/* Organization Selection - after auth, before entering app */}
|
|
<Route
|
|
path="/org-selection"
|
|
element={
|
|
<RequireAuth>
|
|
<OrgSelection />
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
{/* Subscription Setup - after organization creation */}
|
|
<Route
|
|
path="/subscription-setup"
|
|
element={
|
|
<RequireAuth>
|
|
<SubscriptionSetup />
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
{/* Routes that require both auth and org selection */}
|
|
<Route
|
|
path="/employee-questionnaire"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<EmployeeQuestionnaire />
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
<Route
|
|
path="/employee-questionnaire-steps"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<EmployeeQuestionnaireSteps />
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
<Route
|
|
path="/onboarding"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<Onboarding />
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
<Route path="/questionnaire-complete" element={<QuestionnaireComplete />} />
|
|
|
|
{/* New Figma Chat Implementation - Standalone route */}
|
|
<Route
|
|
path="/chat-new"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<RequireOnboarding>
|
|
<ChatNew />
|
|
</RequireOnboarding>
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
{/* New Figma Help Implementation - Standalone route */}
|
|
<Route
|
|
path="/help-new"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<RequireOnboarding>
|
|
<HelpNew />
|
|
</RequireOnboarding>
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
{/* New Figma Settings Implementation - Standalone route */}
|
|
<Route
|
|
path="/settings-new"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<RequireOnboarding>
|
|
<SettingsNew />
|
|
</RequireOnboarding>
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
|
|
{/* Main app routes - require auth, org selection, and completed onboarding */}
|
|
<Route
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<RequireOnboarding>
|
|
<Layout />
|
|
</RequireOnboarding>
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
>
|
|
<Route path="/" element={<Navigate to="/reports" replace />} />
|
|
<Route path="/company-wiki" element={<CompanyWiki />} />
|
|
<Route path="/submissions" element={<EmployeeData mode="submissions" />} />
|
|
<Route path="/reports" element={<EmployeeData mode="reports" />} />
|
|
<Route path="/chat" element={<Chat />} />
|
|
<Route path="/help" element={<HelpAndSettings />} />
|
|
<Route path="/settings" element={<HelpAndSettings />} />
|
|
</Route>
|
|
|
|
{/* Debug routes */}
|
|
<Route
|
|
path="/question-types-demo"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<QuestionTypesDemo />
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/forms-dashboard"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<FormsDashboard />
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/debug-employee"
|
|
element={
|
|
<RequireAuth>
|
|
<RequireOrgSelection>
|
|
<OrgProviderWrapper>
|
|
<DebugEmployee />
|
|
</OrgProviderWrapper>
|
|
</RequireOrgSelection>
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
</Routes>
|
|
</HashRouter>
|
|
</UserOrganizationsProvider>
|
|
</AuthProvider>
|
|
</ThemeProvider>
|
|
);
|
|
}
|
|
|
|
export default App; |