feat(health): health card share link, PDF export, weight chart in card
- ShareDialog: expiry selector (7/14/30/60/90 days, default 14), shows expiry date after generation, "Als PDF öffnen / drucken" button - WeightChart extracted to standalone component (WeightChart.tsx) so it can be shared between HealthDashboard and the public health card page - Health card page: renders WeightChart when 2+ weight entries exist - AutoPrint client component: auto-triggers window.print() when card is opened with ?print=1 (600ms delay for render to settle) - README: Phase 6 + Phase 7 marked complete with full feature summaries; project structure and router list updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
b9f786c87f
commit
80559c3b3f
12 files changed
+780
-371
No files matched your search
@@ -135,27 +135,43 @@ export const healthRouter = router({
|
||||
// ── Health Card ──────────────────────────────────────────────────────────────
|
||||
|
||||
getOrCreateCard: protectedProcedure
|
||||
.input(z.object({ petId: z.string().min(1) }))
|
||||
.input(z.object({
|
||||
petId: z.string().min(1),
|
||||
expiryDays: z.union([
|
||||
z.literal(7), z.literal(14), z.literal(30),
|
||||
z.literal(60), z.literal(90),
|
||||
]).default(14),
|
||||
}))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
await assertOwner(ctx.prisma, input.petId, ctx.userId);
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setDate(expiresAt.getDate() + input.expiryDays);
|
||||
const card = await ctx.prisma.healthCard.upsert({
|
||||
where: { petId: input.petId },
|
||||
update: {},
|
||||
create: { petId: input.petId },
|
||||
update: { expiresAt },
|
||||
create: { petId: input.petId, expiresAt },
|
||||
});
|
||||
return { token: card.token };
|
||||
return { token: card.token, expiresAt: card.expiresAt };
|
||||
}),
|
||||
|
||||
regenerateCard: protectedProcedure
|
||||
.input(z.object({ petId: z.string().min(1) }))
|
||||
.input(z.object({
|
||||
petId: z.string().min(1),
|
||||
expiryDays: z.union([
|
||||
z.literal(7), z.literal(14), z.literal(30),
|
||||
z.literal(60), z.literal(90),
|
||||
]).default(14),
|
||||
}))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
await assertOwner(ctx.prisma, input.petId, ctx.userId);
|
||||
const newToken = crypto.randomUUID().replace(/-/g, "");
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setDate(expiresAt.getDate() + input.expiryDays);
|
||||
const card = await ctx.prisma.healthCard.upsert({
|
||||
where: { petId: input.petId },
|
||||
update: { token: newToken },
|
||||
create: { petId: input.petId, token: newToken },
|
||||
update: { token: newToken, expiresAt },
|
||||
create: { petId: input.petId, token: newToken, expiresAt },
|
||||
});
|
||||
return { token: card.token };
|
||||
return { token: card.token, expiresAt: card.expiresAt };
|
||||
}),
|
||||
});
|
||||
Reference in new issue
Block a user