Skip to content

feat: add dashboard layout with calendar, notes, and improved sidebar#115

Open
AliiiBenn wants to merge 4 commits intomainfrom
feature/new-header
Open

feat: add dashboard layout with calendar, notes, and improved sidebar#115
AliiiBenn wants to merge 4 commits intomainfrom
feature/new-header

Conversation

@AliiiBenn
Copy link
Member

Summary

  • Add two-column 80/20 layout to home page with calendar and notes
  • Create NotesList component with fullscreen dialog and checkbox completion
  • Add tooltips to header buttons (create new, export)
  • Add active state highlighting to sidebar navigation items

Test plan

  • Verify home page displays in 80/20 layout
  • Check calendar renders on right side
  • Test notes list with fullscreen dialog
  • Verify checkbox completion works
  • Check sidebar highlights active page
  • Verify header tooltips appear on hover

🤖 Generated with Claude Code

AliiiBenn and others added 2 commits March 5, 2026 14:30
- Extract QuickActionsDialog to separate component
- Add AppHeader with Quick actions button, Add button, and Export button
- Lift quickActionsOpen state to RootPage for proper overlay positioning
- Remove QuickActionsDialog from AppSidebar

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
- Add two-column 80/20 layout to home page with calendar and notes
- Create NotesList component with fullscreen dialog and checkbox completion
- Add tooltips to header buttons (create new, export)
- Add active state highlighting to sidebar navigation items

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
const navigate = useNavigate();
const openDialog = useDialogStore((state) => state.openDialog);

const quickActions: QuickAction[] = [
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quickActions array is missing TypeScript type safety. Items with heading property don't match the QuickAction interface.

Consider either:

  1. Creating a union type that includes heading items
  2. Using a type assertion
type QuickActionItem = QuickAction | { heading: string };
const quickActions: QuickActionItem[] = [...]

},
];

const groupedActions = quickActions.reduce<{ heading?: string; items: QuickAction[] }[]>(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reduce operation could be simplified and made more type-safe by defining proper types for the accumulator.

interface ActionGroup {
  heading?: string;
  items: QuickAction[];
}

This would make the code more maintainable and self-documenting.


export function NotesList({ notes }: NotesListProps) {
const [selectedNote, setSelectedNote] = useState<Note | null>(null);
const [completedNotes, setCompletedNotes] = useState<Set<string>>(new Set());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The completedNotes state is local to this component and will be lost when the component unmounts. Consider persisting this state (e.g., to localStorage) or passing the completion state from the parent component if persistence is desired.

<CardTitle>Notes</CardTitle>
</CardHeader>
<CardContent className="border-t px-0">
<NotesList
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded notes data should be moved to a centralized data source or retrieved from an API/database. This would allow for:

  1. Dynamic notes management
  2. Persistence across sessions
  3. Better separation of concerns

Consider creating a notes hook (useNotes) similar to the existing useAlerts, useEmployees hooks.

}

export const AppHeader = ({ onQuickActionsClick }: AppHeaderProps) => {
React.useEffect(() => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keyboard shortcut for Cmd+K / Ctrl+K is good UX. However, consider adding this to a quick actions documentation or tooltip hint so users discover this feature.

Also, the effect dependency array includes onQuickActionsClick which may cause unnecessary effect re-runs if the parent re-renders. Consider using useCallback in the parent or wrapping in useRef.

/>
)}
<Sidebar
className="top-(--header-height) h-[calc(100svh-var(--header-height))]!"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an unusual Tailwind class syntax here: top-(--header-height) h-[calc(100svh-var(--header-height))]!

The exclamation mark at the end and parentheses around the CSS variable seem incorrect. This should likely be:
h-[calc(100svh-var(--header-height))]

Please verify this renders correctly in production.

sidebarStore.getServerSnapshot,
);

const [quickActionsOpen, setQuickActionsOpen] = useState(false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of useSyncExternalStore for sidebar state persistence! This is a proper pattern that avoids hydration mismatches and provides synchronous access to localStorage state.

Consider extracting this custom store pattern to a reusable hook in src/renderer/src/hooks/ for better maintainability (e.g., useLocalStorageStore).

};

// Get counts for sidebar badges
const { data: alerts = [] } = useAlerts();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isActive function for determining active navigation state is simple and effective. However, it may cause issues with routes like /employees and /employees/:id both being highlighted.

