Replace status_id with in_progress boolean field

- Remove task_statuses lookup table and StatusID foreign key
- Add InProgress boolean field to Task model
- Add database migration (005_replace_status_with_in_progress)
- Update all handlers, services, and repositories
- Update admin frontend to display in_progress as checkbox/boolean
- Remove Task Statuses tab from admin lookups page
- Update tests to use InProgress instead of StatusID
- Task categorization now uses InProgress for kanban column assignment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-08 20:48:16 -06:00
parent cb250f108b
commit c5b0225422
43 changed files with 353 additions and 753 deletions
+2 -3
View File
@@ -38,7 +38,6 @@ import {
const lookupTabs = [
{ key: 'categories', label: 'Task Categories', api: lookupsApi.categories },
{ key: 'priorities', label: 'Task Priorities', api: lookupsApi.priorities },
{ key: 'statuses', label: 'Task Statuses', api: lookupsApi.statuses },
{ key: 'frequencies', label: 'Task Frequencies', api: lookupsApi.frequencies },
{ key: 'residenceTypes', label: 'Residence Types', api: lookupsApi.residenceTypes },
{ key: 'specialties', label: 'Contractor Specialties', api: lookupsApi.specialties },
@@ -320,12 +319,12 @@ export default function LookupsPage() {
<CardHeader>
<CardTitle>Reference Data</CardTitle>
<CardDescription>
Configure task categories, priorities, statuses, frequencies, residence types, and contractor specialties
Configure task categories, priorities, frequencies, residence types, and contractor specialties
</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="categories" className="w-full">
<TabsList className="grid w-full grid-cols-6">
<TabsList className="grid w-full grid-cols-5">
{lookupTabs.map((tab) => (
<TabsTrigger key={tab.key} value={tab.key} className="text-xs">
{tab.label}
@@ -248,7 +248,7 @@ export function ResidenceDetailClient() {
<TableHeader>
<TableRow>
<TableHead>Title</TableHead>
<TableHead>Status</TableHead>
<TableHead>In Progress</TableHead>
<TableHead>Priority</TableHead>
<TableHead>Category</TableHead>
<TableHead>Due Date</TableHead>
@@ -271,7 +271,7 @@ export function ResidenceDetailClient() {
</div>
</TableCell>
<TableCell>
<Badge variant="outline">{task.status_name || '-'}</Badge>
{task.in_progress ? '✓' : ''}
</TableCell>
<TableCell>{task.priority_name || '-'}</TableCell>
<TableCell>{task.category_name || '-'}</TableCell>
+1 -1
View File
@@ -108,7 +108,7 @@ export default function SettingsPage() {
This will insert or update all lookup tables including:
<ul className="list-disc list-inside mt-2 space-y-1">
<li>Residence types</li>
<li>Task categories, priorities, statuses, frequencies</li>
<li>Task categories, priorities, frequencies</li>
<li>Contractor specialties</li>
<li>Subscription tiers and feature benefits</li>
<li><strong>Task templates (60+ predefined tasks)</strong></li>
@@ -117,8 +117,8 @@ export function TaskDetailClient() {
<div>{task.priority_name || '-'}</div>
</div>
<div>
<div className="text-sm font-medium text-muted-foreground">Status</div>
<div>{task.status_name || '-'}</div>
<div className="text-sm font-medium text-muted-foreground">In Progress</div>
<div>{task.in_progress ? 'Yes' : 'No'}</div>
</div>
<div>
<div className="text-sm font-medium text-muted-foreground">Due Date</div>
@@ -62,11 +62,6 @@ export default function EditTaskPage() {
queryFn: () => lookupsApi.priorities.list(),
});
const { data: statuses, isLoading: statusesLoading } = useQuery({
queryKey: ['lookups', 'statuses'],
queryFn: () => lookupsApi.statuses.list(),
});
const { data: frequencies, isLoading: frequenciesLoading } = useQuery({
queryKey: ['lookups', 'frequencies'],
queryFn: () => lookupsApi.frequencies.list(),
@@ -85,7 +80,7 @@ export default function EditTaskPage() {
const [formInitialized, setFormInitialized] = useState(false);
// Wait for ALL data including lookups before initializing form
const lookupsLoaded = !categoriesLoading && !prioritiesLoading && !statusesLoading && !frequenciesLoading;
const lookupsLoaded = !categoriesLoading && !prioritiesLoading && !frequenciesLoading;
useEffect(() => {
if (task && lookupsLoaded && !formInitialized) {
@@ -97,7 +92,7 @@ export default function EditTaskPage() {
description: task.description,
category_id: task.category_id,
priority_id: task.priority_id,
status_id: task.status_id,
in_progress: task.in_progress,
frequency_id: task.frequency_id,
due_date: task.due_date,
next_due_date: task.next_due_date,
@@ -323,30 +318,15 @@ export default function EditTaskPage() {
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="status_id">Status</Label>
<Select
value={formData.status_id !== undefined ? formData.status_id.toString() : 'none'}
onValueChange={(value) => {
const newValue = value === 'none' ? undefined : Number(value);
// Only update if actually different (prevents spurious triggers)
if (newValue !== formData.status_id) {
updateField('status_id', newValue);
}
}}
>
<SelectTrigger>
<SelectValue placeholder="Select status" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none">None</SelectItem>
{statuses?.map((status: { id: number; name: string }) => (
<SelectItem key={status.id} value={status.id.toString()}>
{status.name}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex items-center space-x-2 pt-8">
<input
type="checkbox"
id="in_progress"
checked={formData.in_progress ?? false}
onChange={(e) => updateField('in_progress', e.target.checked)}
className="h-4 w-4 rounded border-gray-300"
/>
<Label htmlFor="in_progress">In Progress</Label>
</div>
<div className="space-y-2">
<Label htmlFor="frequency_id">Frequency</Label>
+3 -3
View File
@@ -58,9 +58,9 @@ const columns: ColumnDef<Task>[] = [
cell: ({ row }) => row.original.priority_name || '-',
},
{
accessorKey: 'status_name',
header: 'Status',
cell: ({ row }) => row.original.status_name || '-',
accessorKey: 'in_progress',
header: 'In Progress',
cell: ({ row }) => row.original.in_progress ? '✓' : '',
},
{
accessorKey: 'due_date',
-1
View File
@@ -517,7 +517,6 @@ const createLookupApi = (endpoint: string) => ({
export const lookupsApi = {
categories: createLookupApi('categories'),
priorities: createLookupApi('priorities'),
statuses: createLookupApi('statuses'),
frequencies: createLookupApi('frequencies'),
residenceTypes: createLookupApi('residence-types'),
specialties: createLookupApi('specialties'),
+4 -5
View File
@@ -186,8 +186,7 @@ export interface Task {
category_name?: string;
priority_id?: number;
priority_name?: string;
status_id?: number;
status_name?: string;
in_progress: boolean;
frequency_id?: number;
frequency_name?: string;
due_date?: string;
@@ -211,7 +210,7 @@ export interface TaskListParams extends ListParams {
residence_id?: number;
category_id?: number;
priority_id?: number;
status_id?: number;
in_progress?: boolean;
is_cancelled?: boolean;
is_archived?: boolean;
}
@@ -223,7 +222,7 @@ export interface CreateTaskRequest {
description?: string;
category_id?: number;
priority_id?: number;
status_id?: number;
in_progress?: boolean;
frequency_id?: number;
assigned_to_id?: number;
due_date?: string;
@@ -239,7 +238,7 @@ export interface UpdateTaskRequest {
description?: string;
category_id?: number;
priority_id?: number;
status_id?: number;
in_progress?: boolean;
frequency_id?: number;
due_date?: string;
next_due_date?: string;