121 lines
3.4 KiB
TypeScript
121 lines
3.4 KiB
TypeScript
import {
|
|
createContext,
|
|
useState,
|
|
useEffect,
|
|
useCallback,
|
|
type ReactNode,
|
|
} from 'react'
|
|
import { projectService, type Project } from '@/services'
|
|
import { useAuth } from '@/hooks'
|
|
|
|
export interface ProjectContextType {
|
|
projects: Project[]
|
|
currentProject: Project | null
|
|
isLoading: boolean
|
|
error: string | null
|
|
setCurrentProject: (project: Project | null) => void
|
|
refreshProjects: () => Promise<void>
|
|
createProject: (name: string, description?: string) => Promise<Project>
|
|
}
|
|
|
|
export const ProjectContext = createContext<ProjectContextType | undefined>(undefined)
|
|
|
|
const STORAGE_KEY = 'selectedProjectId'
|
|
|
|
interface ProjectProviderProps {
|
|
children: ReactNode
|
|
}
|
|
|
|
export function ProjectProvider({ children }: ProjectProviderProps) {
|
|
const { isAuthenticated, isLoading: authLoading } = useAuth()
|
|
const [projects, setProjects] = useState<Project[]>([])
|
|
const [currentProject, setCurrentProjectState] = useState<Project | null>(null)
|
|
const [isLoading, setIsLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const setCurrentProject = useCallback((project: Project | null) => {
|
|
setCurrentProjectState(project)
|
|
if (project) {
|
|
localStorage.setItem(STORAGE_KEY, project.id.toString())
|
|
} else {
|
|
localStorage.removeItem(STORAGE_KEY)
|
|
}
|
|
}, [])
|
|
|
|
const refreshProjects = useCallback(async () => {
|
|
if (!isAuthenticated) {
|
|
setProjects([])
|
|
setCurrentProjectState(null)
|
|
setIsLoading(false)
|
|
return
|
|
}
|
|
|
|
try {
|
|
setIsLoading(true)
|
|
setError(null)
|
|
const fetchedProjects = await projectService.getMyProjects()
|
|
setProjects(fetchedProjects)
|
|
|
|
// Restore selected project from localStorage or select first available
|
|
const savedProjectId = localStorage.getItem(STORAGE_KEY)
|
|
if (savedProjectId) {
|
|
const savedProject = fetchedProjects.find(
|
|
(p) => p.id === parseInt(savedProjectId, 10)
|
|
)
|
|
if (savedProject) {
|
|
setCurrentProjectState(savedProject)
|
|
} else if (fetchedProjects.length > 0) {
|
|
// Saved project no longer available, select first one
|
|
setCurrentProject(fetchedProjects[0])
|
|
}
|
|
} else if (fetchedProjects.length > 0) {
|
|
// No saved project, select first one
|
|
setCurrentProject(fetchedProjects[0])
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to fetch projects:', err)
|
|
setError('Failed to load projects')
|
|
} finally {
|
|
setIsLoading(false)
|
|
}
|
|
}, [isAuthenticated, setCurrentProject])
|
|
|
|
const createProject = useCallback(async (name: string, description?: string): Promise<Project> => {
|
|
const newProject = await projectService.createProject({
|
|
project_name: name,
|
|
project_desc: description,
|
|
})
|
|
|
|
// Add to projects list
|
|
setProjects((prev: Project[]) => [newProject, ...prev])
|
|
|
|
// If no current project, set this as current
|
|
if (!currentProject) {
|
|
setCurrentProject(newProject)
|
|
}
|
|
|
|
return newProject
|
|
}, [currentProject, setCurrentProject])
|
|
|
|
// Fetch projects when authentication status changes
|
|
useEffect(() => {
|
|
if (!authLoading) {
|
|
refreshProjects()
|
|
}
|
|
}, [authLoading, isAuthenticated, refreshProjects])
|
|
|
|
const value: ProjectContextType = {
|
|
projects,
|
|
currentProject,
|
|
isLoading,
|
|
error,
|
|
setCurrentProject,
|
|
refreshProjects,
|
|
createProject,
|
|
}
|
|
|
|
return (
|
|
<ProjectContext.Provider value={value}>{children}</ProjectContext.Provider>
|
|
)
|
|
}
|