Consider using the router's match functionality or a more precise path matching algorithm if you need to distinguish between list and detail views.

@marty-action
Copy link

marty-action bot commented Mar 6, 2026

Summary

This PR adds a dashboard layout with a two-column 80/20 split, featuring a calendar and notes panel on the right side, along with improved header and sidebar components. The code is generally well-structured and follows the project's existing patterns.

Critical Issues

None - This PR can be merged as-is. The following are suggestions for future improvements.

Recommendations

Code Quality & Type Safety

  1. TypeScript Type Safety (src/renderer/src/components/quick-actions-dialog.tsx:46, :215)

    • The quickActions array mixes items with heading property and QuickAction type
    • Consider creating a union type for better type safety
    • Define explicit accumulator type for the reduce operation
  2. State Persistence (src/renderer/src/components/home/notes-list.tsx:40)

    • The completedNotes state is lost on component unmount
    • Consider persisting to localStorage or lifting state to parent if persistence is desired
  3. Hardcoded Data (src/renderer/src/pages/home-page.tsx:236)

    • Notes are currently hardcoded in the component
    • Consider creating a useNotes hook similar to existing useAlerts, useEmployees hooks
    • This would enable dynamic notes management and persistence
  4. Tailwind CSS Syntax (src/renderer/src/components/app-sidebar.tsx:123)

    • Unusual syntax: top-(--header-height) h-[calc(100svh-var(--header-height))]!
    • The exclamation mark and parentheses may cause issues
    • Verify this renders correctly in production builds
  5. Navigation Active State (src/renderer/src/components/app-sidebar.tsx:97)

    • The isActive function may highlight both list and detail views (e.g., /employees and /employees/:id)
    • Consider using router's match functionality for more precise path matching

Performance

  1. Effect Dependencies (src/renderer/src/components/app-header.tsx:15)
    • The keyboard shortcut effect depends on onQuickActionsClick which may cause unnecessary re-runs
    • Consider using useCallback in parent component or wrapping in useRef

Positive Notes

  • ✅ Excellent component extraction - QuickActionsDialog is now properly separated
  • ✅ Good use of useSyncExternalStore for sidebar state persistence (avoids hydration issues)
  • ✅ Proper keyboard shortcut support (Cmd/Ctrl+K) for quick actions
  • ✅ Active state highlighting for sidebar navigation improves UX
  • ✅ Tooltips on header buttons enhance discoverability
  • ✅ Clean two-column layout with proper responsive considerations
  • ✅ No security vulnerabilities identified
  • ✅ Follows existing code patterns and conventions

Test Coverage

No new tests were added for these UI changes. Consider adding tests for:

  • Quick actions dialog keyboard shortcuts
  • Notes list checkbox completion behavior
  • Sidebar active state routing logic

AliiiBenn and others added 2 commits March 6, 2026 13:31
- Add footer with copyright, Help/Privacy/Terms links, online status, and version
- Move write mode indicator from sidebar to footer
- Remove TanStack Router devtools from codebase

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
Add no-drag CSS class and apply proper drag regions to ensure
window can be dragged while keeping buttons clickable

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
import { AppSidebar } from "@/components/app-sidebar";
import { AppHeader } from "@/components/app-header";
import { DialogManager } from "@/components/dialogs/DialogManager";
import { RightSidebar } from "@/components/right-sidebar";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RightSidebar component is imported here but the file doesn't exist in the repository. This will cause a build/runtime error. Either create the missing component or remove this import and the conditional rendering at line 167.

import { AppSidebar } from "@/components/app-sidebar";
import { AppHeader } from "@/components/app-header";
import { DialogManager } from "@/components/dialogs/DialogManager";
import { RightSidebar } from "@/components/right-sidebar";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RightSidebar component is imported here but the file doesn't exist in the repository. This will cause a build/runtime error. Either create the missing component or remove this import and the conditional rendering at line 167.

