83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
import type {Project} from '@plunk/db';
|
|
import {createContext, type ReactNode, useContext, useEffect, useState} from 'react';
|
|
import {useSWRConfig} from 'swr';
|
|
|
|
import {useProjects} from '../hooks/useProject';
|
|
|
|
interface ActiveProjectContextValue {
|
|
activeProject: Project | null;
|
|
setActiveProject: (project: Project) => void;
|
|
updateActiveProject: (project: Project) => void;
|
|
availableProjects: Project[];
|
|
isLoading: boolean;
|
|
}
|
|
|
|
const ActiveProjectContext = createContext<ActiveProjectContextValue | undefined>(undefined);
|
|
|
|
export function ActiveProjectProvider({children}: {children: ReactNode}) {
|
|
const {data: projects, isLoading} = useProjects();
|
|
const {mutate} = useSWRConfig();
|
|
|
|
// State is null until projects load, but localStorage is read synchronously by network.ts
|
|
// This ensures consistent behavior: either all calls use stored ID, or all fall back to projects[0]
|
|
const [activeProject, setActiveProjectState] = useState<Project | null>(null);
|
|
|
|
// Initialize active project from localStorage or use first project
|
|
useEffect(() => {
|
|
if (!projects || projects.length === 0) return;
|
|
|
|
const storedProjectId = localStorage.getItem('activeProjectId');
|
|
|
|
if (storedProjectId) {
|
|
// Find the stored project in available projects
|
|
const project = projects.find(p => p.id === storedProjectId);
|
|
if (project) {
|
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
setActiveProjectState(project);
|
|
} else if (projects[0]) {
|
|
// Stored project not found (user might have been removed), use first project
|
|
|
|
setActiveProjectState(projects[0]);
|
|
localStorage.setItem('activeProjectId', projects[0].id);
|
|
}
|
|
} else if (projects[0]) {
|
|
// No stored project, initialize with first one
|
|
|
|
setActiveProjectState(projects[0]);
|
|
localStorage.setItem('activeProjectId', projects[0].id);
|
|
}
|
|
}, [projects]);
|
|
|
|
const setActiveProject = (project: Project) => {
|
|
setActiveProjectState(project);
|
|
localStorage.setItem('activeProjectId', project.id);
|
|
|
|
// Invalidate all SWR cache to refetch data for new project
|
|
void mutate(() => true, undefined, {revalidate: true});
|
|
};
|
|
|
|
// Updates the active project's data in-place without invalidating the SWR cache.
|
|
// Use this when saving settings for the current project, not when switching projects.
|
|
const updateActiveProject = (project: Project) => {
|
|
setActiveProjectState(project);
|
|
};
|
|
|
|
const value: ActiveProjectContextValue = {
|
|
activeProject,
|
|
setActiveProject,
|
|
updateActiveProject,
|
|
availableProjects: projects ?? [],
|
|
isLoading,
|
|
};
|
|
|
|
return <ActiveProjectContext.Provider value={value}>{children}</ActiveProjectContext.Provider>;
|
|
}
|
|
|
|
export function useActiveProject() {
|
|
const context = useContext(ActiveProjectContext);
|
|
if (context === undefined) {
|
|
throw new Error('useActiveProject must be used within an ActiveProjectProvider');
|
|
}
|
|
return context;
|
|
}
|