fix most of the listed bugs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import { useAuth } from './AuthContext';
|
||||
import { Employee, EmployeeReport, Submission, CompanyReport } from '../types';
|
||||
import { SAMPLE_COMPANY_REPORT, API_URL } from '../constants';
|
||||
@@ -9,11 +9,19 @@ import { secureApi } from '../services/secureApi';
|
||||
|
||||
interface OrgData {
|
||||
orgId: string;
|
||||
name?: string;
|
||||
companyName?: string;
|
||||
onboardingData?: Record<string, any>;
|
||||
companyLogo?: string;
|
||||
updatedAt?: number;
|
||||
onboardingCompleted?: boolean;
|
||||
ownerId?: string;
|
||||
ownerInfo?: {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
joinedAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface OrgContextType {
|
||||
@@ -63,7 +71,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
// Use the provided selectedOrgId instead of deriving from user
|
||||
const orgId = selectedOrgId;
|
||||
|
||||
// Load initial data using secure API
|
||||
// Load initial data using secure API - memoized to prevent unnecessary re-runs
|
||||
useEffect(() => {
|
||||
if (!orgId || !user?.uid) {
|
||||
setLoading(false);
|
||||
@@ -76,54 +84,57 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// Load organization data
|
||||
try {
|
||||
const orgData = await secureApi.getOrgData();
|
||||
setOrg({ orgId, ...orgData });
|
||||
} catch (error) {
|
||||
console.warn('Could not load org data, creating default:', error);
|
||||
// Create default org if not found
|
||||
// Batch all API calls for better performance
|
||||
const [orgData, employeesData, submissionsData, reportsData, companyReportsData] = await Promise.allSettled([
|
||||
secureApi.getOrgData().catch(() => null),
|
||||
secureApi.getEmployees().catch(() => []),
|
||||
secureApi.getSubmissions().catch(() => ({})),
|
||||
secureApi.getReports().catch(() => ({})),
|
||||
secureApi.getCompanyReports().catch(() => [])
|
||||
]);
|
||||
|
||||
// Process organization data
|
||||
if (orgData.status === 'fulfilled' && orgData.value) {
|
||||
setOrg({ orgId, ...orgData.value });
|
||||
} else {
|
||||
console.warn('Could not load org data, creating default');
|
||||
const defaultOrg = { name: 'Your Company', onboardingCompleted: false };
|
||||
await secureApi.updateOrgData(defaultOrg);
|
||||
setOrg({ orgId, ...defaultOrg });
|
||||
}
|
||||
|
||||
// Load employees
|
||||
try {
|
||||
const employeesData = await secureApi.getEmployees();
|
||||
setEmployees(employeesData.map(emp => ({
|
||||
// Process employees data
|
||||
if (employeesData.status === 'fulfilled') {
|
||||
setEmployees(employeesData.value.map(emp => ({
|
||||
...emp,
|
||||
initials: emp.name ? emp.name.split(' ').map(n => n[0]).join('').toUpperCase() : emp.email?.substring(0, 2).toUpperCase() || 'U'
|
||||
})));
|
||||
} catch (error) {
|
||||
console.warn('Could not load employees:', error);
|
||||
} else {
|
||||
console.warn('Could not load employees');
|
||||
setEmployees([]);
|
||||
}
|
||||
|
||||
// Load submissions
|
||||
try {
|
||||
const submissionsData = await secureApi.getSubmissions();
|
||||
setSubmissions(submissionsData);
|
||||
} catch (error) {
|
||||
console.warn('Could not load submissions:', error);
|
||||
// Process submissions data
|
||||
if (submissionsData.status === 'fulfilled') {
|
||||
setSubmissions(submissionsData.value);
|
||||
} else {
|
||||
console.warn('Could not load submissions');
|
||||
setSubmissions({});
|
||||
}
|
||||
|
||||
// Load reports
|
||||
try {
|
||||
const reportsData = await secureApi.getReports();
|
||||
setReports(reportsData as Record<string, EmployeeReport>);
|
||||
} catch (error) {
|
||||
console.warn('Could not load reports:', error);
|
||||
// Process reports data
|
||||
if (reportsData.status === 'fulfilled') {
|
||||
setReports(reportsData.value as Record<string, EmployeeReport>);
|
||||
} else {
|
||||
console.warn('Could not load reports');
|
||||
setReports({});
|
||||
}
|
||||
|
||||
// Load company reports
|
||||
try {
|
||||
const companyReportsData = await secureApi.getCompanyReports();
|
||||
setFullCompanyReports(companyReportsData);
|
||||
} catch (error) {
|
||||
console.warn('Could not load company reports:', error);
|
||||
// Process company reports data
|
||||
if (companyReportsData.status === 'fulfilled') {
|
||||
setFullCompanyReports(companyReportsData.value);
|
||||
} else {
|
||||
console.warn('Could not load company reports');
|
||||
setFullCompanyReports([]);
|
||||
}
|
||||
|
||||
@@ -135,9 +146,9 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
};
|
||||
|
||||
loadOrgData();
|
||||
}, [orgId, user?.uid]);
|
||||
}, [orgId, user?.uid]); // Only re-run when orgId or user changes
|
||||
|
||||
const upsertOrg = async (data: Partial<OrgData>) => {
|
||||
const upsertOrg = useCallback(async (data: Partial<OrgData>) => {
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
@@ -164,9 +175,9 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
console.error('Failed to update organization:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}, [user?.uid, org, orgId]);
|
||||
|
||||
const saveReport = async (employeeId: string, report: EmployeeReport) => {
|
||||
const saveReport = useCallback(async (employeeId: string, report: EmployeeReport) => {
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
@@ -180,7 +191,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
console.error('Failed to save report:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}, [user?.uid]);
|
||||
|
||||
const inviteEmployee = async ({ name, email, role, department }: { name: string; email: string, role?: string, department?: string }) => {
|
||||
console.log('inviteEmployee called:', { name, email, orgId });
|
||||
@@ -199,7 +210,6 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
initials: data.employee.name ? data.employee.name.split(' ').map(n => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase(),
|
||||
department: data.employee.department,
|
||||
role: data.employee.role,
|
||||
isOwner: false,
|
||||
status: data.employee.status
|
||||
};
|
||||
|
||||
@@ -332,17 +342,12 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
}
|
||||
|
||||
// Calculate concrete metrics from actual data (no AI needed)
|
||||
// Exclude owners from employee counts - they are company wiki contributors, not employees
|
||||
const actualEmployees = employees.filter(emp => !emp.isOwner);
|
||||
// Employees collection only contains actual employees (owners are not in this collection)
|
||||
const actualEmployees = employees;
|
||||
const totalEmployees = actualEmployees.length;
|
||||
|
||||
// Only count submissions from non-owner employees
|
||||
const employeeSubmissions = Object.fromEntries(
|
||||
Object.entries(submissions).filter(([employeeId]) => {
|
||||
const employee = employees.find(emp => emp.id === employeeId);
|
||||
return employee && !employee.isOwner;
|
||||
})
|
||||
);
|
||||
// Count submissions from employees
|
||||
const employeeSubmissions = submissions;
|
||||
const submittedEmployees = Object.keys(employeeSubmissions).length;
|
||||
const submissionRate = totalEmployees > 0 ? (submittedEmployees / totalEmployees) * 100 : 0;
|
||||
|
||||
@@ -356,7 +361,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
|
||||
try {
|
||||
// Use secure API for AI generation
|
||||
const data = await secureApi.generateCompanyWiki({
|
||||
let response = await secureApi.generateCompanyWiki({
|
||||
...org,
|
||||
metrics: {
|
||||
totalEmployees,
|
||||
@@ -368,25 +373,25 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
console.log('Company insights generated via AI successfully');
|
||||
|
||||
// Combine concrete metrics with AI insights
|
||||
const report: CompanyReport = {
|
||||
let report: CompanyReport = {
|
||||
id: Date.now().toString(),
|
||||
createdAt: Date.now(),
|
||||
// Use AI-generated insights for subjective analysis
|
||||
...(data as any),
|
||||
// Override with our concrete metrics
|
||||
overview: {
|
||||
totalEmployees,
|
||||
departmentBreakdown,
|
||||
submissionRate,
|
||||
lastUpdated: Date.now(),
|
||||
averagePerformanceScore: (data as any)?.overview?.averagePerformanceScore || 0,
|
||||
riskLevel: (data as any)?.overview?.riskLevel || 'Unknown'
|
||||
}
|
||||
averagePerformanceScore: (response as any)?.overview?.averagePerformanceScore || 0,
|
||||
riskLevel: (response as any)?.overview?.riskLevel || 'Unknown'
|
||||
},
|
||||
...(response as any)
|
||||
};
|
||||
|
||||
console.log('Final company report object:', report);
|
||||
await saveFullCompanyReport(report);
|
||||
return report;
|
||||
// await saveFullCompanyReport(report);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('generateCompanyReport error:', error);
|
||||
throw error;
|
||||
@@ -408,12 +413,12 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
// Use secure API for wiki generation
|
||||
try {
|
||||
console.log('Making API call to generateCompanyWiki...');
|
||||
const payload = await secureApi.generateCompanyWiki(orgData, Object.values(submissions || {}));
|
||||
let response = await secureApi.generateCompanyWiki(orgData, Object.values(submissions || {}));
|
||||
|
||||
console.log('API success response:', payload);
|
||||
console.log('API success response:', response);
|
||||
|
||||
// Ensure the report has all required fields to prevent undefined errors
|
||||
const data: CompanyReport = {
|
||||
const report: CompanyReport = {
|
||||
id: Date.now().toString(),
|
||||
createdAt: Date.now(),
|
||||
overview: {
|
||||
@@ -430,21 +435,22 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
forwardOperatingPlan: { quarterlyGoals: [], resourceNeeds: [], riskMitigation: [] },
|
||||
executiveSummary: 'Company report generated successfully.',
|
||||
// Override with API data if available
|
||||
...(payload as any || {})
|
||||
...(response as any || {})
|
||||
};
|
||||
|
||||
await saveFullCompanyReport(data);
|
||||
return data;
|
||||
// await saveFullCompanyReport(data);
|
||||
return response;
|
||||
} catch (e) {
|
||||
console.error('generateCompanyWiki error, falling back to local synthetic:', e);
|
||||
return generateCompanyReport();
|
||||
}
|
||||
};
|
||||
|
||||
const isOwner = (employeeId?: string): boolean => {
|
||||
const currentEmployee = employeeId ? employees.find(e => e.id === employeeId) :
|
||||
employees.find(e => e.email === user?.email);
|
||||
return currentEmployee?.isOwner === true;
|
||||
const isOwner = (userId?: string): boolean => {
|
||||
// Check if the given user ID matches the org owner ID
|
||||
// If no userId provided, check current user
|
||||
const targetUserId = userId || user?.uid;
|
||||
return targetUserId === org?.ownerId;
|
||||
};
|
||||
|
||||
const getEmployeeReport = async (employeeId: string) => {
|
||||
@@ -483,7 +489,141 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
}
|
||||
};
|
||||
|
||||
const value = {
|
||||
// Memoize functions that don't need dependencies
|
||||
const issueInviteViaApi = useCallback(async ({ name, email, role, department }) => {
|
||||
try {
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
|
||||
const data = await secureApi.createInvitation({ name, email, role, department });
|
||||
|
||||
// Optimistically add employee shell (not yet active until consume)
|
||||
setEmployees(prev => prev.find(e => e.id === data.employee.id) ? prev : [...prev, {
|
||||
...data.employee,
|
||||
initials: data.employee.name ? data.employee.name.split(' ').map((n: string) => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase()
|
||||
} as Employee]);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error('issueInviteViaApi error', e);
|
||||
throw e;
|
||||
}
|
||||
}, [user?.uid]);
|
||||
|
||||
const getInviteStatus = useCallback(async (code: string) => {
|
||||
try {
|
||||
return await secureApi.getInvitationStatus(code);
|
||||
} catch (e) {
|
||||
console.error('getInviteStatus error', e);
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const consumeInvite = useCallback(async (code: string) => {
|
||||
try {
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
|
||||
const result = await secureApi.consumeInvitation(code, user.uid);
|
||||
|
||||
// Mark employee as active
|
||||
if (result && (result as any).employee) {
|
||||
setEmployees(prev => prev.find(e => e.id === (result as any).employee.id) ? prev : [...prev, (result as any).employee]);
|
||||
return { ...(result as any), orgId: org?.orgId };
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error('consumeInvite error', e);
|
||||
return null;
|
||||
}
|
||||
}, [user?.uid, org?.orgId]);
|
||||
|
||||
const submitEmployeeAnswers = useCallback(async (employeeId: string, answers: Record<string, string>) => {
|
||||
try {
|
||||
// Use secure API for submission
|
||||
await secureApi.submitEmployeeAnswers(employeeId, answers);
|
||||
|
||||
// Update local state for immediate UI feedback
|
||||
const convertedSubmission: Submission = {
|
||||
employeeId,
|
||||
answers: Object.entries(answers).map(([question, answer]) => ({
|
||||
question,
|
||||
answer
|
||||
}))
|
||||
};
|
||||
setSubmissions(prev => ({ ...prev, [employeeId]: convertedSubmission }));
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('submitEmployeeAnswers error', e);
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const generateEmployeeReport = useCallback(async (employee: Employee) => {
|
||||
try {
|
||||
console.log('generateEmployeeReport called for:', employee.name, 'in org:', orgId);
|
||||
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
|
||||
// Get submission data for this employee
|
||||
const submission = submissions[employee.id];
|
||||
if (!submission) {
|
||||
throw new Error(`No questionnaire submission found for ${employee.name}. Please ensure they have completed the employee questionnaire first.`);
|
||||
}
|
||||
|
||||
// Convert submission format for API
|
||||
let submissionAnswers: Record<string, string> = {};
|
||||
if (submission.answers) {
|
||||
if (Array.isArray(submission.answers)) {
|
||||
// If answers is an array of {question, answer} objects
|
||||
submissionAnswers = submission.answers.reduce((acc, item: any) => {
|
||||
acc[item.question] = item.answer;
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
} else {
|
||||
// If answers is already a key-value object
|
||||
submissionAnswers = submission.answers as Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Submission data found:', Object.keys(submissionAnswers).length, 'answers');
|
||||
|
||||
// Get company report and wiki data for context
|
||||
let companyWiki = null;
|
||||
try {
|
||||
const companyReports = await getFullCompanyReportHistory();
|
||||
if (companyReports.length > 0) {
|
||||
companyWiki = {
|
||||
org: org,
|
||||
companyReport: companyReports[0]
|
||||
};
|
||||
console.log('Including company context in employee report generation');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Could not fetch company report for context:', error);
|
||||
}
|
||||
|
||||
const data = await secureApi.generateEmployeeReport(employee, submissionAnswers, companyWiki);
|
||||
|
||||
if ((data as any).report) {
|
||||
console.log('Employee report generated successfully');
|
||||
const report = (data as any).report as EmployeeReport;
|
||||
setReports(prev => ({ ...prev, [employee.id]: report }));
|
||||
return report;
|
||||
} else {
|
||||
throw new Error('No report data received from API');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('generateEmployeeReport error', e);
|
||||
throw e; // Re-throw to allow caller to handle
|
||||
}
|
||||
}, [user?.uid, orgId, submissions, org, getFullCompanyReportHistory]);
|
||||
|
||||
// Memoize the entire context value to prevent unnecessary re-renders
|
||||
const value = useMemo(() => ({
|
||||
org,
|
||||
orgId,
|
||||
employees,
|
||||
@@ -504,136 +644,42 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
generateCompanyWiki,
|
||||
seedInitialData,
|
||||
isOwner,
|
||||
issueInviteViaApi: async ({ name, email, role, department }) => {
|
||||
try {
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
|
||||
const data = await secureApi.createInvitation({ name, email, role, department });
|
||||
|
||||
// Optimistically add employee shell (not yet active until consume)
|
||||
setEmployees(prev => prev.find(e => e.id === data.employee.id) ? prev : [...prev, {
|
||||
...data.employee,
|
||||
initials: data.employee.name ? data.employee.name.split(' ').map((n: string) => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase()
|
||||
} as Employee]);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error('issueInviteViaApi error', e);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
getInviteStatus: async (code: string) => {
|
||||
try {
|
||||
return await secureApi.getInvitationStatus(code);
|
||||
} catch (e) {
|
||||
console.error('getInviteStatus error', e);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
consumeInvite: async (code: string) => {
|
||||
try {
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
|
||||
const result = await secureApi.consumeInvitation(code, user.uid);
|
||||
|
||||
// Mark employee as active
|
||||
if (result && (result as any).employee) {
|
||||
setEmployees(prev => prev.find(e => e.id === (result as any).employee.id) ? prev : [...prev, (result as any).employee]);
|
||||
return { ...(result as any), orgId: org?.orgId };
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error('consumeInvite error', e);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
submitEmployeeAnswers: async (employeeId: string, answers: Record<string, string>) => {
|
||||
try {
|
||||
// Use secure API for submission
|
||||
await secureApi.submitEmployeeAnswers(employeeId, answers);
|
||||
|
||||
// Update local state for immediate UI feedback
|
||||
const convertedSubmission: Submission = {
|
||||
employeeId,
|
||||
answers: Object.entries(answers).map(([question, answer]) => ({
|
||||
question,
|
||||
answer
|
||||
}))
|
||||
};
|
||||
setSubmissions(prev => ({ ...prev, [employeeId]: convertedSubmission }));
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('submitEmployeeAnswers error', e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
generateEmployeeReport: async (employee: Employee) => {
|
||||
try {
|
||||
console.log('generateEmployeeReport called for:', employee.name, 'in org:', orgId);
|
||||
|
||||
if (!user?.uid) {
|
||||
throw new Error('User authentication required');
|
||||
}
|
||||
|
||||
// Get submission data for this employee
|
||||
const submission = submissions[employee.id];
|
||||
if (!submission) {
|
||||
throw new Error(`No questionnaire submission found for ${employee.name}. Please ensure they have completed the employee questionnaire first.`);
|
||||
}
|
||||
|
||||
// Convert submission format for API
|
||||
let submissionAnswers: Record<string, string> = {};
|
||||
if (submission.answers) {
|
||||
if (Array.isArray(submission.answers)) {
|
||||
// If answers is an array of {question, answer} objects
|
||||
submissionAnswers = submission.answers.reduce((acc, item: any) => {
|
||||
acc[item.question] = item.answer;
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
} else {
|
||||
// If answers is already a key-value object
|
||||
submissionAnswers = submission.answers as Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Submission data found:', Object.keys(submissionAnswers).length, 'answers');
|
||||
|
||||
// Get company report and wiki data for context
|
||||
let companyWiki = null;
|
||||
try {
|
||||
const companyReports = await getFullCompanyReportHistory();
|
||||
if (companyReports.length > 0) {
|
||||
companyWiki = {
|
||||
org: org,
|
||||
companyReport: companyReports[0]
|
||||
};
|
||||
console.log('Including company context in employee report generation');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Could not fetch company report for context:', error);
|
||||
}
|
||||
|
||||
const data = await secureApi.generateEmployeeReport(employee, submissionAnswers, companyWiki);
|
||||
|
||||
if ((data as any).report) {
|
||||
console.log('Employee report generated successfully');
|
||||
const report = (data as any).report as EmployeeReport;
|
||||
setReports(prev => ({ ...prev, [employee.id]: report }));
|
||||
return report;
|
||||
} else {
|
||||
throw new Error('No report data received from API');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('generateEmployeeReport error', e);
|
||||
throw e; // Re-throw to allow caller to handle
|
||||
}
|
||||
},
|
||||
issueInviteViaApi,
|
||||
getInviteStatus,
|
||||
consumeInvite,
|
||||
submitEmployeeAnswers,
|
||||
generateEmployeeReport,
|
||||
getEmployeeReport,
|
||||
getEmployeeReports,
|
||||
};
|
||||
}), [
|
||||
org,
|
||||
orgId,
|
||||
employees,
|
||||
submissions,
|
||||
reports,
|
||||
loading,
|
||||
upsertOrg,
|
||||
saveReport,
|
||||
inviteEmployee,
|
||||
getReportVersions,
|
||||
saveReportVersion,
|
||||
acceptInvite,
|
||||
saveCompanyReport,
|
||||
getCompanyReportHistory,
|
||||
saveFullCompanyReport,
|
||||
getFullCompanyReportHistory,
|
||||
generateCompanyReport,
|
||||
generateCompanyWiki,
|
||||
seedInitialData,
|
||||
isOwner,
|
||||
issueInviteViaApi,
|
||||
getInviteStatus,
|
||||
consumeInvite,
|
||||
submitEmployeeAnswers,
|
||||
generateEmployeeReport,
|
||||
getEmployeeReport,
|
||||
getEmployeeReports,
|
||||
]);
|
||||
|
||||
return (
|
||||
<OrgContext.Provider value={value}>
|
||||
|
||||
Reference in New Issue
Block a user