- Company Profile
-
+ {/* Company Profile - Q&A Format from Onboarding */}
+
+
Company Profile
+
{org?.mission && (
-
-
Mission
-
{org.mission}
-
+
+
+
+
Question:
+
What is your company's mission?
+
+
+
Answer:
+
{org.mission}
+
+
+
)}
{org?.vision && (
-
-
Vision
-
{org.vision}
-
+
+
+
+
Question:
+
What is your company's vision?
+
+
+
Answer:
+
{org.vision}
+
+
+
)}
{org?.evolution && (
-
-
Company Evolution
-
{org.evolution}
-
+
+
+
+
Question:
+
How has your company evolved over time?
+
+
+
Answer:
+
{org.evolution}
+
+
+
)}
{org?.advantages && (
-
-
Competitive Advantages
-
{org.advantages}
-
+
+
+
+
Question:
+
What are your competitive advantages?
+
+
+
Answer:
+
{org.advantages}
+
+
+
)}
{org?.vulnerabilities && (
-
-
Vulnerabilities
-
{org.vulnerabilities}
-
+
+
+
+
Question:
+
What are your key vulnerabilities?
+
+
+
Answer:
+
{org.vulnerabilities}
+
+
+
)}
{org?.shortTermGoals && (
-
-
Short Term Goals
-
{org.shortTermGoals}
-
+
+
+
+
Question:
+
What are your short-term goals?
+
+
+
Answer:
+
{org.shortTermGoals}
+
+
+
)}
{org?.longTermGoals && (
-
-
Long Term Goals
-
{org.longTermGoals}
-
+
+
+
+
Question:
+
What are your long-term goals?
+
+
+
Answer:
+
{org.longTermGoals}
+
+
+
)}
{org?.cultureDescription && (
-
-
Culture
-
{org.cultureDescription}
-
+
+
+
+
Question:
+
How would you describe your company culture?
+
+
+
Answer:
+
{org.cultureDescription}
+
+
+
)}
{org?.workEnvironment && (
-
-
Work Environment
-
{org.workEnvironment}
-
+
+
+
+
Question:
+
What is your work environment like?
+
+
+
Answer:
+
{org.workEnvironment}
+
+
+
)}
{org?.additionalContext && (
-
-
Additional Context
-
{org.additionalContext}
-
+
+
+
+
Question:
+
Any additional context about your company?
+
+
+
Answer:
+
{org.additionalContext}
+
+
+
)}
-
+
{org?.description && (
diff --git a/pages/EmployeeData.tsx b/pages/EmployeeData.tsx
index 31a7d5b..28bd23c 100644
--- a/pages/EmployeeData.tsx
+++ b/pages/EmployeeData.tsx
@@ -5,6 +5,7 @@ import { CompanyReport, Employee, Report } from '../types';
import RadarPerformanceChart from '../components/charts/RadarPerformanceChart';
import ScoreBarList from '../components/charts/ScoreBarList';
import { SAMPLE_COMPANY_REPORT } from '../constants';
+import ReportDetail from './ReportDetail';
interface EmployeeDataProps {
mode: 'submissions' | 'reports';
@@ -47,7 +48,7 @@ const CompanyReportCard: React.FC<{ report: CompanyReport }> = ({ report }) => {
Departments
-
{report.overview.departmentBreakdown.length}
+
{report.overview.departmentBreakdown.length}
Avg Performance
@@ -219,7 +220,8 @@ const EmployeeCard: React.FC<{
isOwner: boolean;
onGenerateReport?: (employee: Employee) => void;
isGeneratingReport?: boolean;
-}> = ({ employee, report, mode, isOwner, onGenerateReport, isGeneratingReport }) => {
+ onViewReport?: (report: Report, employeeName: string) => void;
+}> = ({ employee, report, mode, isOwner, onGenerateReport, isGeneratingReport, onViewReport }) => {
const [isExpanded, setIsExpanded] = useState(false);
return (
@@ -243,13 +245,22 @@ const EmployeeCard: React.FC<{
{report && (
-
+ <>
+
+
+ >
)}
{isOwner && mode === 'reports' && (
{/* Company Report - Only visible to owners in reports mode */}
- {currentUserIsOwner && mode === 'reports' && companyReport && (
-
+ {currentUserIsOwner && mode === 'reports' && (
+
+ {companyReport ? (
+
+
+
Company Report
+
+
+
+
+
+
+
+ ) : (
+
+
+
+ Generate Company Report
+
+
+ Create a comprehensive AI-powered report analyzing your organization's performance,
+ strengths, and recommendations based on employee data.
+
+
+
+
+ )}
+
)}
{/* Employee Cards */}
@@ -442,10 +504,21 @@ const EmployeeData: React.FC = ({ mode }) => {
isOwner={currentUserIsOwner}
onGenerateReport={handleGenerateReport}
isGeneratingReport={generatingReports.has(employee.id)}
+ onViewReport={(report, employeeName) => setSelectedReport({ report, type: 'employee', employeeName })}
/>
))
)}
+
+ {/* Report Detail Modal */}
+ {selectedReport && (
+ setSelectedReport(null)}
+ />
+ )}
);
};
diff --git a/pages/EmployeeQuestionnaire.tsx b/pages/EmployeeQuestionnaire.tsx
index 594b2de..2f3ba30 100644
--- a/pages/EmployeeQuestionnaire.tsx
+++ b/pages/EmployeeQuestionnaire.tsx
@@ -15,17 +15,28 @@ const EmployeeQuestionnaire: React.FC = () => {
const location = useLocation();
const params = useParams();
const { user } = useAuth();
- const { submitEmployeeAnswers, generateEmployeeReport, employees } = useOrg();
+
+ // 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 [answers, setAnswers] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState('');
const [inviteEmployee, setInviteEmployee] = useState(null);
const [isLoadingInvite, setIsLoadingInvite] = useState(false);
- // Check if this is an invite-based flow (no auth needed)
- const inviteCode = params.inviteCode;
- const isInviteFlow = !!inviteCode;
-
// Load invite details if this is an invite flow
useEffect(() => {
if (inviteCode) {
@@ -36,15 +47,24 @@ const EmployeeQuestionnaire: React.FC = () => {
const loadInviteDetails = async (code: string) => {
setIsLoadingInvite(true);
try {
- const response = await fetch(`${API_URL}/api/invitations/${code}`);
+ // Use Cloud Function endpoint for invite status
+ const response = await fetch(`${API_URL}/getInvitationStatus?code=${code}`);
if (response.ok) {
const data = await response.json();
- setInviteEmployee(data.employee);
- setError('');
+ if (data.used) {
+ setError('This invitation has already been used');
+ } else if (data.employee) {
+ setInviteEmployee(data.employee);
+ setError('');
+ } else {
+ setError('Invalid invitation data');
+ }
} else {
- setError('Invalid or expired invitation link');
+ 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);
@@ -120,30 +140,39 @@ const EmployeeQuestionnaire: React.FC = () => {
}));
};
- const submitViaInvite = async (employee: any, answers: EmployeeSubmissionAnswers, inviteCode: string) => {
+ const submitViaInvite = async (answers: EmployeeSubmissionAnswers, inviteCode: string) => {
try {
// First, consume the invite to mark it as used
- const consumeResponse = await fetch(`${API_URL}/api/invitations/${inviteCode}/consume`, {
- method: 'POST'
+ 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');
}
- // Submit the questionnaire answers
- const submitResponse = await fetch(`${API_URL}/api/employee-submissions`, {
+ // 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({
- employeeId: employee.id,
- employee: employee,
- answers: answers
+ inviteCode: inviteCode,
+ answers: answers,
+ orgId: orgId
})
});
if (!submitResponse.ok) {
- throw new Error('Failed to submit questionnaire');
+ const errorData = await submitResponse.json();
+ throw new Error(errorData.error || 'Failed to submit questionnaire');
}
const result = await submitResponse.json();
@@ -223,7 +252,7 @@ const EmployeeQuestionnaire: React.FC = () => {
let result;
if (isInviteFlow) {
// Direct API submission for invite flow (no auth needed)
- result = await submitViaInvite(currentEmployee, answers, inviteCode);
+ result = await submitViaInvite(answers, inviteCode);
} else {
// Use org context for authenticated flow
result = await submitEmployeeAnswers(currentEmployee.id, answers);
@@ -338,7 +367,7 @@ const EmployeeQuestionnaire: React.FC = () => {
-