155 lines
5.2 KiB
JavaScript
155 lines
5.2 KiB
JavaScript
/* eslint-disable react-refresh/only-export-components */
|
|
import { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
|
import apiClient from '../api/client';
|
|
import { getRuntimeCompanyId } from '../utils/runtimeContext';
|
|
|
|
const BusinessContext = createContext(null);
|
|
|
|
const SESSION_KEY = 'sms_active_business';
|
|
|
|
export function BusinessProvider({ children }) {
|
|
const [activeBusiness, setActiveBusinessState] = useState(null);
|
|
const [hasGlobalSms, setHasGlobalSms] = useState(false);
|
|
const [isSetupComplete, setIsSetupComplete] = useState(false);
|
|
const [hasSelectedTemplates, setHasSelectedTemplates] = useState(false);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const updateReadyState = useCallback((activeProfile, templates = [], hasProfilesOverride = false) => {
|
|
const hasProfile = !!activeProfile;
|
|
const hasGlobalSmsProfiles = hasProfile || hasProfilesOverride;
|
|
setHasGlobalSms(hasGlobalSmsProfiles);
|
|
const nextIsSetupComplete = hasProfile && activeProfile?.executionReadiness?.isSetupComplete === true;
|
|
setIsSetupComplete(nextIsSetupComplete);
|
|
const nextHasSelectedTemplates = Array.isArray(templates)
|
|
? templates.some((template) => !!template?.selectedTemplate)
|
|
: false;
|
|
setHasSelectedTemplates(nextHasSelectedTemplates);
|
|
|
|
return {
|
|
hasGlobalSms: hasGlobalSmsProfiles,
|
|
isSetupComplete: nextIsSetupComplete,
|
|
hasSelectedTemplates: nextHasSelectedTemplates,
|
|
};
|
|
}, []);
|
|
|
|
const refreshOnboardingState = useCallback(async (businessIdOverride) => {
|
|
const targetBusinessId = businessIdOverride || activeBusiness?.businessId;
|
|
|
|
if (!targetBusinessId) {
|
|
setHasGlobalSms(false);
|
|
setIsSetupComplete(false);
|
|
setHasSelectedTemplates(false);
|
|
return {
|
|
hasGlobalSms: false,
|
|
isSetupComplete: false,
|
|
hasSelectedTemplates: false,
|
|
};
|
|
}
|
|
|
|
const [smsRes, templatesRes] = await Promise.all([
|
|
apiClient.get(`/api/businesses/${targetBusinessId}/global-sms/active`).catch(() => ({ data: {} })),
|
|
apiClient.get(`/api/businesses/${targetBusinessId}/templates`).catch(() => ({ data: { templates: [] } })),
|
|
]);
|
|
|
|
return updateReadyState(
|
|
smsRes.data?.activeProfile,
|
|
templatesRes.data?.templates || [],
|
|
smsRes.data?.hasProfiles === true,
|
|
);
|
|
}, [activeBusiness?.businessId, updateReadyState]);
|
|
|
|
// On mount: rehydrate from sessionStorage and refresh from API
|
|
useEffect(() => {
|
|
async function rehydrate() {
|
|
const stored = sessionStorage.getItem(SESSION_KEY);
|
|
if (!stored) { setLoading(false); return; }
|
|
try {
|
|
const { businessId, companyId } = JSON.parse(stored);
|
|
const runtimeCompanyId = getRuntimeCompanyId();
|
|
|
|
if (runtimeCompanyId && companyId && runtimeCompanyId !== companyId) {
|
|
throw new Error('Stored business belongs to a different company context');
|
|
}
|
|
|
|
const [bizRes, smsRes] = await Promise.all([
|
|
apiClient.get(`/api/businesses/${businessId}`),
|
|
Promise.all([
|
|
apiClient.get(`/api/businesses/${businessId}/global-sms/active`).catch(() => ({ data: {} })),
|
|
apiClient.get(`/api/businesses/${businessId}/templates`).catch(() => ({ data: { templates: [] } })),
|
|
]),
|
|
]);
|
|
setActiveBusinessState(bizRes.data);
|
|
updateReadyState(
|
|
smsRes[0].data?.activeProfile,
|
|
smsRes[1].data?.templates || [],
|
|
smsRes[0].data?.hasProfiles === true,
|
|
);
|
|
sessionStorage.setItem(SESSION_KEY, JSON.stringify({
|
|
businessId,
|
|
companyId: runtimeCompanyId || companyId || '',
|
|
}));
|
|
} catch {
|
|
// Business no longer exists — clear stale session
|
|
sessionStorage.removeItem(SESSION_KEY);
|
|
setActiveBusinessState(null);
|
|
setHasGlobalSms(false);
|
|
setIsSetupComplete(false);
|
|
setHasSelectedTemplates(false);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
rehydrate();
|
|
}, [updateReadyState]);
|
|
|
|
const setActiveBusiness = useCallback(async (business) => {
|
|
setActiveBusinessState(business);
|
|
sessionStorage.setItem(SESSION_KEY, JSON.stringify({
|
|
businessId: business.businessId,
|
|
companyId: getRuntimeCompanyId(),
|
|
}));
|
|
try {
|
|
const progress = await refreshOnboardingState(business.businessId);
|
|
return progress.isSetupComplete;
|
|
} catch {
|
|
setHasGlobalSms(false);
|
|
setIsSetupComplete(false);
|
|
setHasSelectedTemplates(false);
|
|
return false;
|
|
}
|
|
}, [refreshOnboardingState]);
|
|
|
|
const clearBusiness = useCallback(() => {
|
|
setActiveBusinessState(null);
|
|
setHasGlobalSms(false);
|
|
setIsSetupComplete(false);
|
|
setHasSelectedTemplates(false);
|
|
sessionStorage.removeItem(SESSION_KEY);
|
|
}, []);
|
|
|
|
const activeBusinessId = activeBusiness?.businessId || null;
|
|
|
|
return (
|
|
<BusinessContext.Provider value={{
|
|
activeBusiness,
|
|
activeBusinessId,
|
|
setActiveBusiness,
|
|
clearBusiness,
|
|
loading,
|
|
hasGlobalSms,
|
|
setHasGlobalSms,
|
|
isSetupComplete,
|
|
setIsSetupComplete,
|
|
hasSelectedTemplates,
|
|
setHasSelectedTemplates,
|
|
refreshOnboardingState,
|
|
}}>
|
|
{children}
|
|
</BusinessContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useBusiness() {
|
|
return useContext(BusinessContext);
|
|
}
|