refactor(workspaces): normalize workspace bootstrap and edit flows

This commit is contained in:
2026-04-24 22:22:28 +03:30
parent dfe280d9a1
commit 790e5f1dba
6 changed files with 199 additions and 207 deletions

View File

@@ -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);

View File

@@ -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>
)
}