Skip to content

Commit 2df8bb6

Browse files
committed
refactor: update AppLayout and NavigationSidebar components to improve sidebar management; simplify devlog fetching logic in ProjectDevlogDetailsPage
1 parent db3ece4 commit 2df8bb6

File tree

4 files changed

+40
-47
lines changed

4 files changed

+40
-47
lines changed

packages/web/app/AppLayout.tsx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
import React, { useEffect, useState } from 'react';
44
import { AppLayoutSkeleton, ErrorBoundary, NavigationSidebar, TopNavbar } from '@/components';
5-
import { SidebarProvider } from '@/components/ui/sidebar';
6-
import { useLayoutStore } from '@/stores';
5+
import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar';
76

87
interface AppLayoutProps {
98
children: React.ReactNode;
@@ -12,8 +11,6 @@ interface AppLayoutProps {
1211
export function AppLayout({ children }: AppLayoutProps) {
1312
const [mounted, setMounted] = useState(false);
1413

15-
const { sidebarOpen, setSidebarOpen } = useLayoutStore();
16-
1714
// Handle client-side hydration
1815
useEffect(() => {
1916
setMounted(true);
@@ -28,20 +25,14 @@ export function AppLayout({ children }: AppLayoutProps) {
2825
<ErrorBoundary>
2926
<div className="min-h-screen bg-background w-full">
3027
<TopNavbar />
31-
<SidebarProvider
32-
defaultOpen={sidebarOpen}
33-
open={sidebarOpen}
34-
onOpenChange={(open) => {
35-
setSidebarOpen(open);
36-
}}
37-
>
28+
<SidebarProvider>
3829
<div className="flex w-full h-[calc(100vh-3rem)]">
3930
<NavigationSidebar />
40-
<div className="flex-1 flex flex-col w-full">
31+
<SidebarInset>
4132
<main className="flex-1 p-6 w-full overflow-auto">
4233
<div className="w-full">{children}</div>
4334
</main>
44-
</div>
35+
</SidebarInset>
4536
</div>
4637
</SidebarProvider>
4738
</div>

packages/web/app/components/layout/NavigationSidebar.tsx

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import {
66
Sidebar,
77
SidebarContent,
88
SidebarFooter,
9+
SidebarGroup,
910
SidebarMenu,
1011
SidebarMenuButton,
1112
SidebarMenuItem,
1213
SidebarTrigger,
14+
useSidebar,
1315
} from '@/components/ui/sidebar';
1416
import { Home, SquareKanban } from 'lucide-react';
1517

@@ -24,19 +26,13 @@ export function NavigationSidebar() {
2426
const router = useRouter();
2527
const pathname = usePathname();
2628
const [mounted, setMounted] = useState(false);
29+
const { open, toggleSidebar } = useSidebar();
2730

2831
// Handle client-side hydration
2932
useEffect(() => {
3033
setMounted(true);
3134
}, []);
3235

33-
// Check if sidebar should be hidden
34-
const shouldHideSidebar = () => {
35-
if (!mounted) return false;
36-
// No pages currently hide the sidebar
37-
return false;
38-
};
39-
4036
const getProjectId = () => {
4137
const matched = pathname.match(/\/projects\/(\w+)/);
4238
if (matched) {
@@ -49,21 +45,21 @@ export function NavigationSidebar() {
4945
{
5046
key: 'overview',
5147
label: 'Overview',
52-
icon: <Home size={16} />,
48+
icon: <Home />,
5349
onClick: () => router.push('/projects'),
5450
},
5551
];
5652
const projectDetailMenuItems = [
5753
{
5854
key: 'overview',
5955
label: 'Overview',
60-
icon: <Home size={16} />,
56+
icon: <Home />,
6157
onClick: () => router.push(`/projects/${getProjectId()}`),
6258
},
6359
{
6460
key: 'list',
6561
label: 'Devlogs',
66-
icon: <SquareKanban size={16} />,
62+
icon: <SquareKanban />,
6763
onClick: () => router.push(`/projects/${getProjectId()}/devlogs`),
6864
},
6965
];
@@ -96,23 +92,19 @@ export function NavigationSidebar() {
9692
};
9793

9894
// Don't render menu items until mounted to prevent hydration issues
99-
if (!mounted || shouldHideSidebar()) {
95+
if (!mounted) {
10096
return null;
10197
}
10298

10399
const menuItems = getMenuItems();
104100

105101
return (
106-
<Sidebar className="border-r bg-background">
102+
<Sidebar collapsible="icon" className="py-1 border-r bg-background">
107103
<SidebarContent className="bg-background">
108-
<SidebarMenu className="space-y-2 px-4 py-2">
104+
<SidebarMenu className="space-y-2 p-2">
109105
{menuItems.map((item) => (
110106
<SidebarMenuItem key={item.key}>
111-
<SidebarMenuButton
112-
isActive={getSelectedKey() === item.key}
113-
className="flex items-center gap-3 px-4 py-3 text-sm font-medium min-h-[44px] rounded-md"
114-
onClick={item.onClick}
115-
>
107+
<SidebarMenuButton isActive={getSelectedKey() === item.key} onClick={item.onClick}>
116108
{item.icon}
117109
<span>{item.label}</span>
118110
</SidebarMenuButton>
@@ -121,8 +113,8 @@ export function NavigationSidebar() {
121113
</SidebarMenu>
122114
</SidebarContent>
123115

124-
<SidebarFooter className="p-4 bg-background border-t-0">
125-
<SidebarTrigger className="h-8 w-8 p-0" />
116+
<SidebarFooter className="p-2 bg-background border-t-0">
117+
<SidebarTrigger className="h-8 w-8 p-0" onClick={toggleSidebar} />
126118
</SidebarFooter>
127119
</Sidebar>
128120
);

packages/web/app/projects/[id]/devlogs/[devlogId]/ProjectDevlogDetailsPage.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import {
1111
} from '@/components';
1212
import { useDevlogStore, useProjectStore } from '@/stores';
1313
import { useRouter } from 'next/navigation';
14-
import { Alert, AlertDescription } from '@/components/ui/alert';
15-
import { AlertTriangleIcon, ArrowLeftIcon, SaveIcon, TrashIcon, UndoIcon } from 'lucide-react';
14+
import { ArrowLeftIcon, SaveIcon, TrashIcon, UndoIcon } from 'lucide-react';
1615
import { toast } from 'sonner';
1716

1817
interface ProjectDevlogDetailsPageProps {
@@ -26,11 +25,14 @@ export function ProjectDevlogDetailsPage({ projectId, devlogId }: ProjectDevlogD
2625
const { setCurrentProjectId } = useProjectStore();
2726

2827
const {
28+
currentDevlogId,
29+
setCurrentDevlogId,
2930
currentDevlogContext,
3031
currentDevlogNotesContext,
3132
fetchCurrentDevlog,
33+
fetchCurrentDevlogNotes,
3234
updateSelectedDevlog,
33-
deleteDevlog: deleteDevlogFromList,
35+
deleteDevlog,
3436
clearCurrentDevlog,
3537
} = useDevlogStore();
3638
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
@@ -42,17 +44,24 @@ export function ProjectDevlogDetailsPage({ projectId, devlogId }: ProjectDevlogD
4244

4345
useEffect(() => {
4446
setCurrentProjectId(projectId);
45-
}, [projectId, setCurrentProjectId]);
47+
}, [projectId]);
4648

47-
// Fetch the devlog when component mounts or devlogId changes
4849
useEffect(() => {
49-
fetchCurrentDevlog(devlogId);
50+
setCurrentDevlogId(devlogId);
51+
}, [devlogId]);
52+
53+
// Fetch the devlog when currentDevlogId changes
54+
useEffect(() => {
55+
if (!currentDevlogId) return;
56+
57+
fetchCurrentDevlog();
58+
fetchCurrentDevlogNotes();
5059

5160
// Clear selected devlog when component unmounts
5261
return () => {
5362
clearCurrentDevlog();
5463
};
55-
}, [devlogId, fetchCurrentDevlog, clearCurrentDevlog]);
64+
}, [currentDevlogId]);
5665

5766
const handleUpdate = async (data: any) => {
5867
try {
@@ -80,7 +89,7 @@ export function ProjectDevlogDetailsPage({ projectId, devlogId }: ProjectDevlogD
8089
const handleDelete = async () => {
8190
try {
8291
// Delete the devlog (this will also clear selected devlog via context)
83-
await deleteDevlogFromList(devlogId);
92+
await deleteDevlog(devlogId);
8493

8594
router.push(`/projects/${projectId}/devlogs`);
8695
} catch (error) {

packages/web/app/stores/devlog-store.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ interface DevlogState {
4848
fetchDevlogs: () => Promise<void>;
4949
fetchStats: () => Promise<void>;
5050
fetchTimeSeriesStats: () => Promise<void>;
51-
fetchCurrentDevlog: (id: DevlogId) => Promise<void>;
51+
fetchCurrentDevlog: () => Promise<void>;
5252
clearCurrentDevlog: () => void;
53-
fetchCurrentDevlogNotes: (id: DevlogId) => Promise<void>;
53+
fetchCurrentDevlogNotes: () => Promise<void>;
5454
clearCurrentDevlogNotes: () => void;
5555
createDevlog: (data: Partial<DevlogEntry>) => Promise<any>;
5656
updateDevlog: (data: Partial<DevlogEntry> & { id: DevlogId }) => Promise<any>;
@@ -285,14 +285,15 @@ export const useDevlogStore = create<DevlogState>()(
285285
}
286286
},
287287

288-
fetchCurrentDevlog: async (id: DevlogId) => {
288+
fetchCurrentDevlog: async () => {
289+
const { currentDevlogId } = get();
289290
const devlogApiClient = getDevlogApiClient();
290-
if (!devlogApiClient) {
291+
if (!currentDevlogId || !devlogApiClient) {
291292
set((state) => ({
292293
currentDevlogContext: {
293294
...state.currentDevlogContext,
294295
loading: false,
295-
error: 'API client unavailable',
296+
error: 'No devlog selected or API client unavailable',
296297
},
297298
}));
298299
return;
@@ -306,7 +307,7 @@ export const useDevlogStore = create<DevlogState>()(
306307
error: null,
307308
},
308309
}));
309-
const currentDevlog = await devlogApiClient.get(id);
310+
const currentDevlog = await devlogApiClient.get(currentDevlogId);
310311
set((state) => ({
311312
currentDevlogContext: {
312313
...state.currentDevlogContext,

0 commit comments

Comments
 (0)