瀏覽代碼

feat(workout-session): add WorkoutSessionsSynchronizer component for syncing workout sessions and enhance schema validation for workout sessions and exercises

Mathias 1 月之前
父節點
當前提交
bf925a4a15

+ 2 - 0
app/[locale]/layout.tsx

@@ -7,6 +7,7 @@ import { cn } from "@/shared/lib/utils";
 import { getServerUrl } from "@/shared/lib/server-url";
 import { FB_PIXEL_ID } from "@/shared/lib/facebook/fb-pixel";
 import { SiteConfig } from "@/shared/config/site-config";
+import { WorkoutSessionsSynchronizer } from "@/features/workout-session/ui/workout-sessions-synchronizer";
 import { Header } from "@/features/layout/Header";
 import { Footer } from "@/features/layout/Footer";
 import { TailwindIndicator } from "@/components/utils/TailwindIndicator";
@@ -114,6 +115,7 @@ export default async function RootLayout({ params, children }: RootLayoutProps)
           suppressHydrationWarning
         >
           <Providers locale={locale}>
+            <WorkoutSessionsSynchronizer />
             <NextTopLoader color="#FF5722" delay={100} showSpinner={false} />
 
             {/* Main Card Container */}

+ 37 - 7
src/features/workout-session/actions/sync-workout-sessions.action.ts

@@ -6,14 +6,33 @@ import { workoutSessionStatuses } from "@/shared/lib/workout-session/types/worko
 import { prisma } from "@/shared/lib/prisma";
 import { actionClient } from "@/shared/api/safe-actions";
 
-// Schéma de validation
+// Schéma WorkoutSet
+const workoutSetSchema = z.object({
+  id: z.string(),
+  setIndex: z.number(),
+  types: z.array(z.enum(["TIME", "WEIGHT", "REPS", "BODYWEIGHT", "NA"])),
+  valueInt: z.number().optional(),
+  valuesInt: z.array(z.number()).optional(),
+  valueSec: z.number().optional(),
+  valuesSec: z.array(z.number()).optional(),
+  unit: z.enum(["kg", "lbs"]).optional(),
+  units: z.array(z.enum(["kg", "lbs"])).optional(),
+  completed: z.boolean(),
+});
+
+const workoutSessionExerciseSchema = z.object({
+  id: z.string(),
+  order: z.number(),
+  sets: z.array(workoutSetSchema),
+});
+
 const syncWorkoutSessionSchema = z.object({
   session: z.object({
     id: z.string(),
     userId: z.string(),
     startedAt: z.string(),
     endedAt: z.string().optional(),
-    exercises: z.array(z.any()), // TODO: define the schema
+    exercises: z.array(workoutSessionExerciseSchema),
     status: z.enum(workoutSessionStatuses),
   }),
 });
@@ -28,9 +47,15 @@ export const syncWorkoutSessionAction = actionClient.schema(syncWorkoutSessionSc
         ...session,
         exercises: {
           create: session.exercises.map((exercise) => ({
-            ...exercise,
+            id: exercise.id,
+            order: exercise.order,
+            exerciseId: exercise.id,
+            exercise: { connect: { id: exercise.id } },
             sets: {
-              create: exercise.sets,
+              create: exercise.sets.map((set) => ({
+                ...set,
+                type: set.types && set.types.length > 0 ? set.types[0] : "NA",
+              })),
             },
           })),
         },
@@ -38,11 +63,16 @@ export const syncWorkoutSessionAction = actionClient.schema(syncWorkoutSessionSc
       update: {
         ...session,
         exercises: {
-          deleteMany: {},
           create: session.exercises.map((exercise) => ({
-            ...exercise,
+            id: exercise.id,
+            order: exercise.order,
+            exerciseId: exercise.id,
+            exercise: { connect: { id: exercise.id } },
             sets: {
-              create: exercise.sets,
+              create: exercise.sets.map((set) => ({
+                ...set,
+                type: set.types && set.types.length > 0 ? set.types[0] : "NA",
+              })),
             },
           })),
         },

+ 13 - 0
src/features/workout-session/ui/workout-sessions-synchronizer.tsx

@@ -0,0 +1,13 @@
+"use client";
+
+import { useSyncWorkoutSessions } from "../model/use-sync-workout-sessions";
+
+export const WorkoutSessionsSynchronizer = () => {
+  const { isSyncing, syncSessions } = useSyncWorkoutSessions();
+
+  if (isSyncing) {
+    return <div>Synchronizing...</div>;
+  }
+
+  return <button onClick={() => syncSessions()}>Sync</button>;
+};