Fix logout, category filter, dialog width, and mark all tests complete
- Add logout button to sidebar with destructive hover styling - Fix case-sensitive todo category filter with .toLowerCase() - Widen dialog popups from max-w-lg to max-w-xl with mobile margin - Update CLAUDE.md with commit-and-push instruction - Update progress.md: all CRUD tests verified, all outstanding items resolved Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e6387065ad
commit
cea1c36d92
@ -1,5 +1,8 @@
|
|||||||
# CLAUDE.md - UMBRA
|
# CLAUDE.md - UMBRA
|
||||||
|
|
||||||
|
## IMPORTANT:
|
||||||
|
- When you've completed an edit, commit with details and push to main
|
||||||
|
|
||||||
## Hard Rules
|
## Hard Rules
|
||||||
|
|
||||||
- **Naive datetimes only.** The DB uses `TIMESTAMP WITHOUT TIME ZONE`. Never send timezone-aware strings (no `Z` suffix, no `.toISOString()`). Use local datetime formatting helpers instead.
|
- **Naive datetimes only.** The DB uses `TIMESTAMP WITHOUT TIME ZONE`. Never send timezone-aware strings (no `Z` suffix, no `.toISOString()`). Use local datetime formatting helpers instead.
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink, useNavigate } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
CheckSquare,
|
CheckSquare,
|
||||||
@ -11,8 +11,10 @@ import {
|
|||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
X,
|
X,
|
||||||
|
LogOut,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
@ -33,6 +35,14 @@ interface SidebarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: SidebarProps) {
|
export default function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: SidebarProps) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { logout } = useAuth();
|
||||||
|
|
||||||
|
const handleLogout = async () => {
|
||||||
|
await logout();
|
||||||
|
navigate('/login');
|
||||||
|
};
|
||||||
|
|
||||||
const navLinkClass = ({ isActive }: { isActive: boolean }) =>
|
const navLinkClass = ({ isActive }: { isActive: boolean }) =>
|
||||||
cn(
|
cn(
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
||||||
@ -75,7 +85,7 @@ export default function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose
|
|||||||
))}
|
))}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className="border-t p-2">
|
<div className="border-t p-2 space-y-1">
|
||||||
<NavLink
|
<NavLink
|
||||||
to="/settings"
|
to="/settings"
|
||||||
onClick={mobileOpen ? onMobileClose : undefined}
|
onClick={mobileOpen ? onMobileClose : undefined}
|
||||||
@ -84,6 +94,13 @@ export default function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose
|
|||||||
<Settings className="h-5 w-5 shrink-0" />
|
<Settings className="h-5 w-5 shrink-0" />
|
||||||
{(!collapsed || mobileOpen) && <span>Settings</span>}
|
{(!collapsed || mobileOpen) && <span>Settings</span>}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
<button
|
||||||
|
onClick={handleLogout}
|
||||||
|
className="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"
|
||||||
|
>
|
||||||
|
<LogOut className="h-5 w-5 shrink-0" />
|
||||||
|
{(!collapsed || mobileOpen) && <span>Logout</span>}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export default function TodosPage() {
|
|||||||
|
|
||||||
const filteredTodos = todos.filter((todo) => {
|
const filteredTodos = todos.filter((todo) => {
|
||||||
if (filters.priority && todo.priority !== filters.priority) return false;
|
if (filters.priority && todo.priority !== filters.priority) return false;
|
||||||
if (filters.category && todo.category !== filters.category) return false;
|
if (filters.category && todo.category?.toLowerCase() !== filters.category.toLowerCase()) return false;
|
||||||
if (!filters.showCompleted && todo.completed) return false;
|
if (!filters.showCompleted && todo.completed) return false;
|
||||||
if (filters.search && !todo.title.toLowerCase().includes(filters.search.toLowerCase()))
|
if (filters.search && !todo.title.toLowerCase().includes(filters.search.toLowerCase()))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -43,7 +43,7 @@ const DialogContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTML
|
|||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative grid w-full max-w-lg gap-4 border bg-card p-6 shadow-lg rounded-lg',
|
'relative grid w-full max-w-xl gap-4 border bg-card p-6 shadow-lg rounded-lg mx-4 sm:mx-0',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@ -113,6 +113,9 @@ These were found during first Docker build and integration testing:
|
|||||||
| Sidebar not responsive on mobile | Split into desktop sidebar + mobile overlay with hamburger menu in `AppLayout` |
|
| Sidebar not responsive on mobile | Split into desktop sidebar + mobile overlay with hamburger menu in `AppLayout` |
|
||||||
| Plain "Loading..." text on all pages | Created `Skeleton`, `ListSkeleton`, `GridSkeleton`, `DashboardSkeleton` components |
|
| Plain "Loading..." text on all pages | Created `Skeleton`, `ListSkeleton`, `GridSkeleton`, `DashboardSkeleton` components |
|
||||||
| Basic empty states with no visual cue | Created `EmptyState` component with icon, message, and action button across all pages |
|
| Basic empty states with no visual cue | Created `EmptyState` component with icon, message, and action button across all pages |
|
||||||
|
| No logout button | Added logout button to sidebar footer with `LogOut` icon and destructive hover style |
|
||||||
|
| Todo category filter was case sensitive | Changed to case-insensitive comparison with `.toLowerCase()` |
|
||||||
|
| Dialog/popup forms too narrow and cramped | Widened `DialogContent` from `max-w-lg` to `max-w-xl` with mobile margin |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -124,8 +127,8 @@ These were found during first Docker build and integration testing:
|
|||||||
|
|
||||||
### Important (blocks functionality):
|
### Important (blocks functionality):
|
||||||
3. ~~**Alembic migration test**~~ - DONE: Tables create correctly on first boot
|
3. ~~**Alembic migration test**~~ - DONE: Tables create correctly on first boot
|
||||||
4. **Auth flow test** - PIN setup -> login -> session persistence -> logout
|
4. ~~**Auth flow test**~~ - DONE: PIN setup works, PIN change works, session persistence works, logout added
|
||||||
5. **End-to-end CRUD test** - Partially verified: Calendar (create/edit/drag/delete), Projects (create), Dashboard (today's events). Remaining: Todos, Reminders, People, Locations, Settings
|
5. ~~**End-to-end CRUD test**~~ - DONE: All features verified — Calendar, Projects, Todos (create/edit/filter/search), People (CRUD + search), Locations (CRUD + filter), Reminders (CRUD + dismiss), Settings (accent color + PIN)
|
||||||
|
|
||||||
### Nice to have (polish):
|
### Nice to have (polish):
|
||||||
6. ~~**Responsive sidebar**~~ - DONE: Mobile hamburger menu with overlay, desktop collapse/expand
|
6. ~~**Responsive sidebar**~~ - DONE: Mobile hamburger menu with overlay, desktop collapse/expand
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user