setSelectedCategory(category)}
- className={`px-3 py-1.5 rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden cursor-pointer ${selectedCategory === category ? 'bg-white' : ''
+ className={`px-3 py-1.5 rounded-lg shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)] flex justify-center items-center gap-1 overflow-hidden cursor-pointer ${selectedCategory === category ? 'bg-[--Neutrals-NeutralSlate50]' : ''
}`}
>
diff --git a/src/pages/CompanyWiki.tsx b/src/pages/CompanyWiki.tsx
index 31c4ab5..4463f1f 100644
--- a/src/pages/CompanyWiki.tsx
+++ b/src/pages/CompanyWiki.tsx
@@ -1,94 +1,304 @@
-import React, { useEffect, useState } from 'react';
-import { useOrg } from '../contexts/OrgContext';
-import { CompanyReport } from '../types';
-import { CompanyWikiManager } from '../components/CompanyWiki';
-
-const CompanyWiki: React.FC = () => {
- const { org, employees, getFullCompanyReportHistory, generateCompanyWiki } = useOrg();
- const [isGenerating, setIsGenerating] = useState(false);
- const [companyReport, setCompanyReport] = useState
(null);
- const [error, setError] = useState(null);
- const [onboardingProgress, setOnboardingProgress] = useState(60);
-
- useEffect(() => {
- (async () => {
- try {
- const history = await getFullCompanyReportHistory();
- if (history.length) {
- setCompanyReport(history[0]);
- }
- } catch (e) {
- console.error('Failed loading company report history', e);
- }
- })();
- }, [getFullCompanyReportHistory]);
-
- // Determine wiki state based on company data
- const wikiState = companyReport ? 'completed' : 'empty';
-
- // Create Q&A items from company report or org data
- const qaItems = companyReport ? [
- {
- question: "What is the mission of your company?",
- answer: org?.mission || "To empower small businesses with AI-driven automation tools that increase efficiency and reduce operational overhead."
- },
- {
- question: "How has your mission evolved in the last 1–3 years?",
- answer: org?.evolution || "We shifted from general SaaS tools to vertical-specific solutions, with deeper integrations and onboarding support."
- },
- {
- question: "What is your 5-year vision for the company?",
- answer: org?.vision || "To become the leading AI operations platform for SMBs in North America, serving over 100,000 customers."
- },
- {
- question: "What are your company's top 3 strategic advantages?",
- answer: org?.advantages || "Fast product iteration enabled by in-house AI capabilities\nDeep customer understanding from vertical specialization\nHigh customer retention due to integrated onboarding"
- },
- {
- question: "What are your biggest vulnerabilities or threats?",
- answer: org?.vulnerabilities || "Dependence on a single marketing channel, weak middle management, and rising customer acquisition costs."
- }
- ] : undefined;
-
- // Convert employees to suggested format for invitations
- const suggestedEmployees = employees?.map(emp => ({
- id: emp.id,
- name: emp.name || emp.email,
- email: emp.email
- })) || [];
-
- const handleCompleteOnboarding = async () => {
- setIsGenerating(true);
- setError(null);
- try {
- const report = await generateCompanyWiki();
- setCompanyReport(report);
- setOnboardingProgress(100);
- } catch (e: any) {
- console.error(e);
- setError('Failed to generate company wiki');
- } finally {
- setIsGenerating(false);
- }
- };
-
- return (
-
- {error && (
-
- {error}
-
- )}
-
-
-
- );
-};
-
+import React, { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { secureApi } from '../services/secureApi';
+import { OnboardingData } from '../types';
+
+
+const CompanyWiki: React.FC = () => {
+ const navigate = useNavigate();
+ const [onboardingData, setOnboardingData] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [activeSection, setActiveSection] = useState(1);
+ const [onboardingCompleted, setOnboardingCompleted] = useState(false);
+ const [lastStep, setLastStep] = useState();
+
+ useEffect(() => {
+ loadOnboardingData();
+ }, []);
+
+ const loadOnboardingData = async () => {
+ try {
+ setIsLoading(true);
+ const response = await secureApi.getOrgData();
+
+ if (!response.onboardingCompleted) {
+ navigate(`/onboarding`);
+ return;
+ }
+
+ if (response.onboardingData) {
+ setOnboardingData(response?.onboardingData);
+ setOnboardingCompleted(response.onboardingCompleted);
+ // setLastStep(response.lastStep);
+ }
+ } catch (err: any) {
+ console.error('Failed to load onboarding data:', err);
+ setError(err.message || 'Failed to load company wiki data');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const getSectionTitle = (section: number): string => {
+ const titles = {
+ 1: 'Company Overview & Vision',
+ 2: 'Leadership & Organizational Structure',
+ 3: 'Operations & Execution',
+ 4: 'Culture & Team Health',
+ 5: 'Sales, Marketing & Growth',
+ 6: 'Innovation & Product/Service Strategy',
+ 7: 'Personal Leadership & Risk'
+ };
+ return titles[section as keyof typeof titles] || '';
+ };
+
+ const getSectionQuestions = (section: number) => {
+ if (!onboardingData) return [];
+
+ const sectionFields = {
+ 1: [
+ 'companySize',
+ 'mission',
+ 'missionEvolution',
+ 'vision',
+ 'strategicAdvantages',
+ 'vulnerabilities',
+ 'scalabilityChallenges',
+ 'growthLimitations'
+ ],
+ 2: [
+ 'leadershipStructure',
+ 'criticalPeople',
+ 'leadershipGaps',
+ 'delegationOpportunities',
+ 'leadershipDevelopment',
+ 'heldOntoTooLong',
+ 'successionConfidence'
+ ],
+ 3: [
+ 'businessSystems',
+ 'personalDependencies',
+ 'operationalFriction',
+ 'workflowEfficiency',
+ 'fragileProcesses',
+ 'recurringProblems'
+ ],
+ 4: [
+ 'cultureDescription',
+ 'livedValues',
+ 'internalFriction',
+ 'speakUpCulture',
+ 'clearExpectations',
+ 'staffFeedback',
+ 'highPerformerLove'
+ ],
+ 5: [
+ 'revenuePipeline',
+ 'customerAcquisition',
+ 'customerAcquisitionCost',
+ 'customerLifetimeValue',
+ 'underutilizedChannels',
+ 'overspendingROI',
+ 'currentBottleneck'
+ ],
+ 6: [
+ 'monthlyBurnOverhead',
+ 'currentRevenue',
+ 'netProfitMargin',
+ 'financialsUpToDate',
+ 'financialGrowthPlanning',
+ 'cashRunway',
+ 'underpricing'
+ ],
+ 7: [
+ 'uniqueOffering',
+ 'productStagnation',
+ 'industryTrends',
+ 'innovationAhead',
+ 'industryDirection'
+ ],
+ 8: [
+ 'avoidedDecisions',
+ 'hardestCall',
+ 'energyDrain',
+ 'leadershipStretched',
+ 'sabbaticalRisks',
+ 'companyLegacy',
+ 'yearSuccess'
+ ]
+ };
+
+ const fields = sectionFields[section as keyof typeof sectionFields] || [];
+ return fields.map(field => ({
+ field,
+ question: getQuestionText(field),
+ answer: onboardingData[field] || 'No answer provided'
+ }));
+ };
+
+ const getQuestionText = (field: string): string => {
+ const questions = {
+ companySize: 'What is the size of your company?',
+ mission: 'What is the mission of your company?',
+ missionEvolution: 'How has your mission evolved in the last 1–3 years?',
+ vision: 'What is your company\'s vision for the future?',
+ strategicAdvantages: 'What does success look like for your company?',
+ vulnerabilities: 'What are your core company values?',
+ scalabilityChallenges: 'Describe your current leadership structure.',
+ growthLimitations: 'Who are the most critical people in the business today?',
+
+ leadershipStructure: 'Where are leadership gaps or weak links?',
+ criticalPeople: 'What decisions are you still involved in that someone else should own?',
+ leadershipGaps: 'What systems or tools do you rely on to run the business?',
+ delegationOpportunities: 'Where does the business rely too much on you personally?',
+ leadershipDevelopment: 'Where is the most operational friction inside the company?',
+ heldOntoTooLong: 'How efficient is your workflow from sales to delivery?',
+ successionConfidence: 'How confident are you in your succession plan?',
+
+ businessSystems: 'What systems or tools do you rely on to run the business?',
+ personalDependencies: 'Where does the business rely too much on you personally?',
+ operationalFriction: 'Where is the most operational friction inside the company?',
+ workflowEfficiency: 'How efficient is your workflow from sales to delivery?',
+ fragileProcesses: 'What processes feel fragile or inconsistent?',
+ recurringProblems: 'What recurring problems never seem to get solved?',
+
+ cultureDescription: 'How would you describe your company culture in a few words?',
+ livedValues: 'What values are truly lived out daily by your team?',
+ internalFriction: 'Where is there internal friction or misalignment?',
+ speakUpCulture: 'Do people speak up when things are broken or wrong?',
+ clearExpectations: 'How do customers typically find you?',
+ staffFeedback: 'What is your competitive advantage?',
+ highPerformerLove: 'Where do you lose potential customers?',
+
+ revenuePipeline: 'How consistent is your revenue pipeline?',
+ customerAcquisition: 'Where do most of your customers come from?',
+ customerAcquisitionCost: 'What is your customer acquisition cost (CAC)?',
+ customerLifetimeValue: 'What\'s your average customer lifetime value (LTV)?',
+ underutilizedChannels: 'What channels or strategies are underutilized?',
+ overspendingROI: 'Where are you overspending with low ROI?',
+ currentBottleneck: 'What is your current bottleneck in scaling revenue?',
+
+ monthlyBurnOverhead: 'What is your monthly burn or overhead?',
+ currentRevenue: 'What is your current monthly/annual revenue?',
+ netProfitMargin: 'What is your current net profit margin?',
+ financialsUpToDate: 'Are your financials up to date and properly reported?',
+ financialGrowthPlanning: 'What would your team do differently if they had full financial transparency?',
+ cashRunway: 'What does your cash runway look like?',
+ underpricing: 'What are you underpricing or undervaluing?',
+
+ uniqueOffering: 'What is your most unique offering?',
+ productStagnation: 'What part of the product/service is outdated or stagnant?',
+ industryTrends: 'What trends are you tracking in your industry?',
+ innovationAhead: 'How does your company stay ahead of innovation?',
+ industryDirection: 'What new product/service do you believe could change the game for you?',
+
+
+ avoidedDecisions: 'What decisions are you avoiding right now?',
+ hardestCall: 'What\'s been the hardest call you\'ve had to make in the last year?',
+ energyDrain: 'What part of the business drains your energy the most?',
+ leadershipStretched: 'Where are you most stretched as a leader?',
+ sabbaticalRisks: 'If you had to take a 90-day sabbatical, what would collapse?',
+ companyLegacy: 'What legacy are you trying to build through this company?',
+ yearSuccess: 'What would need to happen in the next 12 months for this year to be a success?'
+ };
+ return questions[field as keyof typeof questions] || field;
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+
Loading company wiki...
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+
Error: {error}
+
+
+
+ );
+ }
+
+ if (!onboardingCompleted || !onboardingData) {
+ return null;
+ }
+
+ return (
+
+ {/* Left Sidebar - Company Navigation */}
+ {/* Main Content Area */}
+
+
+ {/* Table of Contents Sidebar */}
+
+
+
+ {[1, 2, 3, 4, 5, 6, 7].map((section, index) => (
+
setActiveSection(section)}
+ >
+
+
+ {getSectionTitle(section)}
+
+
+ ))}
+
+
+
+ {/* Questions Content */}
+
+
+
+ {getSectionTitle(activeSection)}
+
+
+
+ {getSectionQuestions(activeSection).map((qa, index) => (
+
+
+
+
Q
+
+ {qa.question}
+
+
+
+
+
+ ))}
+
+
+
+
+
+ );
+};
+
export default CompanyWiki;
\ No newline at end of file
diff --git a/src/pages/CompanyWikiNew.tsx b/src/pages/CompanyWikiNew.tsx
new file mode 100644
index 0000000..44e7aa1
--- /dev/null
+++ b/src/pages/CompanyWikiNew.tsx
@@ -0,0 +1,263 @@
+import React, { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { secureApi } from '../services/secureApi';
+
+interface OnboardingData {
+ [key: string]: string;
+}
+
+const CompanyWiki: React.FC = () => {
+ const navigate = useNavigate();
+ const [onboardingData, setOnboardingData] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [activeSection, setActiveSection] = useState(1);
+ const [onboardingCompleted, setOnboardingCompleted] = useState(false);
+ const [lastStep, setLastStep] = useState();
+
+ useEffect(() => {
+ loadOnboardingData();
+ }, []);
+
+ const loadOnboardingData = async () => {
+ try {
+ setIsLoading(true);
+ const response = await secureApi.getOnboardingQuestions();
+
+ if (!response.completed && response.lastStep) {
+ navigate(`/onboarding?step=${response.lastStep}`);
+ return;
+ }
+
+ if (!response.completed) {
+ navigate('/onboarding');
+ return;
+ }
+
+ setOnboardingData(response.questions);
+ setOnboardingCompleted(response.completed);
+ setLastStep(response.lastStep);
+ } catch (err: any) {
+ console.error('Failed to load onboarding data:', err);
+ setError(err.message || 'Failed to load company wiki data');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const getSectionTitle = (section: number): string => {
+ const titles = {
+ 1: 'Company Overview & Vision',
+ 2: 'Leadership & Organizational Structure',
+ 3: 'Operations & Execution',
+ 4: 'Culture & Team Health',
+ 5: 'Sales, Marketing & Growth',
+ 6: 'Innovation & Product/Service Strategy',
+ 7: 'Personal Leadership & Risk'
+ };
+ return titles[section as keyof typeof titles] || '';
+ };
+
+ const getSectionQuestions = (section: number) => {
+ if (!onboardingData) return [];
+
+ const sectionFields = {
+ 1: ['mission', 'missionEvolution', 'vision', 'successDefinition', 'coreValues'],
+ 2: ['leadershipStructure', 'criticalPeople', 'leadershipGaps', 'delegationOpportunities'],
+ 3: ['businessSystems', 'personalDependencies', 'operationalFriction', 'workflowEfficiency'],
+ 4: ['cultureDescription', 'livedValues', 'internalFriction', 'speakUpCulture'],
+ 5: ['customerAcquisition', 'competitiveAdvantage', 'customerLoss', 'customerLoyalty'],
+ 6: ['newProducts', 'innovationProcess', 'uniquePosition', 'industryDirection'],
+ 7: ['businessWorries', 'leadershipBlindSpots', 'stressManagement', 'regretfulDecisions']
+ };
+
+ const fields = sectionFields[section as keyof typeof sectionFields] || [];
+ return fields.map(field => ({
+ field,
+ question: getQuestionText(field),
+ answer: onboardingData[field] || 'No answer provided'
+ }));
+ };
+
+ const getQuestionText = (field: string): string => {
+ const questions = {
+ mission: 'What is the mission of your company?',
+ missionEvolution: 'How has your mission evolved in the last 1–3 years?',
+ vision: 'What is your company\'s vision for the future?',
+ successDefinition: 'What does success look like for your company?',
+ coreValues: 'What are your core company values?',
+ leadershipStructure: 'Describe your current leadership structure.',
+ criticalPeople: 'Who are the most critical people in the business today?',
+ leadershipGaps: 'Where are leadership gaps or weak links?',
+ delegationOpportunities: 'What decisions are you still involved in that someone else should own?',
+ businessSystems: 'What systems or tools do you rely on to run the business?',
+ personalDependencies: 'Where does the business rely too much on you personally?',
+ operationalFriction: 'Where is the most operational friction inside the company?',
+ workflowEfficiency: 'How efficient is your workflow from sales to delivery?',
+ cultureDescription: 'How would you describe your company culture in a few words?',
+ livedValues: 'What values are truly lived out daily by your team?',
+ internalFriction: 'Where is there internal friction or misalignment?',
+ speakUpCulture: 'Do people speak up when things are broken or wrong?',
+ customerAcquisition: 'How do customers typically find you?',
+ competitiveAdvantage: 'What is your competitive advantage?',
+ customerLoss: 'Where do you lose potential customers?',
+ customerLoyalty: 'What drives customer loyalty and retention?',
+ newProducts: 'What new products or services are you considering?',
+ innovationProcess: 'How do you stay innovative and ahead of trends?',
+ uniquePosition: 'What customer problems are you uniquely positioned to solve?',
+ industryDirection: 'Where do you see your industry heading?',
+ businessWorries: 'What keeps you up at night about the business?',
+ leadershipBlindSpots: 'What are your biggest blind spots as a leader?',
+ stressManagement: 'How do you handle stress and pressure?',
+ regretfulDecisions: 'What decisions do you most regret or would do differently?'
+ };
+ return questions[field as keyof typeof questions] || field;
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+
Loading company wiki...
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+
Error: {error}
+
+
+
+ );
+ }
+
+ if (!onboardingCompleted || !onboardingData) {
+ return null;
+ }
+
+ return (
+
+
+ {/* Left Sidebar - Company Navigation */}
+
+ {/* Company Header */}
+
+
+
+
+
+
+ {onboardingData?.companyName || 'Company Name'}
+
+
+
+
+
+ {/* Navigation Items */}
+
+
+
+ {/* Bottom Section */}
+
+
+
+ {/* Main Content Area */}
+
+
+ {/* Table of Contents Sidebar */}
+
+
+
+ {[1, 2, 3, 4, 5, 6, 7].map((section, index) => (
+
setActiveSection(section)}
+ >
+
+
+ {getSectionTitle(section)}
+
+
+ ))}
+
+
+
+ {/* Questions Content */}
+
+
+
+ {getSectionTitle(activeSection)}
+
+
+
+ {getSectionQuestions(activeSection).map((qa, index) => (
+
+
+
+
Q
+
+ {qa.question}
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+export default CompanyWiki;
\ No newline at end of file
diff --git a/src/pages/HelpNew.tsx b/src/pages/HelpNew.tsx
index 6bf0768..de63e38 100644
--- a/src/pages/HelpNew.tsx
+++ b/src/pages/HelpNew.tsx
@@ -73,7 +73,7 @@ const HelpNew: React.FC = () => {
{faqItems.map((item, index) => (
toggleFAQ(index)}
@@ -105,7 +105,7 @@ const HelpNew: React.FC = () => {
))}
-
+
Still have questions?
We are available for 24/7
diff --git a/src/pages/Onboarding.tsx b/src/pages/Onboarding.tsx
index 4db639b..90f3d54 100644
--- a/src/pages/Onboarding.tsx
+++ b/src/pages/Onboarding.tsx
@@ -13,7 +13,6 @@ import {
const Onboarding: React.FC = () => {
const { org, upsertOrg, generateCompanyWiki } = useOrg();
- const { user } = useAuth();
const navigate = useNavigate();
useEffect(() => {
diff --git a/src/pages/Reports.tsx b/src/pages/Reports.tsx
index 1464ea4..23d3b06 100644
--- a/src/pages/Reports.tsx
+++ b/src/pages/Reports.tsx
@@ -1,10 +1,13 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useCallback } from 'react';
+import { useLocation } from 'react-router-dom';
import { useOrg } from '../contexts/OrgContext';
+import { secureApiPOST, secureApi } from '../services/secureApi';
import { CompanyReport, Employee, EmployeeReport } from '../types';
import { SAMPLE_COMPANY_REPORT } from '../constants';
import RadarPerformanceChart from '../components/charts/RadarPerformanceChart';
const Reports: React.FC = () => {
+ const location = useLocation();
const { employees, reports, user, isOwner, getFullCompanyReportHistory, generateEmployeeReport, generateCompanyReport, orgId } = useOrg();
const [companyReport, setCompanyReport] = useState
(null);
const [selectedReport, setSelectedReport] = useState<{ report: CompanyReport | EmployeeReport; type: 'company' | 'employee'; employeeName?: string } | null>(null);
@@ -14,6 +17,9 @@ const Reports: React.FC = () => {
const currentUserIsOwner = isOwner(user?.uid || '');
+ // Get selected employee ID from navigation state (from Submissions page)
+ const selectedEmployeeId = location.state?.selectedEmployeeId;
+
// Load company report on component mount
useEffect(() => {
const loadCompanyReport = async () => {
@@ -38,6 +44,16 @@ const Reports: React.FC = () => {
loadCompanyReport();
}, [currentUserIsOwner, getFullCompanyReportHistory]);
+ // Handle navigation from Submissions page
+ useEffect(() => {
+ if (selectedEmployeeId) {
+ const employee = employees.find(emp => emp.id === selectedEmployeeId);
+ if (employee) {
+ handleEmployeeSelect(employee);
+ }
+ }
+ }, [selectedEmployeeId, employees, handleEmployeeSelect]);
+
// Filter and sort employees
const visibleEmployees = currentUserIsOwner
? employees.filter(emp =>
@@ -45,7 +61,7 @@ const Reports: React.FC = () => {
).sort((a, b) => a.name.localeCompare(b.name))
: employees.filter(emp => emp.id === user?.uid);
- const handleEmployeeSelect = (employee: Employee) => {
+ const handleEmployeeSelect = useCallback((employee: Employee) => {
const employeeReport = reports[employee.id];
if (employeeReport) {
setSelectedReport({
@@ -54,7 +70,7 @@ const Reports: React.FC = () => {
employeeName: employee.name
});
}
- };
+ }, [reports]);
const handleCompanyReportSelect = () => {
if (companyReport) {
@@ -76,237 +92,101 @@ const Reports: React.FC = () => {
};
return (
-
-
-
- {/* Left Sidebar - Navigation */}
-
-
- {/* Company Logo */}
-
-
- {/* Navigation Items */}
-
+
+ {/* Middle Section - Employee List */}
+
+
+
-
- {/* Bottom Section - Settings and CTA */}
-
-
-
- {/* CTA Card */}
-
-
-
-
Build [Company]'s Report
-
Share this form with your team members to capture valuable info about your company to train Auditly.
-
-
-
-
-
-
-
+
+ {/* Search */}
+
+
+
+
+
setSearchQuery(e.target.value)}
+ className="flex-1 bg-transparent text-[--Neutrals-NeutralSlate500] text-sm font-normal font-['Inter'] leading-tight outline-none"
+ />
+
+ {/* Employee List */}
+
+ {/* Company Report Item */}
+ {currentUserIsOwner && (
+
+ )}
+
+ {/* Employee Items */}
+ {visibleEmployees.map((employee) => (
+
handleEmployeeSelect(employee)}
+ >
+
+
+ {employee.initials}
+
+
+
+ {employee.name}
+
+
+ ))}
+
- {/* Middle Section - Employee List */}
-
-
-
-
- {/* Search */}
-
-
-
-
-
setSearchQuery(e.target.value)}
- className="flex-1 bg-transparent text-[--Neutrals-NeutralSlate500] text-sm font-normal font-['Inter'] leading-tight outline-none"
- />
-
-
-
-
- {/* Employee List */}
-
- {/* Company Report Item */}
- {currentUserIsOwner && (
-
- )}
-
- {/* Employee Items */}
- {visibleEmployees.map((employee) => (
-
handleEmployeeSelect(employee)}
- >
-
-
- {employee.initials}
-
-
-
- {employee.name}
-
-
- ))}
-
-
-
-
- {/* Main Content Area */}
-
- {selectedReport ? (
- selectedReport.type === 'company' ? (
-
- ) : (
-
- )
+ {/* Main Content Area */}
+
+ {selectedReport ? (
+ selectedReport.type === 'company' ? (
+
) : (
-
-
-
- Select a Report
-
-
- Choose a company or employee report from the list to view details.
-
-
+
+ )
+ ) : (
+
+
+
+ Select a Report
+
+
+ Choose a company or employee report from the list to view details.
+
- )}
-
+
+ )}
@@ -319,7 +199,10 @@ const CompanyReportContent: React.FC<{
onRegenerate: () => void;
isGenerating: boolean;
}> = ({ report, onRegenerate, isGenerating }) => {
- const [activeDepartmentTab, setActiveDepartmentTab] = useState('Campaigns');
+ // Default to the first department in the array
+ const [activeDepartmentTab, setActiveDepartmentTab] = useState(() =>
+ report?.gradingBreakdown?.[0]?.departmentNameShort || 'Campaigns'
+ );
return (
<>
@@ -331,11 +214,11 @@ const CompanyReportContent: React.FC<{
-
Download as PDF
+
Download as PDF
@@ -343,29 +226,29 @@ const CompanyReportContent: React.FC<{
{/* Content */}
{/* Company Weaknesses */}
-
+
-
Company Weaknesses
+
Company Weaknesses
-
+
{report?.weaknesses?.map((weakness, index) => (
-
{weakness.title}:
-
{weakness.description}
+
{weakness.title}:
+
{weakness.description}
{index < (report?.weaknesses?.length || 0) - 1 && (
-
)) || (
-
Lack of Structure:
-
People are confused about their roles. No one knows who's responsible.
+
Lack of Structure:
+
People are confused about their roles. No one knows who's responsible.
)}
@@ -373,16 +256,15 @@ const CompanyReportContent: React.FC<{
{/* Personnel Changes */}
{report?.personnelChanges && (
-
+
-
Personnel Changes
+
Personnel Changes
-
-
+
{/* New Hires */}
{report.personnelChanges.newHires && report.personnelChanges.newHires.length > 0 && (
-
New Hires
+
New Hires
{report.personnelChanges.newHires.map((hire, index) => (
{hire.name} - {hire.role}
@@ -396,7 +278,7 @@ const CompanyReportContent: React.FC<{
{/* Promotions */}
{report.personnelChanges.promotions && report.personnelChanges.promotions.length > 0 && (
-
Promotions
+
Promotions
{report.personnelChanges.promotions.map((promotion, index) => (
{promotion.name}
@@ -410,7 +292,7 @@ const CompanyReportContent: React.FC<{
{/* Departures */}
{report.personnelChanges.departures && report.personnelChanges.departures.length > 0 && (
-
Departures
+
Departures
{report.personnelChanges.departures.map((departure, index) => (
{departure.name}
@@ -426,7 +308,7 @@ const CompanyReportContent: React.FC<{
{(!report.personnelChanges.newHires || report.personnelChanges.newHires.length === 0) &&
(!report.personnelChanges.promotions || report.personnelChanges.promotions.length === 0) &&
(!report.personnelChanges.departures || report.personnelChanges.departures.length === 0) && (
-
+
No personnel changes to report.
)}
@@ -436,30 +318,43 @@ const CompanyReportContent: React.FC<{
{/* Hiring Needs */}
{report?.immediateHiringNeeds && report.immediateHiringNeeds.length > 0 && (
-
+
-
Immediate Hiring Needs
+
Immediate Hiring Needs
-
+ {/*
{report.immediateHiringNeeds.map((need, index) => (
-
-
-
-
- {need.role} - {need.department}
-
-
- {need.priority} Priority
-
+
+
{need.role} - {need.department}
+
+
+ {need.priority} Priority
-
- {need.reasoning}
-
+
+
+
+ ))}
+
*/}
+
+ {report.immediateHiringNeeds.map((need, index) => (
+
+
+
{need.role} - {need.department}
+
{need.reasoning}
+
+ {index !== report.immediateHiringNeeds.length - 1 && (
+
+ )}
+
))}
@@ -467,23 +362,28 @@ const CompanyReportContent: React.FC<{
{/* Forward Plan */}
{report?.forwardOperatingPlan && (
-
+
-
Forward Plan
+
Forward Plan
-
+
{
report.forwardOperatingPlan.map((plan, index) => (
-
{plan.title}
-
- {plan.details.map((detail, idx) => (
-
{detail}
- ))}
+
{plan.title}
+
+
+ {plan.details.map((detail, idx) => (
+ -
+
+ {detail}
+
+ ))}
+
-
+ {index !== report.forwardOperatingPlan.length - 1 &&
}
))
}
@@ -495,22 +395,22 @@ const CompanyReportContent: React.FC<{
Strengths goes here
*/}
{report?.strengths && (
-
+
-
+
{report.strengths.map((strength, idx) => (
-
{strength}
+
{strength}
))}
@@ -521,23 +421,22 @@ const CompanyReportContent: React.FC<{
Organizational Impact Summary
*/}
{report?.organizationalImpactSummary && (
-
+
-
Organizational Impact Summary
+
Organizational Impact Summary
-
-
+
{/* Mission Critical */}
-
Mission Critical
+
Mission Critical
{report.organizationalImpactSummary.missionCritical.map((employee, index) => (
-
{employee.employeeName}
-
{employee.description}
+
{employee.employeeName}
+
{employee.description}
))}
@@ -547,13 +446,13 @@ const CompanyReportContent: React.FC<{
-
Highly Valuable
+
Highly Valuable
{report.organizationalImpactSummary.highlyValuable.map((employee, index) => (
-
{employee.employeeName}
-
{employee.description}
+
{employee.employeeName}
+
{employee.description}
))}
@@ -563,13 +462,13 @@ const CompanyReportContent: React.FC<{
-
Core Support
+
Core Support
{report.organizationalImpactSummary.coreSupport.map((employee, index) => (
-
{employee.employeeName}
-
{employee.description}
+
{employee.employeeName}
+
{employee.description}
))}
@@ -579,13 +478,13 @@ const CompanyReportContent: React.FC<{
-
Low Criticality
+
Low Criticality
{report.organizationalImpactSummary.lowCriticality.map((employee, index) => (
-
{employee.employeeName}
-
{employee.description}
+
{employee.employeeName}
+
{employee.description}
))}
@@ -595,110 +494,110 @@ const CompanyReportContent: React.FC<{
)}
{/* Grading Overview */}
-
+
-
Grading Overview
+
Grading Overview
-
+
{/* Department Tabs */}
- {['Campaigns', 'Social Media', 'Creative', 'Tech', 'Admin/OPS'].map((dept) => (
+ {report?.gradingBreakdown?.map(dept => (
setActiveDepartmentTab(dept)}
+ onClick={() => setActiveDepartmentTab(dept.departmentNameShort)}
>
-
- {dept}
+ {dept.departmentNameShort}
))}
-
- {/* Department Overview Section */}
-
-
-
Department Overview
-
-
Overall Grade
-
-
A
+ {/* Content for the currently selected department */}
+ {(() => {
+ const currentDepartment = report?.gradingBreakdown?.find(dept => dept.departmentNameShort === activeDepartmentTab);
+ if (!currentDepartment) return null;
+
+ return (
+
+ {/* Department Overview Section */}
+
+
+
Department Overview
+
+
+
+
+ Overall company performance shows strong collaboration and delivery with opportunities for process improvement.
-
-
-
- Overall company performance shows strong collaboration and delivery with opportunities for process improvement.
-
-
- {/* Employee Radar Charts Section */}
-
-
Team Performance Analysis
-
- {report?.gradingBreakdown?.teamScores
- ?.filter(teamScore => {
- // Filter employees based on active department tab
- // For now, showing all employees as we don't have department info per employee
- // In a real implementation, you'd filter by employee department
- return true;
- })
- ?.map((teamScore, index) => {
- const radarData = [
- { label: 'Reliability', value: teamScore.reliability * 10 },
- { label: 'Role Fit', value: teamScore.roleFit * 10 },
- { label: 'Scalability', value: teamScore.scalability * 10 },
- { label: 'Output', value: teamScore.output * 10 },
- { label: 'Initiative', value: teamScore.initiative * 10 }
- ];
+ {/* Employee Radar Charts Section */}
+
+
Team Performance Analysis
+
+ {currentDepartment.teamScores?.map((teamScore, index) => {
+ const radarData = [
+ { label: 'Reliability', value: teamScore.reliability * 10 },
+ { label: 'Role Fit', value: teamScore.roleFit * 10 },
+ { label: 'Scalability', value: teamScore.scalability * 10 },
+ { label: 'Output', value: teamScore.output * 10 },
+ { label: 'Initiative', value: teamScore.initiative * 10 }
+ ];
- return (
-
-
-
{teamScore.employeeName}
-
+
+
{teamScore.employeeName}
+
- Grade: {teamScore.grade}
+ }`}>
+ Grade: {teamScore.grade}
+
+
+
+
-
-
-
-
- );
- })
- }
+ );
+ })}
+
+
-
-
+ );
+ })()}
{/* Company Strengths */}
{/* {report?.organizationalStrengths && (
-
+
@@ -721,7 +620,7 @@ const CompanyReportContent: React.FC<{
)} */}
-
+
>
);
};
@@ -753,7 +652,7 @@ const EmployeeReportContent: React.FC<{
{/* Content */}
{/* Role & Responsibilities */}
-
+
@@ -766,7 +665,7 @@ const EmployeeReportContent: React.FC<{
{/* Self-Rated Output */}
{report.roleAndOutput?.selfRatedOutput && (
-
+
@@ -780,7 +679,7 @@ const EmployeeReportContent: React.FC<{
{/* Insights */}
{report.insights && (
-
+
@@ -815,7 +714,7 @@ const EmployeeReportContent: React.FC<{
{/* Strengths */}
{report.strengths && report.strengths.length > 0 && (
-
+
@@ -839,7 +738,7 @@ const EmployeeReportContent: React.FC<{
{/* Recommendations */}
{report.recommendations && report.recommendations.length > 0 && (
-
+
diff --git a/src/pages/SettingsNew.tsx b/src/pages/SettingsNew.tsx
index 4259806..3d9fda3 100644
--- a/src/pages/SettingsNew.tsx
+++ b/src/pages/SettingsNew.tsx
@@ -72,7 +72,7 @@ const SettingsNew: React.FC = () => {
General Settings
{activeTab === 'general' && (
-
+
)}
{
Plan & Billings
{activeTab === 'billing' && (
-
+
)}
-
+
{/* General Settings Content */}
diff --git a/src/pages/Submissions.tsx b/src/pages/Submissions.tsx
new file mode 100644
index 0000000..3ce5cb5
--- /dev/null
+++ b/src/pages/Submissions.tsx
@@ -0,0 +1,326 @@
+import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useOrg } from '../contexts/OrgContext';
+import { useAuth } from '../contexts/AuthContext';
+import { secureApiPOST, secureApi } from '../services/secureApi';
+import { Employee } from '../types';
+import { EMPLOYEE_QUESTIONS } from '../employeeQuestions';
+
+interface EmployeeSubmission {
+ employeeId: string;
+ answers: Record
;
+ submittedAt: number;
+ employee?: Employee;
+}
+
+const Submissions: React.FC = () => {
+ const navigate = useNavigate();
+ const { employees, user, isOwner, orgId } = useOrg();
+ const [submissions, setSubmissions] = useState>({});
+ const [selectedEmployee, setSelectedEmployee] = useState(null);
+ const [searchQuery, setSearchQuery] = useState('');
+ const [loading, setLoading] = useState(true);
+
+ const currentUserIsOwner = isOwner(user?.uid || '');
+
+ // Load submissions on component mount
+ useEffect(() => {
+ const loadSubmissions = async () => {
+ try {
+ setLoading(true);
+ // Use the secure API service to get submissions
+ // const data = await secureApi.getSubmissions();
+ const data = { submissions: [] }; // temp fix
+
+ if (data) {
+ setSubmissions(data.submissions);
+
+ // Auto-select first employee with submission
+ const employeesWithSubmissions = employees.filter(emp => data.submissions?.[emp.id]);
+ if (employeesWithSubmissions.length > 0) {
+ setSelectedEmployee(employeesWithSubmissions[0]);
+ }
+ } else {
+ console.error('Failed to load submissions:', response.statusText);
+ }
+ } catch (error) {
+ console.error('Error loading submissions:', error);
+ // Load demo data for development
+ loadDemoSubmissions();
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ loadSubmissions();
+ }, [employees]);
+
+ const loadDemoSubmissions = () => {
+ // Demo submission data for testing
+ const demoSubmissions: Record = {};
+
+ employees.forEach((employee, index) => {
+ if (index < 3) { // Only add submissions for first 3 employees
+ demoSubmissions[employee.id] = {
+ employeeId: employee.id,
+ employee,
+ submittedAt: Date.now() - (index * 86400000), // Stagger dates
+ answers: {
+ full_name: employee.name,
+ email: employee.email,
+ title_department: employee.role || 'Team Member',
+ mission: 'To empower small businesses with AI-driven automation tools that increase efficiency and reduce operational overhead.',
+ mission_evolution: 'We shifted from general SaaS tools to vertical-specific solutions, with deeper integrations and onboarding support.',
+ vision: 'To become the leading AI operations platform for SMBs in North America, serving over 100,000 customers.',
+ advantages: 'Fast product iteration enabled by in-house AI capabilities\nDeep customer understanding from vertical specialization\nHigh customer retention due to integrated onboarding',
+ vulnerabilities: 'Dependence on a single marketing channel, weak middle management, and rising customer acquisition costs.',
+ role_clarity: 'I understand my role clearly and feel aligned with company objectives.',
+ performance_output: 'I consistently deliver high-quality work and meet deadlines.',
+ collaboration: 'I work well with my team and communicate effectively.',
+ additional_feedback: 'I would appreciate more structured processes and clearer communication channels.'
+ }
+ };
+ }
+ });
+
+ setSubmissions(demoSubmissions);
+ const employeesWithSubmissions = employees.filter(emp => demoSubmissions[emp.id]);
+ if (employeesWithSubmissions.length > 0) {
+ setSelectedEmployee(employeesWithSubmissions[0]);
+ }
+ };
+
+ // Filter employees: show only those with submissions, and apply search
+ const visibleEmployees = employees
+ .filter(emp => submissions[emp.id]) // Only employees with submissions
+ .filter(emp => emp.name.toLowerCase().includes(searchQuery.toLowerCase()))
+ .sort((a, b) => a.name.localeCompare(b.name));
+
+ const handleEmployeeSelect = (employee: Employee) => {
+ setSelectedEmployee(employee);
+ };
+
+ const handleViewReport = () => {
+ if (selectedEmployee) {
+ // Navigate to reports page with the selected employee
+ navigate('/reports', { state: { selectedEmployeeId: selectedEmployee.id } });
+ }
+ };
+
+ const handleChatWithAI = () => {
+ if (selectedEmployee) {
+ // Navigate to chat page with employee context
+ navigate('/chat', { state: { employeeContext: selectedEmployee } });
+ }
+ };
+
+ // Get questions and answers for selected employee
+ const getEmployeeQuestionsAndAnswers = () => {
+ if (!selectedEmployee || !submissions[selectedEmployee.id]) {
+ return [];
+ }
+
+ const submission = submissions[selectedEmployee.id];
+ const questionsAndAnswers: Array<{ question: string; answer: string; isLong?: boolean }> = [];
+
+ // Map EMPLOYEE_QUESTIONS to actual answers
+ EMPLOYEE_QUESTIONS.forEach(q => {
+ const answer = submission.answers[q.id];
+ if (answer && answer.trim()) {
+ questionsAndAnswers.push({
+ question: q.prompt,
+ answer: answer,
+ isLong: answer.length > 150 // Mark long answers for different styling
+ });
+ }
+ });
+
+ return questionsAndAnswers;
+ };
+
+ if (loading) {
+ return (
+
+
+
+ Loading Submissions...
+
+
+
+ );
+ }
+
+ return (
+
+ {/* Middle Section - Employee List */}
+
+
+
+
+ {/* Search */}
+
+
+
+
+
setSearchQuery(e.target.value)}
+ className="flex-1 bg-transparent text-[--Neutrals-NeutralSlate500] text-sm font-normal font-['Inter'] leading-tight outline-none"
+ />
+
+
+
+
+ {/* Employee List */}
+
+ {visibleEmployees.length === 0 ? (
+
+ {searchQuery ? 'No employees found matching your search.' : 'No employee submissions found.'}
+
+ ) : (
+ visibleEmployees.map((employee) => (
+
handleEmployeeSelect(employee)}
+ >
+
+
+ {employee.initials}
+
+
+
+ {employee.name}
+
+
+ ))
+ )}
+
+
+
+
+ {/* Main Content Area */}
+
+ {selectedEmployee ? (
+
+ ) : (
+
+
+
+ Select an Employee
+
+
+ Choose an employee from the list to view their submission answers.
+
+
+
+ )}
+
+
+
+ );
+};
+
+// Component for displaying submission content
+const SubmissionContent: React.FC<{
+ employee: Employee;
+ submission: EmployeeSubmission;
+ onViewReport: () => void;
+ onChatWithAI: () => void;
+ questionsAndAnswers: Array<{ question: string; answer: string; isLong?: boolean }>;
+}> = ({ employee, submission, onViewReport, onChatWithAI, questionsAndAnswers }) => {
+ return (
+ <>
+ {/* Header */}
+
+
+ {employee.name}'s Answers
+
+
+
+
+ {/* Content */}
+
+ {questionsAndAnswers.length === 0 ? (
+
+
No submission data available for this employee.
+
+ ) : (
+ questionsAndAnswers.map((qa, index) => (
+
+ ))
+ )}
+
+ >
+ );
+};
+
+export default Submissions;
\ No newline at end of file
diff --git a/src/pages/figma/ChatAIResponse.tsx b/src/pages/figma/ChatAIResponse.tsx
index 5b3b73d..7ef45ae 100644
--- a/src/pages/figma/ChatAIResponse.tsx
+++ b/src/pages/figma/ChatAIResponse.tsx
@@ -153,9 +153,9 @@ const ChatAIResponse: React.FC = () => {
{/* User Question */}
-
+
What are the main characteristics?
-
+
{/* Chat Input */}
-
+
Ask anything, use @ to tag staff and ask questions.
@@ -204,7 +204,7 @@ const ChatAIResponse: React.FC = () => {
-
+
-
+
How can the company serve them better?
-
+
How can the company serve them better?
-
+
How can the company serve them better?
-
+
-
+
Ask anything, use @ to tag staff and ask questions.
@@ -237,7 +237,7 @@ const ChatLight: React.FC = () => {
-
+