update onboarding colors and add image upload
This commit is contained in:
@@ -82,70 +82,6 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
useEffect(() => {
|
||||
console.log('OrgContext effect running, orgId:', orgId, 'isFirebaseConfigured:', isFirebaseConfigured);
|
||||
if (!orgId) return; // Wait for orgId to be available
|
||||
if (!isFirebaseConfigured) {
|
||||
// Demo mode data - use persistent localStorage with proper initialization
|
||||
console.log('Setting up demo org data with persistence');
|
||||
|
||||
// Get or create persistent demo org
|
||||
let demoOrg = demoStorage.getOrganization(orgId);
|
||||
if (!demoOrg) {
|
||||
demoOrg = {
|
||||
orgId: orgId,
|
||||
name: 'Demo Company',
|
||||
onboardingCompleted: false
|
||||
};
|
||||
demoStorage.saveOrganization(demoOrg);
|
||||
|
||||
// Initialize with empty employee list for clean start
|
||||
// (Removed automatic seeding of 6 default employees per user feedback)
|
||||
|
||||
// Don't automatically create sample submissions - let users create real data
|
||||
// through the proper questionnaire flow
|
||||
|
||||
// Note: Sample employee reports removed - real reports generated via AI after questionnaire submission
|
||||
|
||||
// Don't save sample company report - let users generate real AI-powered reports
|
||||
}
|
||||
|
||||
// Load persistent demo data
|
||||
setOrg({ orgId, name: demoOrg.name, onboardingCompleted: demoOrg.onboardingCompleted });
|
||||
|
||||
// Convert employees to expected format
|
||||
const demoEmployees = demoStorage.getEmployeesByOrg(orgId);
|
||||
const convertedEmployees: Employee[] = demoEmployees.map(emp => ({
|
||||
id: emp.id,
|
||||
name: emp.name,
|
||||
email: emp.email,
|
||||
initials: emp.name ? emp.name.split(' ').map(n => n[0]).join('').toUpperCase() : emp.email.substring(0, 2).toUpperCase(),
|
||||
department: emp.department,
|
||||
role: emp.role,
|
||||
isOwner: emp.id === user?.uid
|
||||
}));
|
||||
setEmployees(convertedEmployees);
|
||||
|
||||
// Load any existing submissions from localStorage
|
||||
const orgSubmissions = demoStorage.getSubmissionsByOrg(orgId);
|
||||
const convertedSubmissions: Record<string, Submission> = {};
|
||||
Object.entries(orgSubmissions).forEach(([employeeId, demoSub]) => {
|
||||
convertedSubmissions[employeeId] = {
|
||||
employeeId,
|
||||
answers: Object.entries(demoSub.answers).map(([question, answer]) => ({
|
||||
question,
|
||||
answer
|
||||
}))
|
||||
};
|
||||
});
|
||||
setSubmissions(convertedSubmissions);
|
||||
|
||||
// Load any existing AI-generated reports from localStorage
|
||||
const orgReports = demoStorage.getEmployeeReportsByOrg(orgId);
|
||||
setReports(orgReports);
|
||||
|
||||
// Load any existing company reports from localStorage
|
||||
const companyReports = demoStorage.getCompanyReportsByOrg(orgId);
|
||||
setFullCompanyReports(companyReports);
|
||||
return;
|
||||
}
|
||||
console.log('Setting up Firebase org data');
|
||||
const orgRef = doc(db, 'orgs', orgId);
|
||||
getDoc(orgRef).then(async (snap) => {
|
||||
@@ -183,89 +119,27 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
}, [orgId]);
|
||||
|
||||
const upsertOrg = async (data: Partial<OrgData>) => {
|
||||
if (!isFirebaseConfigured) {
|
||||
const updatedOrg = { ...(org || { orgId, name: 'Demo Company' }), ...data } as OrgData;
|
||||
setOrg(updatedOrg);
|
||||
|
||||
// If onboarding was completed, update localStorage for persistence and notify other contexts
|
||||
if (data.onboardingCompleted) {
|
||||
const demoOrgData = {
|
||||
orgId: updatedOrg.orgId,
|
||||
name: updatedOrg.name,
|
||||
onboardingCompleted: updatedOrg.onboardingCompleted || false,
|
||||
...updatedOrg // Include all additional fields
|
||||
};
|
||||
demoStorage.saveOrganization(demoOrgData);
|
||||
|
||||
console.log('OrgContext: Onboarding completed, dispatching update event', {
|
||||
orgId: updatedOrg.orgId,
|
||||
onboardingCompleted: true
|
||||
});
|
||||
|
||||
// Signal to UserOrganizationsContext and other components about completion
|
||||
window.dispatchEvent(new CustomEvent('organizationUpdated', {
|
||||
detail: { orgId: updatedOrg.orgId, onboardingCompleted: true }
|
||||
}));
|
||||
}
|
||||
|
||||
// Organization already exists, no need to sync with server during onboarding
|
||||
// We'll update Firestore directly in the Firebase mode below
|
||||
} else {
|
||||
// Firebase mode - save to Firestore
|
||||
const orgRef = doc(db, 'orgs', orgId);
|
||||
await setDoc(orgRef, data, { merge: true });
|
||||
|
||||
// Update local state
|
||||
const updatedOrg = { ...(org || { orgId, name: 'Your Company' }), ...data } as OrgData;
|
||||
setOrg(updatedOrg);
|
||||
|
||||
// If onboarding was completed, notify other contexts
|
||||
if (data.onboardingCompleted) {
|
||||
console.log('OrgContext (Firebase): Onboarding completed, dispatching update event', {
|
||||
orgId: updatedOrg.orgId,
|
||||
onboardingCompleted: true
|
||||
});
|
||||
|
||||
window.dispatchEvent(new CustomEvent('organizationUpdated', {
|
||||
detail: { orgId: updatedOrg.orgId, onboardingCompleted: true }
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const updateOrg = async (data: Partial<OrgData>) => {
|
||||
if (!isFirebaseConfigured) {
|
||||
const updatedOrg = { ...(org || { orgId, name: 'Demo Company' }), ...data } as OrgData;
|
||||
setOrg(updatedOrg);
|
||||
|
||||
// Also sync with server for multi-tenant persistence
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/api/organizations/${orgId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.warn('Failed to sync organization data with server');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to sync organization data:', error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
const orgRef = doc(db, 'orgs', orgId);
|
||||
await setDoc(orgRef, data, { merge: true });
|
||||
|
||||
// Update local state
|
||||
const updatedOrg = { ...(org || { orgId, name: 'Your Company' }), ...data } as OrgData;
|
||||
setOrg(updatedOrg);
|
||||
|
||||
// If onboarding was completed, notify other contexts
|
||||
if (data.onboardingCompleted) {
|
||||
console.log('OrgContext (Firebase): Onboarding completed, dispatching update event', {
|
||||
orgId: updatedOrg.orgId,
|
||||
onboardingCompleted: true
|
||||
});
|
||||
|
||||
window.dispatchEvent(new CustomEvent('organizationUpdated', {
|
||||
detail: { orgId: updatedOrg.orgId, onboardingCompleted: true }
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const saveReport = async (employeeId: string, report: Report) => {
|
||||
if (!isFirebaseConfigured) {
|
||||
setReports(prev => ({ ...prev, [employeeId]: report }));
|
||||
// Persist to localStorage
|
||||
demoStorage.saveEmployeeReport(orgId, employeeId, report);
|
||||
return;
|
||||
}
|
||||
const ref = doc(db, 'orgs', orgId, 'reports', employeeId);
|
||||
await setDoc(ref, report, { merge: true });
|
||||
};
|
||||
@@ -446,7 +320,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
// Exclude owners from employee counts - they are company wiki contributors, not employees
|
||||
const actualEmployees = employees.filter(emp => !emp.isOwner);
|
||||
const totalEmployees = actualEmployees.length;
|
||||
|
||||
|
||||
// Only count submissions from non-owner employees
|
||||
const employeeSubmissions = Object.fromEntries(
|
||||
Object.entries(submissions).filter(([employeeId]) => {
|
||||
@@ -539,7 +413,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
|
||||
const payload = await res.json();
|
||||
console.log('API success response:', payload);
|
||||
|
||||
|
||||
// Ensure the report has all required fields to prevent undefined errors
|
||||
const data: CompanyReport = {
|
||||
id: Date.now().toString(),
|
||||
@@ -565,7 +439,7 @@ export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: s
|
||||
// Override with API data if available
|
||||
...(payload.report || payload)
|
||||
};
|
||||
|
||||
|
||||
await saveFullCompanyReport(data);
|
||||
return data;
|
||||
} catch (e) {
|
||||
|
||||
@@ -41,26 +41,14 @@ export const UserOrganizationsProvider: React.FC<{ children: React.ReactNode }>
|
||||
}
|
||||
|
||||
try {
|
||||
if (!isFirebaseConfigured) {
|
||||
// Demo mode - fetch from server API
|
||||
const response = await fetch(`${API_URL}/api/user/${user.uid}/organizations`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setOrganizations(data.organizations || []);
|
||||
} else {
|
||||
console.error('Failed to load organizations:', response.status);
|
||||
setOrganizations([]);
|
||||
}
|
||||
// Firebase mode - fetch from Cloud Functions
|
||||
const response = await fetch(`${API_URL}/getUserOrganizations?userId=${user.uid}`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setOrganizations(data.organizations || []);
|
||||
} else {
|
||||
// Firebase mode - fetch from Cloud Functions
|
||||
const response = await fetch(`${API_URL}/getUserOrganizations?userId=${user.uid}`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setOrganizations(data.organizations || []);
|
||||
} else {
|
||||
console.error('Failed to load organizations:', response.status);
|
||||
setOrganizations([]);
|
||||
}
|
||||
console.error('Failed to load organizations:', response.status);
|
||||
setOrganizations([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load organizations:', error);
|
||||
@@ -134,53 +122,29 @@ export const UserOrganizationsProvider: React.FC<{ children: React.ReactNode }>
|
||||
let newOrg: UserOrganization;
|
||||
let requiresSubscription = false;
|
||||
|
||||
if (!isFirebaseConfigured) {
|
||||
// Demo mode - use server API
|
||||
const response = await fetch(`${API_URL}/api/organizations`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, userId: user.uid })
|
||||
});
|
||||
// Firebase mode - use Cloud Function
|
||||
const response = await fetch(`${API_URL}/createOrganization`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, userId: user.uid })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to create organization: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
newOrg = {
|
||||
orgId: data.orgId,
|
||||
name: data.name,
|
||||
role: data.role,
|
||||
onboardingCompleted: data.onboardingCompleted,
|
||||
joinedAt: data.joinedAt
|
||||
};
|
||||
|
||||
setOrganizations(prev => [...prev, newOrg]);
|
||||
} else {
|
||||
// Firebase mode - use Cloud Function
|
||||
const response = await fetch(`${API_URL}/createOrganization`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, userId: user.uid })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to create organization: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
newOrg = {
|
||||
orgId: data.orgId,
|
||||
name: data.name,
|
||||
role: data.role,
|
||||
onboardingCompleted: data.onboardingCompleted,
|
||||
joinedAt: data.joinedAt
|
||||
};
|
||||
|
||||
requiresSubscription = data.requiresSubscription || false;
|
||||
setOrganizations(prev => [...prev, newOrg]);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to create organization: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
newOrg = {
|
||||
orgId: data.orgId,
|
||||
name: data.name,
|
||||
role: data.role,
|
||||
onboardingCompleted: data.onboardingCompleted,
|
||||
joinedAt: data.joinedAt
|
||||
};
|
||||
|
||||
requiresSubscription = data.requiresSubscription || false;
|
||||
setOrganizations(prev => [...prev, newOrg]);
|
||||
|
||||
return { orgId: newOrg.orgId, requiresSubscription };
|
||||
} catch (error) {
|
||||
console.error('Failed to create organization:', error);
|
||||
@@ -192,70 +156,70 @@ export const UserOrganizationsProvider: React.FC<{ children: React.ReactNode }>
|
||||
if (!user) throw new Error('User not authenticated');
|
||||
|
||||
try {
|
||||
if (!isFirebaseConfigured) {
|
||||
// Demo mode - use server API to get and consume invite
|
||||
const inviteStatusRes = await fetch(`/api/invitations/${inviteCode}`);
|
||||
if (!inviteStatusRes.ok) {
|
||||
throw new Error('Invalid or expired invite code');
|
||||
}
|
||||
// if (!isFirebaseConfigured) {
|
||||
// // Demo mode - use server API to get and consume invite
|
||||
// const inviteStatusRes = await fetch(`/api/invitations/${inviteCode}`);
|
||||
// if (!inviteStatusRes.ok) {
|
||||
// throw new Error('Invalid or expired invite code');
|
||||
// }
|
||||
|
||||
const inviteData = await inviteStatusRes.json();
|
||||
if (inviteData.used) {
|
||||
throw new Error('Invite code has already been used');
|
||||
}
|
||||
// const inviteData = await inviteStatusRes.json();
|
||||
// if (inviteData.used) {
|
||||
// throw new Error('Invite code has already been used');
|
||||
// }
|
||||
|
||||
// Consume the invite
|
||||
const consumeRes = await fetch(`/api/invitations/${inviteCode}/consume`, {
|
||||
method: 'POST'
|
||||
});
|
||||
if (!consumeRes.ok) {
|
||||
throw new Error('Failed to consume invite');
|
||||
}
|
||||
// // Consume the invite
|
||||
// const consumeRes = await fetch(`/api/invitations/${inviteCode}/consume`, {
|
||||
// method: 'POST'
|
||||
// });
|
||||
// if (!consumeRes.ok) {
|
||||
// throw new Error('Failed to consume invite');
|
||||
// }
|
||||
|
||||
const consumedData = await consumeRes.json();
|
||||
const orgId = consumedData.orgId;
|
||||
// const consumedData = await consumeRes.json();
|
||||
// const orgId = consumedData.orgId;
|
||||
|
||||
// Get organization data (this might be from localStorage for demo mode)
|
||||
const orgData = demoStorage.getOrganization(orgId);
|
||||
if (!orgData) {
|
||||
throw new Error('Organization not found');
|
||||
}
|
||||
// // Get organization data (this might be from localStorage for demo mode)
|
||||
// const orgData = demoStorage.getOrganization(orgId);
|
||||
// if (!orgData) {
|
||||
// throw new Error('Organization not found');
|
||||
// }
|
||||
|
||||
const userOrg: UserOrganization = {
|
||||
orgId: orgId,
|
||||
name: orgData.name,
|
||||
role: 'employee',
|
||||
onboardingCompleted: orgData.onboardingCompleted || false,
|
||||
joinedAt: Date.now()
|
||||
};
|
||||
// const userOrg: UserOrganization = {
|
||||
// orgId: orgId,
|
||||
// name: orgData.name,
|
||||
// role: 'employee',
|
||||
// onboardingCompleted: orgData.onboardingCompleted || false,
|
||||
// joinedAt: Date.now()
|
||||
// };
|
||||
|
||||
setOrganizations(prev => [...prev, userOrg]);
|
||||
return orgId;
|
||||
} else {
|
||||
// Firebase mode - use Cloud Function
|
||||
const response = await fetch(`${API_URL}/joinOrganization`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ userId: user.uid, inviteCode })
|
||||
});
|
||||
// setOrganizations(prev => [...prev, userOrg]);
|
||||
// return orgId;
|
||||
// } else {
|
||||
// Firebase mode - use Cloud Function
|
||||
const response = await fetch(`${API_URL}/joinOrganization`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ userId: user.uid, inviteCode })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.error || 'Failed to join organization');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const userOrg: UserOrganization = {
|
||||
orgId: data.orgId,
|
||||
name: data.name,
|
||||
role: data.role,
|
||||
onboardingCompleted: data.onboardingCompleted,
|
||||
joinedAt: data.joinedAt
|
||||
};
|
||||
|
||||
setOrganizations(prev => [...prev, userOrg]);
|
||||
return data.orgId;
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.error || 'Failed to join organization');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const userOrg: UserOrganization = {
|
||||
orgId: data.orgId,
|
||||
name: data.name,
|
||||
role: data.role,
|
||||
onboardingCompleted: data.onboardingCompleted,
|
||||
joinedAt: data.joinedAt
|
||||
};
|
||||
|
||||
setOrganizations(prev => [...prev, userOrg]);
|
||||
return data.orgId;
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error('Failed to join organization:', error);
|
||||
throw error;
|
||||
|
||||
Reference in New Issue
Block a user