Root cause: the previous approach synced poll data into lockInfo via a useEffect. When the user selected an event with cached lock data, both the poll-data effect and the event-change reset effect ran in the same render cycle. The event-change effect ran second (effects are ordered by definition) and cleared lockInfo to null. On the next render, viewLockQuery.data hadn't changed (TanStack Query structural sharing returns same reference), so the poll-data effect never re-fired. Result: lockInfo stayed null, banner stayed hidden until the next polling interval returned new data. Fix: derive activeLockInfo directly from viewLockQuery.data (structural sharing means it's always the latest authoritative value from TanStack Query) with lockInfo as a fallback for the 423-error path only. Also add refetchIntervalInBackground:true and refetchOnMount:'always' to ensure polling doesn't pause on tab switch and always fires a fresh fetch when the component mounts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UMBRA Frontend
A modern, dark-themed React application for managing your life - todos, calendar events, reminders, projects, people, and locations.
Tech Stack
- React 18 with TypeScript
- Vite for fast builds
- Tailwind CSS v3 for styling
- shadcn/ui components (manually implemented)
- React Router v6 for routing
- TanStack Query v5 for data fetching
- Axios for HTTP requests
- FullCalendar for calendar view
- Lucide React for icons
- date-fns for date formatting
- sonner for toast notifications
Features
- PIN-based authentication with setup wizard
- Dark theme with customizable accent colors (cyan, blue, purple, orange, green)
- Dashboard with stats and widgets
- Todos with priority, category, and recurrence
- Calendar with event management
- Reminders with dismiss functionality
- Projects with tasks and progress tracking
- People management with relationships
- Locations categorization
- Responsive design with collapsible sidebar
Getting Started
Prerequisites
- Node.js 20 or higher
- npm or yarn
Installation
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
Development
The application expects a backend API at /api. During development, Vite proxies /api requests to http://localhost:8000.
Project Structure
frontend/
├── src/
│ ├── components/
│ │ ├── auth/ # Authentication components
│ │ ├── calendar/ # Calendar page and forms
│ │ ├── dashboard/ # Dashboard widgets
│ │ ├── layout/ # Layout components (sidebar, etc)
│ │ ├── locations/ # Locations management
│ │ ├── people/ # People management
│ │ ├── projects/ # Projects and tasks
│ │ ├── reminders/ # Reminders management
│ │ ├── settings/ # Settings page
│ │ ├── todos/ # Todos management
│ │ └── ui/ # shadcn/ui components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Utilities (API client, utils)
│ ├── types/ # TypeScript type definitions
│ ├── App.tsx # Main app with routing
│ ├── main.tsx # Entry point
│ └── index.css # Global styles
├── Dockerfile # Production Docker image
├── nginx.conf # Nginx configuration
└── package.json
Docker Deployment
Build and run with Docker:
# Build image
docker build -t umbra-frontend .
# Run container
docker run -p 80:80 umbra-frontend
Environment Variables
No environment variables required. API base URL is configured to /api and proxied by nginx in production.
Customization
Accent Colors
Accent colors are defined in src/hooks/useTheme.ts and can be changed in Settings. The application uses CSS custom properties for theming.
Adding New Pages
- Create component in
src/components/<feature>/ - Add route in
src/App.tsx - Add navigation item in
src/components/layout/Sidebar.tsx
License
Private project - all rights reserved.