workout-builder.store.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { create } from "zustand";
  2. import { ExerciseAttributeValueEnum, WorkoutSessionExercise } from "@prisma/client";
  3. import { WorkoutBuilderStep } from "../types";
  4. import { shuffleExerciseAction } from "../actions/shuffle-exercise.action";
  5. import { getExercisesAction } from "./get-exercises.action";
  6. interface WorkoutBuilderState {
  7. currentStep: WorkoutBuilderStep;
  8. selectedEquipment: ExerciseAttributeValueEnum[];
  9. selectedMuscles: ExerciseAttributeValueEnum[];
  10. // Exercices (groupés par muscle)
  11. exercisesByMuscle: any[];
  12. isLoadingExercises: boolean;
  13. exercisesError: any;
  14. exercisesOrder: string[];
  15. isShuffling: boolean;
  16. // Actions
  17. setStep: (step: WorkoutBuilderStep) => void;
  18. nextStep: () => void;
  19. prevStep: () => void;
  20. toggleEquipment: (equipment: ExerciseAttributeValueEnum) => void;
  21. clearEquipment: () => void;
  22. toggleMuscle: (muscle: ExerciseAttributeValueEnum) => void;
  23. clearMuscles: () => void;
  24. fetchExercises: () => Promise<void>;
  25. setExercisesOrder: (order: string[]) => void;
  26. shuffleExercise: (exerciseId: string, muscle: ExerciseAttributeValueEnum) => Promise<void>;
  27. loadFromSession: (params: {
  28. equipment: ExerciseAttributeValueEnum[];
  29. muscles: ExerciseAttributeValueEnum[];
  30. exercisesByMuscle: {
  31. muscle: ExerciseAttributeValueEnum;
  32. exercises: WorkoutSessionExercise[];
  33. }[];
  34. exercisesOrder: string[];
  35. }) => void;
  36. }
  37. export const useWorkoutBuilderStore = create<WorkoutBuilderState>((set, get) => ({
  38. currentStep: 1 as WorkoutBuilderStep,
  39. selectedEquipment: [],
  40. selectedMuscles: [],
  41. exercisesByMuscle: [],
  42. isLoadingExercises: false,
  43. exercisesError: null,
  44. exercisesOrder: [],
  45. isShuffling: false,
  46. setStep: (step) => set({ currentStep: step }),
  47. nextStep: () => set((state) => ({ currentStep: Math.min(state.currentStep + 1, 3) as WorkoutBuilderStep })),
  48. prevStep: () => set((state) => ({ currentStep: Math.max(state.currentStep - 1, 1) as WorkoutBuilderStep })),
  49. toggleEquipment: (equipment) =>
  50. set((state) => ({
  51. selectedEquipment: state.selectedEquipment.includes(equipment)
  52. ? state.selectedEquipment.filter((e) => e !== equipment)
  53. : [...state.selectedEquipment, equipment],
  54. })),
  55. clearEquipment: () => set({ selectedEquipment: [] }),
  56. toggleMuscle: (muscle) =>
  57. set((state) => ({
  58. selectedMuscles: state.selectedMuscles.includes(muscle)
  59. ? state.selectedMuscles.filter((m) => m !== muscle)
  60. : [...state.selectedMuscles, muscle],
  61. })),
  62. clearMuscles: () => set({ selectedMuscles: [] }),
  63. fetchExercises: async () => {
  64. set({ isLoadingExercises: true, exercisesError: null });
  65. try {
  66. const { selectedEquipment, selectedMuscles } = get();
  67. const result = await getExercisesAction({
  68. equipment: selectedEquipment,
  69. muscles: selectedMuscles,
  70. limit: 3,
  71. });
  72. if (result?.serverError) {
  73. throw new Error(result.serverError);
  74. }
  75. set({ exercisesByMuscle: result?.data || [], isLoadingExercises: false });
  76. } catch (error) {
  77. set({ exercisesError: error, isLoadingExercises: false });
  78. }
  79. },
  80. setExercisesOrder: (order) => set({ exercisesOrder: order }),
  81. shuffleExercise: async (exerciseId, muscle) => {
  82. set({ isShuffling: true });
  83. try {
  84. const { selectedEquipment, exercisesByMuscle } = get();
  85. // Récupérer tous les IDs des exercices dans le workout actuel
  86. const allExerciseIds = exercisesByMuscle.flatMap((group) => group.exercises.map((ex: any) => ex.id));
  87. const result = await shuffleExerciseAction({
  88. currentExerciseId: exerciseId,
  89. muscle: muscle,
  90. equipment: selectedEquipment,
  91. excludeExerciseIds: allExerciseIds,
  92. });
  93. if (result?.serverError) {
  94. throw new Error(result.serverError);
  95. }
  96. if (result?.data?.exercise) {
  97. const newExercise = result.data.exercise;
  98. set((state) => ({
  99. exercisesByMuscle: state.exercisesByMuscle.map((group) => {
  100. if (group.muscle === muscle) {
  101. return {
  102. ...group,
  103. exercises: group.exercises.map((ex: any) => (ex.id === exerciseId ? { ...newExercise, order: ex.order } : ex)),
  104. };
  105. }
  106. return group;
  107. }),
  108. }));
  109. set((state) => ({
  110. exercisesOrder: state.exercisesOrder.map((id) => (id === exerciseId ? newExercise.id : id)),
  111. }));
  112. }
  113. } catch (error) {
  114. console.error("Error shuffling exercise:", error);
  115. throw error;
  116. } finally {
  117. set({ isShuffling: false });
  118. }
  119. },
  120. loadFromSession: ({ equipment, muscles, exercisesByMuscle, exercisesOrder }) => {
  121. set({
  122. selectedEquipment: equipment,
  123. selectedMuscles: muscles,
  124. exercisesByMuscle,
  125. exercisesOrder,
  126. currentStep: 3,
  127. isLoadingExercises: false,
  128. exercisesError: null,
  129. });
  130. },
  131. }));