Add todo list with kanban board view

- todos table with title, description, status (todo/in_progress/done),
  priority (urgent/high/medium/low), optional device link, due date
- List view: sorted by priority, inline edit, click-to-advance status
  circle (empty → blue dot → green check), edit/delete actions
- Kanban board view: three columns, move buttons between statuses,
  priority badges, device links, due dates
- Toggle between List and Board views via URL param
- Optional link to a device for repair-related todos
- Sidebar nav item added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 13:55:16 +07:00
parent 59371d0cbb
commit fe54496d79
5 changed files with 501 additions and 0 deletions
+5
View File
@@ -37,6 +37,11 @@
label: 'Locations',
icon: 'M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z M15 11a3 3 0 11-6 0 3 3 0 016 0z'
},
{
href: '/todos',
label: 'Todos',
icon: 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'
},
{
href: '/checklists',
label: 'Checklists',
+14
View File
@@ -49,6 +49,20 @@ export const DEVICE_LOG_TYPES = [
export type DeviceLogType = (typeof DEVICE_LOG_TYPES)[number];
export const TODO_STATUSES = ['todo', 'in_progress', 'done'] as const;
export const TODO_STATUS_LABELS: Record<string, string> = {
todo: 'To Do',
in_progress: 'In Progress',
done: 'Done'
};
export const TODO_PRIORITIES = [
{ value: 0, label: 'Urgent', color: 'red' },
{ value: 1, label: 'High', color: 'orange' },
{ value: 2, label: 'Medium', color: 'blue' },
{ value: 3, label: 'Low', color: 'gray' }
] as const;
export const VOLTAGE_OPTIONS = [
'110V AC', '115V AC', '120V AC', '127V AC', '220V AC', '230V AC', '240V AC',
'5V DC', '6V DC', '9V DC', '12V DC', '15V DC', '19V DC', '24V DC',
+24
View File
@@ -274,3 +274,27 @@ export const deviceLog = pgTable(
check('device_log_type_check', sql`${table.type} IN ('repair', 'inspection', 'cleaning', 'modification', 'diagnostic', 'recap', 'other')`)
]
);
// ─── Todos ──────────────────────────────────────────────────────────
export const todos = pgTable(
'todos',
{
id: uuid('id').defaultRandom().primaryKey(),
title: text('title').notNull(),
description: text('description'),
status: text('status').notNull().default('todo'),
priority: integer('priority').notNull().default(2), // 0=urgent, 1=high, 2=medium, 3=low
deviceId: uuid('device_id').references(() => devices.id, { onDelete: 'set null' }),
dueDate: timestamp('due_date', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => [
index('todos_status_idx').on(table.status),
index('todos_priority_idx').on(table.priority),
index('todos_device_idx').on(table.deviceId),
check('todos_status_check', sql`${table.status} IN ('todo', 'in_progress', 'done')`),
check('todos_priority_check', sql`${table.priority} IN (0, 1, 2, 3)`)
]
);