From aafb080eab29049c01f05bb48dfbfa533379ff3d Mon Sep 17 00:00:00 2001 From: Oscar Date: Wed, 1 Oct 2025 10:38:12 +0200 Subject: [PATCH 1/4] Adds project refresh functionality to context and UI Introduces a `refreshProjects` method to the ProjectsContext, enabling manual and programmatic refresh of project data. Updates the ProjectsContextProvider to include this method and refactors the initial refresh logic. Integrates the refresh functionality into the ProjectListItem component to trigger a refresh when a project is selected. Also includes minor code style improvements for consistency. --- src/common/context/ProjectsContext.ts | 2 + .../projects/view/ProjectsContextProvider.tsx | 45 +++---- .../sidebar/projects/ProjectListItem.tsx | 121 +++++++++--------- 3 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/common/context/ProjectsContext.ts b/src/common/context/ProjectsContext.ts index f4d30699..4666e695 100644 --- a/src/common/context/ProjectsContext.ts +++ b/src/common/context/ProjectsContext.ts @@ -8,9 +8,11 @@ export const SidebarTogglableContext = createContext(true) type ProjectsContextValue = { refreshing: boolean, projects: Project[], + refreshProjects: () => void, } export const ProjectsContext = createContext({ refreshing: false, projects: [], + refreshProjects: () => {}, }) diff --git a/src/features/projects/view/ProjectsContextProvider.tsx b/src/features/projects/view/ProjectsContextProvider.tsx index 639363e1..f4200e85 100644 --- a/src/features/projects/view/ProjectsContextProvider.tsx +++ b/src/features/projects/view/ProjectsContextProvider.tsx @@ -19,43 +19,34 @@ const ProjectsContextProvider = ({ setProjects(value); }; + const refreshProjects = () => { + if (isLoadingRef.current) return; + isLoadingRef.current = true; + setRefreshing(true); + fetch("/api/refresh-projects", { method: "POST" }) + .then((res) => res.json()) + .then(({ projects }) => { + if (projects) setProjectsAndRefreshed(projects); + }) + .catch((error) => console.error("Failed to refresh projects", error)) + .finally(() => { + isLoadingRef.current = false; + setRefreshing(false); + }); + }; + // Trigger background refresh after initial mount useEffect(() => { - const refreshProjects = () => { - if (isLoadingRef.current) { - return; - } - isLoadingRef.current = true; - setRefreshing(true); - fetch("/api/refresh-projects", { method: "POST" }) - .then((res) => res.json()) - .then(({ projects }) => { - if (projects) setProjectsAndRefreshed(projects); - }) - .catch((error) => console.error("Failed to refresh projects", error)) - .finally(() => { - isLoadingRef.current = false; - setRefreshing(false); - }); - }; - // Initial refresh refreshProjects(); const handleVisibilityChange = () => { if (!document.hidden) refreshProjects(); }; - document.addEventListener("visibilitychange", handleVisibilityChange); - return () => - document.removeEventListener("visibilitychange", handleVisibilityChange); + return () => document.removeEventListener("visibilitychange", handleVisibilityChange); }, []); return ( - + {children} ); diff --git a/src/features/sidebar/view/internal/sidebar/projects/ProjectListItem.tsx b/src/features/sidebar/view/internal/sidebar/projects/ProjectListItem.tsx index ec9b852d..cfa9294b 100644 --- a/src/features/sidebar/view/internal/sidebar/projects/ProjectListItem.tsx +++ b/src/features/sidebar/view/internal/sidebar/projects/ProjectListItem.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import { Box, @@ -7,26 +7,33 @@ import { ListItemButton, Skeleton as MuiSkeleton, Stack, - Typography -} from "@mui/material" -import MenuItemHover from "@/common/ui/MenuItemHover" -import { Project } from "@/features/projects/domain" -import { useProjectSelection } from "@/features/projects/data" -import ProjectAvatar, { Squircle as ProjectAvatarSquircle } from "./ProjectAvatar" -import { useCloseSidebarOnSelection } from "@/features/sidebar/data" + Typography, +} from "@mui/material"; +import MenuItemHover from "@/common/ui/MenuItemHover"; +import { Project } from "@/features/projects/domain"; +import { useProjectSelection } from "@/features/projects/data"; +import { useContext } from "react"; +import { ProjectsContext } from "@/common"; +import ProjectAvatar, { + Squircle as ProjectAvatarSquircle, +} from "./ProjectAvatar"; +import { useCloseSidebarOnSelection } from "@/features/sidebar/data"; -const AVATAR_SIZE = { width: 40, height: 40 } +const AVATAR_SIZE = { width: 40, height: 40 }; const ProjectListItem = ({ project }: { project: Project }) => { - const { project: selectedProject, selectProject } = useProjectSelection() - const selected = project.id === selectedProject?.id - const { closeSidebarIfNeeded } = useCloseSidebarOnSelection() + const { project: selectedProject, selectProject } = useProjectSelection(); + const { refreshProjects } = useContext(ProjectsContext); + const selected = project.id === selectedProject?.id; + const { closeSidebarIfNeeded } = useCloseSidebarOnSelection(); + return (