chore: fix typecheck on monorepo
- regeneratePlan: switch return type to Promise<void> so it satisfies the React form action contract. - fast.routes PATCH: omit undefined keys instead of passing them, to comply with Prisma + exactOptionalPropertyTypes. - weight-entry-form: cast field value/defaultValues to bypass z.input reporting `Date` for `z.coerce.date()` (zod 3.25 still emits the target type, not unknown). pnpm typecheck, lint, test now all green across the monorepo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ad1e4ecaeb
commit
cdfc685855
3 files changed
+20
-14
No files matched your search
@@ -59,14 +59,17 @@ export const fastRoutes: FastifyPluginAsync = async (fastify) => {
|
|||||||
});
|
});
|
||||||
if (!owned) return reply.code(404).send({ error: 'fast_event_not_found' });
|
if (!owned) return reply.code(404).send({ error: 'fast_event_not_found' });
|
||||||
|
|
||||||
|
// Costruiamo l'oggetto data omettendo le chiavi non fornite, perché con
|
||||||
|
// `exactOptionalPropertyTypes` Prisma rifiuta `undefined` esplicito.
|
||||||
|
const updateData: Parameters<typeof fastify.prisma.fastEvent.update>[0]['data'] = {};
|
||||||
|
if (data.endedAt) updateData.endedAt = data.endedAt;
|
||||||
|
if (data.status) updateData.status = data.status;
|
||||||
|
if (data.symptoms) updateData.symptoms = JSON.stringify(data.symptoms);
|
||||||
|
if (data.notes != null) updateData.notes = data.notes;
|
||||||
|
|
||||||
const event = await fastify.prisma.fastEvent.update({
|
const event = await fastify.prisma.fastEvent.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: {
|
data: updateData,
|
||||||
endedAt: data.endedAt ?? undefined,
|
|
||||||
status: data.status ?? undefined,
|
|
||||||
symptoms: data.symptoms ? JSON.stringify(data.symptoms) : undefined,
|
|
||||||
notes: data.notes ?? undefined,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
return { event: { id: event.id, status: event.status } };
|
return { event: { id: event.id, status: event.status } };
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ export async function fetchCurrentPlan(): Promise<CurrentPlan | null> {
|
|||||||
return data.plan;
|
return data.plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RegenerateResult = { ok: true } | { ok: false; error: string };
|
// Server action invocata via `<form action={regeneratePlan}>`. La firma è
|
||||||
|
// `(FormData) => Promise<void>` per allinearsi al type richiesto da React 18.
|
||||||
export async function regeneratePlan(): Promise<RegenerateResult> {
|
export async function regeneratePlan(_formData?: FormData): Promise<void> {
|
||||||
const res = await fetch(`${API_URL}/me/meal-plans`, {
|
const res = await fetch(`${API_URL}/me/meal-plans`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { cookie: cookieHeader() },
|
headers: { cookie: cookieHeader() },
|
||||||
@@ -52,10 +52,9 @@ export async function regeneratePlan(): Promise<RegenerateResult> {
|
|||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const body = (await res.json().catch(() => ({}))) as { error?: string };
|
const body = (await res.json().catch(() => ({}))) as { error?: string };
|
||||||
return { ok: false, error: body.error ?? `api_error_${res.status}` };
|
throw new Error(body.error ?? `api_error_${res.status}`);
|
||||||
}
|
}
|
||||||
revalidatePath('/plan');
|
revalidatePath('/plan');
|
||||||
return { ok: true };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SwapResult = { ok: true } | { ok: false; error: string };
|
export type SwapResult = { ok: true } | { ok: false; error: string };
|
||||||
|
|||||||
@@ -29,12 +29,16 @@ export function WeightEntryForm({ latest }: { latest: WeightEntryRow | null }) {
|
|||||||
const [serverError, setServerError] = useState<string | null>(null);
|
const [serverError, setServerError] = useState<string | null>(null);
|
||||||
const [savedAt, setSavedAt] = useState<string | null>(null);
|
const [savedAt, setSavedAt] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// L'input HTML type="date" passa stringhe ISO; zod le coerce a Date a runtime
|
||||||
|
// (vedi `weightEntryInputSchema.date = z.coerce.date()`). Il TS-side resta
|
||||||
|
// strict, perciò usiamo cast `unknown` agli ingressi dei defaultValues e di
|
||||||
|
// form.reset.
|
||||||
const form = useForm<WeightEntryInput>({
|
const form = useForm<WeightEntryInput>({
|
||||||
resolver: zodResolver(weightEntryInputSchema),
|
resolver: zodResolver(weightEntryInputSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
date: todayISO(),
|
date: todayISO(),
|
||||||
weightKg: latest?.weightKg,
|
weightKg: latest?.weightKg,
|
||||||
} as WeightEntryInput,
|
} as unknown as WeightEntryInput,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = form.handleSubmit(async (input) => {
|
const onSubmit = form.handleSubmit(async (input) => {
|
||||||
@@ -45,7 +49,7 @@ export function WeightEntryForm({ latest }: { latest: WeightEntryRow | null }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSavedAt(new Date().toISOString());
|
setSavedAt(new Date().toISOString());
|
||||||
form.reset({ date: todayISO(), weightKg: input.weightKg } as WeightEntryInput);
|
form.reset({ date: todayISO(), weightKg: input.weightKg } as unknown as WeightEntryInput);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -59,7 +63,7 @@ export function WeightEntryForm({ latest }: { latest: WeightEntryRow | null }) {
|
|||||||
<FormItem className="space-y-3">
|
<FormItem className="space-y-3">
|
||||||
<FormLabel>{t('date')}</FormLabel>
|
<FormLabel>{t('date')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input type="date" {...field} value={field.value as string} />
|
<Input type="date" {...field} value={field.value as unknown as string} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
Reference in new issue
Block a user