refactor(workspaces): normalize workspace bootstrap and edit flows
This commit is contained in:
@@ -1,71 +1,47 @@
|
||||
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react';
|
||||
import { getUserProfile } from '../api/users';
|
||||
import { fetchWorkspaces } from '../api/workspaces';
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
phone_number: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
}
|
||||
|
||||
interface Workspace {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface AppContextType {
|
||||
user: User | null;
|
||||
workspaces: Workspace[];
|
||||
activeWorkspace: Workspace | null;
|
||||
setActiveWorkspace: (ws: Workspace) => void;
|
||||
fetchInitialData: () => Promise<void>;
|
||||
}
|
||||
|
||||
const AppContext = createContext<AppContextType | null>(null);
|
||||
|
||||
export const AppProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [workspaces, setWorkspaces] = useState<Workspace[]>([]);
|
||||
const [activeWorkspace, setActiveWorkspace] = useState<Workspace | null>(null);
|
||||
|
||||
const fetchInitialData = async () => {
|
||||
try {
|
||||
const [userData, wsData] = await Promise.all([
|
||||
getUserProfile(),
|
||||
fetchWorkspaces() // fetchWorkspaces({ limit: 50 })
|
||||
]);
|
||||
|
||||
setUser(userData);
|
||||
|
||||
const workspacesList = Array.isArray(wsData.data) ? wsData.data : (wsData?.data?.results || []);
|
||||
|
||||
setWorkspaces(workspacesList);
|
||||
|
||||
const savedWsId = localStorage.getItem('active_workspace');
|
||||
const targetWs = workspacesList.find((w: Workspace) => w.id === savedWsId) || workspacesList[0];
|
||||
|
||||
if (targetWs) {
|
||||
setActiveWorkspace(targetWs);
|
||||
localStorage.setItem('active_workspace', targetWs.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch initial context data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem('accessToken')) {
|
||||
fetchInitialData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={{ user, workspaces, activeWorkspace, setActiveWorkspace, fetchInitialData }}>
|
||||
{children}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react';
|
||||
import { getUserProfile } from '../api/users';
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
mobile: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
email?: string;
|
||||
profile_picture?: string | null;
|
||||
}
|
||||
|
||||
interface AppContextType {
|
||||
user: User | null;
|
||||
refreshUser: () => Promise<void>;
|
||||
}
|
||||
|
||||
const AppContext = createContext<AppContextType | null>(null);
|
||||
|
||||
export const AppProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
|
||||
const refreshUser = async () => {
|
||||
try {
|
||||
const userData = await getUserProfile();
|
||||
setUser(userData);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch user context data:", error);
|
||||
setUser(null);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem('accessToken')) {
|
||||
void refreshUser();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={{ user, refreshUser }}>
|
||||
{children}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAppContext = () => {
|
||||
const context = useContext(AppContext);
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { createContext, useContext, useState, useEffect, ReactNode } from "react"
|
||||
import { createContext, useContext, useState, useEffect, type ReactNode } from "react"
|
||||
import { fetchWorkspaces, createWorkspace, type Workspace } from "../api/workspaces"
|
||||
import { useTranslation } from "../hooks/useTranslation"
|
||||
import { toast } from "sonner"
|
||||
import { Button } from "../components/ui/button"
|
||||
import { Input } from "../components/ui/input"
|
||||
|
||||
interface WorkspaceContextType {
|
||||
workspaces: Workspace[]
|
||||
activeWorkspace: Workspace | null
|
||||
setActiveWorkspace: (workspace: Workspace) => void
|
||||
addWorkspace: (name: string) => Promise<void>
|
||||
isLoading: boolean
|
||||
}
|
||||
interface WorkspaceContextType {
|
||||
workspaces: Workspace[]
|
||||
activeWorkspace: Workspace | null
|
||||
setActiveWorkspace: (workspace: Workspace | null) => void
|
||||
addWorkspace: (name: string) => Promise<void>
|
||||
refreshWorkspaces: () => Promise<void>
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
const WorkspaceContext = createContext<WorkspaceContextType | undefined>(undefined)
|
||||
|
||||
@@ -29,45 +30,58 @@ export const WorkspaceProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [newWorkspaceName, setNewWorkspaceName] = useState("")
|
||||
const [isCreatingFirst, setIsCreatingFirst] = useState(false)
|
||||
|
||||
const isAuthenticated = !!localStorage.getItem("accessToken")
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) {
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
const loadWorkspaces = async () => {
|
||||
try {
|
||||
const response = await fetchWorkspaces()
|
||||
|
||||
const data = Array.isArray(response) ? response : (response?.results || [])
|
||||
setWorkspaces(data)
|
||||
|
||||
if (data.length > 0) {
|
||||
const storedId = localStorage.getItem("activeWorkspaceId")
|
||||
const stored = data.find((w: Workspace) => w.id === storedId)
|
||||
if (stored) {
|
||||
setActiveWorkspaceState(stored)
|
||||
} else {
|
||||
setActiveWorkspaceState(data[0])
|
||||
localStorage.setItem("activeWorkspaceId", data[0].id)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
loadWorkspaces()
|
||||
}, [isAuthenticated])
|
||||
|
||||
const setActiveWorkspace = (workspace: Workspace) => {
|
||||
setActiveWorkspaceState(workspace)
|
||||
localStorage.setItem("activeWorkspaceId", workspace.id)
|
||||
}
|
||||
const isAuthenticated = !!localStorage.getItem("accessToken")
|
||||
|
||||
const refreshWorkspaces = async () => {
|
||||
if (!isAuthenticated) {
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const response = await fetchWorkspaces()
|
||||
|
||||
const data = Array.isArray(response) ? response : (response?.results || [])
|
||||
setWorkspaces(data)
|
||||
|
||||
if (data.length > 0) {
|
||||
const storedId = localStorage.getItem("activeWorkspaceId")
|
||||
const stored = data.find((w: Workspace) => w.id === storedId)
|
||||
if (stored) {
|
||||
setActiveWorkspaceState(stored)
|
||||
} else {
|
||||
setActiveWorkspaceState(data[0])
|
||||
localStorage.setItem("activeWorkspaceId", data[0].id)
|
||||
}
|
||||
} else {
|
||||
setActiveWorkspaceState(null)
|
||||
localStorage.removeItem("activeWorkspaceId")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) {
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
void refreshWorkspaces()
|
||||
}, [isAuthenticated])
|
||||
|
||||
const setActiveWorkspace = (workspace: Workspace | null) => {
|
||||
setActiveWorkspaceState(workspace)
|
||||
if (workspace) {
|
||||
localStorage.setItem("activeWorkspaceId", workspace.id)
|
||||
} else {
|
||||
localStorage.removeItem("activeWorkspaceId")
|
||||
}
|
||||
}
|
||||
|
||||
const addWorkspace = async (name: string) => {
|
||||
try {
|
||||
@@ -75,10 +89,10 @@ export const WorkspaceProvider = ({ children }: { children: ReactNode }) => {
|
||||
const newWs = await createWorkspace({ name, description: "" })
|
||||
setWorkspaces((prev) => [...prev, newWs])
|
||||
setActiveWorkspace(newWs)
|
||||
toast.success(t.workspace?.createSuccess || "Workspace created!")
|
||||
} catch (error) {
|
||||
toast.error(t.workspace?.createError || "Failed to create workspace")
|
||||
throw error
|
||||
toast.success(t.workspace?.successCreate || t.workspace?.toast?.successCreate || "Workspace created!")
|
||||
} catch (error) {
|
||||
toast.error(t.workspace?.toast?.errorCreate || "Failed to create workspace")
|
||||
throw error
|
||||
} finally {
|
||||
setIsCreatingFirst(false)
|
||||
setNewWorkspaceName("")
|
||||
@@ -123,10 +137,10 @@ export const WorkspaceProvider = ({ children }: { children: ReactNode }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<WorkspaceContext.Provider
|
||||
value={{ workspaces, activeWorkspace, setActiveWorkspace, addWorkspace, isLoading }}
|
||||
>
|
||||
{children}
|
||||
</WorkspaceContext.Provider>
|
||||
)
|
||||
}
|
||||
<WorkspaceContext.Provider
|
||||
value={{ workspaces, activeWorkspace, setActiveWorkspace, addWorkspace, refreshWorkspaces, isLoading }}
|
||||
>
|
||||
{children}
|
||||
</WorkspaceContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user