notes={[
{
id: "1",
title: "Réunion équipe",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notes data contains hardcoded French text while the rest of the app uses i18n. Either use translation keys or move this data to a proper i18n structure for consistency.

const navigate = useNavigate();
const openDialog = useDialogStore((state) => state.openDialog);

const quickActions: QuickAction[] = [
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quickActions array is recreated on every render. Wrap it in useMemo for better performance: const quickActions = React.useMemo(() => [...], []);

import { Command, CommandEmpty, CommandGroup, CommandItem, CommandList } from "cmdk";
import { useDialogStore } from "@/stores/dialog-store";

interface QuickAction {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The QuickAction interface allows heading to be mixed with regular actions. Consider using a discriminated union for better type safety: type QuickAction = { heading: string } | { id: string; title: string; ... };

<div className="h-6 w-px bg-border" />
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" className="gap-2">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Export button has no onClick handler - it's a non-functional UI element. Either add the export functionality or disable the button with disabled attribute until implemented.

<AppSidebar />
<SidebarInset className="flex flex-1 flex-col">
{/*<header className="h-14 border-b"></header>*/}
<AppHeader
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AppHeader component is called with onToggleRightSidebar and rightSidebarOpen props that are not defined in its interface. Update AppHeaderProps to include these props.

<div className="flex items-center gap-3">
<span>© 2024 WEMS</span>
<span className="text-border">|</span>
<button className="hover:text-foreground transition-colors">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These footer buttons have no click handlers. Either add functionality or disable them until implemented.

export const AppHeader = ({ onQuickActionsClick }: AppHeaderProps) => {
React.useEffect(() => {
// Handle Cmd+K / Ctrl+K keyboard shortcut
const handleKeyDown = (event: KeyboardEvent) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using useCallback for handleKeyDown to ensure stable reference: const handleKeyDown = React.useCallback((event: KeyboardEvent) => { ... }, [onQuickActionsClick]);

@marty-action
Copy link

marty-action bot commented Mar 6, 2026

Summary

This PR adds several UI improvements to the dashboard including a new header component, calendar and notes widgets in an 80/20 layout, active state highlighting for sidebar navigation, and a refactored quick actions dialog. The code is generally well-structured and follows existing patterns.

Critical Issues

1. Missing RightSidebar Component File

📁 src/renderer/src/pages/root-page.tsx:5

The code imports RightSidebar component but the file doesn't exist in the repository. This will cause a build/runtime error.

Recommendation: Either create the missing RightSidebar component or remove the import and conditional rendering.

2. AppHeader Props Mismatch

📁 src/renderer/src/pages/root-page.tsx:118

The AppHeader component is called with props (onToggleRightSidebar, rightSidebarOpen) that are not defined in its interface.

Recommendation: Update the AppHeaderProps interface to include the missing props.

3. Hardcoded French Content

📁 src/renderer/src/pages/home-page.tsx:240

The notes data contains hardcoded French text while the rest of the app uses i18n.

Recommendation: Use translation keys or move this data to a proper i18n structure.

Recommendations

Performance

  • 📁 quick-actions-dialog.tsx:46 - Wrap quickActions array in useMemo to prevent recreating on every render
  • 📁 app-header.tsx:17 - Use useCallback for handleKeyDown to ensure stable reference

Type Safety

  • 📁 quick-actions-dialog.tsx:26 - Consider using a discriminated union for QuickAction to better separate headings from actions

Functionality

  • 📁 app-header.tsx:52 - Export button has no onClick handler - disable until implemented
  • 📁 root-page.tsx:129 - Footer buttons (Help, Privacy, Terms) have no click handlers

Positive Notes

✅ Good component extraction - NotesList and AppHeader are well-separated
✅ Proper TypeScript interfaces for all components
✅ Consistent use of existing UI components (shadcn/ui)
✅ Good use of React hooks (useState, useMemo, useEffect)
✅ Keyboard shortcut (Cmd/Ctrl+K) properly implemented with cleanup
✅ Active state highlighting for sidebar navigation improves UX
✅ LocalStorage persistence for sidebar states
✅ Proper use of external stores for sidebar state management
✅ Tooltip additions improve discoverability
✅ Clean separation of concerns with QuickActionsDialog extracted

Security

✅ No security issues identified - proper input handling, no XSS vulnerabilities, no hardcoded secrets

Testing

⚠️ No test files were added or modified. Consider adding tests for:

  • NotesList component (completion toggle, dialog open)
  • QuickActionsDialog (search filtering, keyboard shortcuts)
  • AppHeader (keyboard shortcut handler)
  • Sidebar active state logic

Overall Assessment: The PR introduces good UX improvements but has some critical issues (missing file, prop mismatches) that need to be addressed before merging. The code quality is generally good with room for some performance optimizations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant