fix(deadlines): submit only form-managed fields from the deadline form (#1185)
* fix(deadlines): submit only form-managed fields from the deadline form Fixes #1176. The form fabricated 11 system-field values on every submit (source: 'user', status: 'upcoming', reminder_offsets, tax_* nulls, ...) and the edit path PUT the entire merged Deadline row; only the route handlers' whitelists prevented editing a system-generated tax deadline from nuking those fields. The form now has an explicit DeadlineFormValues contract (the 7 fields it renders), create and edit send exactly that, and the edit handler takes (id, values) instead of a whole Deadline. No behavior change today; removes the latent data-loss dependency on the server whitelist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(deadlines): migrate calendar DeadlineForm consumers to DeadlineFormValues The calendar extension's PaymentCalendar (and its CalendarWorkspace host) still typed the submit chain as the old full-row Omit<Deadline> shape, failing the core-only typecheck. Behavior unchanged: the raw insert already omitted ids, and the DB defaults cover system fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d012d40b18
commit
731a57dd6e
@@ -24,10 +24,21 @@ import { formatDateISO, DEADLINE_TYPE_LABELS, PRIORITY_LABELS } from '@/lib/cale
|
||||
import { useCanWrite } from '@/lib/hooks/use-can-write'
|
||||
import { Lock } from 'lucide-react'
|
||||
|
||||
/**
|
||||
* Only the fields the form actually manages. Both API routes whitelist to
|
||||
* this set; the form must never fabricate values for system fields (source,
|
||||
* status, reminder_offsets, tax_*), or editing a system-generated tax
|
||||
* deadline would depend on the server whitelist alone to avoid data loss.
|
||||
*/
|
||||
export type DeadlineFormValues = Pick<
|
||||
Deadline,
|
||||
'title' | 'due_date' | 'due_time' | 'deadline_type' | 'priority' | 'customer_id' | 'notes'
|
||||
>
|
||||
|
||||
interface DeadlineFormProps {
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
onSubmit: (data: Omit<Deadline, 'id' | 'user_id' | 'company_id' | 'created_at' | 'updated_at'>) => Promise<void>
|
||||
onSubmit: (data: DeadlineFormValues) => Promise<void>
|
||||
onDelete?: (deadline: Partial<Deadline>) => void
|
||||
initialData?: Partial<Deadline>
|
||||
initialDate?: Date | null
|
||||
@@ -107,20 +118,6 @@ export function DeadlineForm({
|
||||
priority: formData.priority,
|
||||
customer_id: formData.customer_id || null,
|
||||
notes: formData.notes || null,
|
||||
is_completed: initialData?.is_completed || false,
|
||||
completed_at: initialData?.completed_at || null,
|
||||
is_auto_generated: false,
|
||||
// New tax deadline fields with defaults for user-created deadlines
|
||||
tax_deadline_type: null,
|
||||
tax_period: null,
|
||||
source: 'user',
|
||||
reminder_offsets: [14, 7, 1, 0],
|
||||
status: 'upcoming',
|
||||
status_changed_at: new Date().toISOString(),
|
||||
linked_report_type: null,
|
||||
linked_report_period: null,
|
||||
dismissed_at: null,
|
||||
tax_assessment_notice_id: null,
|
||||
})
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState, useEffect, useCallback } from 'react'
|
||||
import { createClient } from '@/lib/supabase/client'
|
||||
import { useToast } from '@/components/ui/use-toast'
|
||||
import { PaymentCalendar } from '@/extensions/general/calendar/components/PaymentCalendar'
|
||||
import type { DeadlineFormValues } from '@/components/deadlines/DeadlineForm'
|
||||
import type { WorkspaceComponentProps } from '@/lib/extensions/workspace-registry'
|
||||
import type { Invoice, Deadline } from '@/types'
|
||||
|
||||
@@ -58,9 +59,7 @@ export default function CalendarWorkspace({ userId }: WorkspaceComponentProps) {
|
||||
fetchData()
|
||||
}, [fetchData])
|
||||
|
||||
const handleDeadlineCreate = async (
|
||||
data: Omit<Deadline, 'id' | 'user_id' | 'company_id' | 'created_at' | 'updated_at'>
|
||||
) => {
|
||||
const handleDeadlineCreate = async (data: DeadlineFormValues) => {
|
||||
try {
|
||||
const { error } = await supabase.from('deadlines').insert([data])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user