import React, { createContext, useContext, useEffect, useState } from 'react'; import { useAuth } from './AuthContext'; import { isFirebaseConfigured } from '../services/firebase'; import { API_URL } from '../constants'; import { demoStorage } from '../services/demoStorage'; interface UserOrganization { orgId: string; name: string; role: 'owner' | 'admin' | 'employee'; onboardingCompleted: boolean; joinedAt: number; } interface UserOrganizationsContextType { organizations: UserOrganization[]; selectedOrgId: string | null; loading: boolean; selectOrganization: (orgId: string) => void; createOrganization: (name: string) => Promise<{ orgId: string; requiresSubscription?: boolean }>; joinOrganization: (inviteCode: string) => Promise; refreshOrganizations: () => Promise; createCheckoutSession: (orgId: string, userEmail: string) => Promise<{ sessionUrl: string; sessionId: string }>; getSubscriptionStatus: (orgId: string) => Promise; } const UserOrganizationsContext = createContext(undefined); export const UserOrganizationsProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const { user } = useAuth(); const [organizations, setOrganizations] = useState([]); const [selectedOrgId, setSelectedOrgId] = useState(null); const [loading, setLoading] = useState(true); // Load user's organizations const loadOrganizations = async () => { if (!user) { setOrganizations([]); setLoading(false); return; } 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([]); } } 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([]); } } } catch (error) { console.error('Failed to load organizations:', error); setOrganizations([]); } finally { setLoading(false); } }; // Initialize selected org from session storage useEffect(() => { const savedOrgId = sessionStorage.getItem('auditly_selected_org'); if (savedOrgId) { setSelectedOrgId(savedOrgId); } }, []); // Load organizations when user changes useEffect(() => { loadOrganizations(); }, [user]); const selectOrganization = (orgId: string) => { setSelectedOrgId(orgId); sessionStorage.setItem('auditly_selected_org', orgId); }; const createOrganization = async (name: string): Promise<{ orgId: string; requiresSubscription?: boolean }> => { if (!user) throw new Error('User not authenticated'); try { 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 }) }); 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]); } return { orgId: newOrg.orgId, requiresSubscription }; } catch (error) { console.error('Failed to create organization:', error); throw error; } }; const joinOrganization = async (inviteCode: string): Promise => { 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'); } 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'); } 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'); } 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 }) }); 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; } }; const refreshOrganizations = async () => { setLoading(true); await loadOrganizations(); }; const createCheckoutSession = async (orgId: string, userEmail: string): Promise<{ sessionUrl: string; sessionId: string }> => { if (!user) throw new Error('User not authenticated'); try { const response = await fetch(`${API_URL}/createCheckoutSession`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orgId, userId: user.uid, userEmail }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to create checkout session'); } const data = await response.json(); return { sessionUrl: data.sessionUrl, sessionId: data.sessionId }; } catch (error) { console.error('Failed to create checkout session:', error); throw error; } }; const getSubscriptionStatus = async (orgId: string) => { try { const response = await fetch(`${API_URL}/getSubscriptionStatus?orgId=${orgId}`); if (!response.ok) { throw new Error('Failed to get subscription status'); } const data = await response.json(); return data; } catch (error) { console.error('Failed to get subscription status:', error); throw error; } }; return ( {children} ); }; export const useUserOrganizations = () => { const context = useContext(UserOrganizationsContext); if (!context) { throw new Error('useUserOrganizations must be used within UserOrganizationsProvider'); } return context; };