From 3993466b4daed5d3837bf0b51ec7d5065d328af1 Mon Sep 17 00:00:00 2001 From: tonyfages Date: Mon, 12 May 2025 11:08:01 +0200 Subject: [PATCH] add store for API connection :spakles: --- api/client.jsx | 13 ++++ api/endpoints.jsx | 5 ++ api/services/ExercicesServices.jsx | 12 +++ app/(tabs)/(exercice)/ExercicesScreen.tsx | 81 +++++++++++---------- app/(tabs)/(exercice)/WorkoutScreen.tsx | 60 +++++++++++---- app/(tabs)/(home)/HomeScreen.tsx | 27 ++++++- components/WorkoutCardComponent.tsx | 12 +-- components/WorkoutPresentationComponent.tsx | 23 +++--- hook/useExercices.jsx | 19 +++++ model/Workout.ts | 53 +++----------- package-lock.json | 68 +++++++++++++++++ package.json | 1 + 12 files changed, 260 insertions(+), 114 deletions(-) create mode 100644 api/client.jsx create mode 100644 api/endpoints.jsx create mode 100644 api/services/ExercicesServices.jsx create mode 100644 hook/useExercices.jsx diff --git a/api/client.jsx b/api/client.jsx new file mode 100644 index 0000000..22c061c --- /dev/null +++ b/api/client.jsx @@ -0,0 +1,13 @@ +import axios from 'axios'; + +const apiClient = axios.create({ + baseURL: 'https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1/', + timeout: 10000, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // ajoute ici les headers supplémentaires, ex. Auth + }, +}); + +export default apiClient; diff --git a/api/endpoints.jsx b/api/endpoints.jsx new file mode 100644 index 0000000..dacb119 --- /dev/null +++ b/api/endpoints.jsx @@ -0,0 +1,5 @@ + + +export const EXERCICES = { + GETALL: '/exercices', +} \ No newline at end of file diff --git a/api/services/ExercicesServices.jsx b/api/services/ExercicesServices.jsx new file mode 100644 index 0000000..ca27e8f --- /dev/null +++ b/api/services/ExercicesServices.jsx @@ -0,0 +1,12 @@ +import apiClient from "../client"; +import {EXERCICES} from "../endpoints"; + +export const getExercices = async () => { + try { + const response = await apiClient.get(EXERCICES.GETALL); + return response.data.data; + } catch (error) { + console.error(error); + throw error; + } +}; diff --git a/app/(tabs)/(exercice)/ExercicesScreen.tsx b/app/(tabs)/(exercice)/ExercicesScreen.tsx index bbe405c..33494dd 100644 --- a/app/(tabs)/(exercice)/ExercicesScreen.tsx +++ b/app/(tabs)/(exercice)/ExercicesScreen.tsx @@ -1,47 +1,54 @@ -import {FlatList, SafeAreaView, Text, View} from "react-native"; -import React from "react"; -import HeaderProfileComponent from "@/components/HeaderProfileComponent"; -import Screen from "@/components/ui/Screen"; +import React, { useEffect, useState } from 'react'; +import { FlatList, Text, TouchableOpacity, View } from 'react-native'; +import { getExercices } from "@/api/services/ExercicesServices"; +import { useRouter } from "expo-router"; +import { Workout } from "@/model/Workout"; import WorkoutCardComponent from "@/components/WorkoutCardComponent"; -import {useSession} from "@/ctx"; -import {Workout} from "@/model/Workout"; -import LinearTimer from "react-native-linear-timer"; export default function ExercicesScreen() { - const [text, onChangeText] = React.useState(""); - const exercise = [new Workout("Développé couché", 25,"8 Series Workout", 412, "assets/images/Sigma-2.png","Intense" ), - new Workout("Curl halterné", 30, "8 Series Workout", 342, "assets/images/Sigma.jpg","Medium" ), - new Workout("Tirage Vertival", 29, "8 Series Workout", 793, "assets/images/Sigma.jpg","Easy" )]; - - return ( - - - - - - - - - Séance du jour - - - - + const [exercices, setExercices] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const router = useRouter(); + + useEffect(() => { + const fetchData = async () => { + try { + const data = await getExercices(); + setExercices(data); + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); } - data={exercise} - className="h-full" - renderItem={({ item }: { item: Workout }) => + }; - - - - } - /> + fetchData(); + }, []); + + if (loading) { + return Chargement...; + } - + if (error) { + return Erreur : {error}; + } + return ( + + item.id} + renderItem={({ item }) => ( + router.push({ pathname: "/WorkoutScreen", params: { workout: JSON.stringify(item) } })} + > + + + )} + /> + ); } \ No newline at end of file diff --git a/app/(tabs)/(exercice)/WorkoutScreen.tsx b/app/(tabs)/(exercice)/WorkoutScreen.tsx index f11ad98..868be03 100644 --- a/app/(tabs)/(exercice)/WorkoutScreen.tsx +++ b/app/(tabs)/(exercice)/WorkoutScreen.tsx @@ -1,23 +1,53 @@ -import * as React from 'react'; -import LinearTimer from 'react-native-linear-timer'; -import {Button, Image, ImageBackground, SafeAreaView, Text, TouchableOpacity, View} from "react-native"; -import Screen from "@/components/ui/Screen"; -import {Background} from "@react-navigation/elements"; -import {AntDesign} from "@expo/vector-icons"; -import {router, useRouter} from "expo-router"; -import WelcomeComponent from "@/components/WelcomeComponent"; + +import React, { useEffect, useState } from 'react'; +import { View, ActivityIndicator, Text } from 'react-native'; +import { useRouter } from 'expo-router'; import WorkoutPresentationComponent from "@/components/WorkoutPresentationComponent"; +import {getExercices} from "@/api/services/ExercicesServices"; +export default function WorkoutScreen() { + const router = useRouter(); -export default function WorkoutScreen() { + const [exercices, setExercices] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - const router = useRouter(); - return ( + useEffect(() => { + const loadExercices = async () => { + try { + const data = await getExercices(); + setExercices(data); + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + loadExercices(); + }, []); - - + if (loading) { + return ( + + - ) + ); + } + if (error) { + return ( + + {error} + + ); + } + + const workout = exercices[1]; // Choisis l’exercice que tu souhaites afficher -} \ No newline at end of file + return ( + + + + ); +} diff --git a/app/(tabs)/(home)/HomeScreen.tsx b/app/(tabs)/(home)/HomeScreen.tsx index 8ccf479..a1ef407 100644 --- a/app/(tabs)/(home)/HomeScreen.tsx +++ b/app/(tabs)/(home)/HomeScreen.tsx @@ -1,15 +1,34 @@ import {SafeAreaView, ScrollView, Text, View} from "react-native"; -import React from "react"; +import React, {useEffect, useState} from "react"; import WorkoutCardComponent from "@/components/WorkoutCardComponent"; import Screen from "@/components/ui/Screen"; import CalendarComponent from "@/components/CalendarComponent"; import WelcomeComponent from "@/components/WelcomeComponent"; import ActivitiesComponent from "@/components/ActivitiesComponent"; import {Workout} from "@/model/Workout"; +import {useRouter} from "expo-router"; +import {getExercices} from "@/api/services/ExercicesServices"; +import {customRandom, random} from "nanoid"; +import {getRandomNumber} from "react-native-svg/lib/typescript/lib/util"; +export default function HomeScreen() { + const [exercices, setExercices] = useState([]); -export default function HomeScreen() { - const exercise = new Workout("Faire caca par terre", 25,"8 Series Workout", 412, "assets/images/Sigma-2.png","Intense" ); + const getRandomNumber = (min: number, max: number) => { + return Math.floor(Math.random() * (max - min + 1)) + min; + }; + useEffect(() => { + const fetchData = async () => { + try { + const data = await getExercices(); + setExercices(data); + } catch (err: any) { + + } + }; + + fetchData(); + }, []); return ( @@ -41,7 +60,7 @@ export default function HomeScreen() { See All - + diff --git a/components/WorkoutCardComponent.tsx b/components/WorkoutCardComponent.tsx index 68d5d0c..80c95c7 100644 --- a/components/WorkoutCardComponent.tsx +++ b/components/WorkoutCardComponent.tsx @@ -5,7 +5,7 @@ import {Workout} from "@/model/Workout"; import {Link, useRouter} from "expo-router"; interface WorkoutCardComponentProps { - exercise: Workout, + exercise?: Workout, background?: String, height?: number, @@ -34,23 +34,23 @@ export default function WorkoutCardComponent({exercise, height, background}: Wor - {exercise.duration} min + {exercise?.duration} min - {exercise.calories} kcal + {exercise?.name} kcal - {exercise.name} - {exercise.repetitions} + {exercise?.name} + {exercise?.nbRepetitions} - {exercise.level} + {exercise?.name} diff --git a/components/WorkoutPresentationComponent.tsx b/components/WorkoutPresentationComponent.tsx index c395ff6..b2ea558 100644 --- a/components/WorkoutPresentationComponent.tsx +++ b/components/WorkoutPresentationComponent.tsx @@ -2,15 +2,19 @@ import {ImageBackground, TouchableOpacity, View, Text} from "react-native"; import Screen from "@/components/ui/Screen"; import * as React from "react"; import {Ionicons} from "@expo/vector-icons"; -import {useRouter} from "expo-router"; +import {Router, useRouter} from "expo-router"; import LinearProgressBar from "@/components/LinearProgressBar"; import {Workout} from "@/model/Workout"; -import {LinearGradient} from "expo-linear-gradient"; -import WelcomeComponent from "@/components/WelcomeComponent"; -import HeaderProfileComponent from "@/components/HeaderProfileComponent"; -export default function WorkoutPresentationComponent(workout: Workout, dataExercise: any) { - const router = useRouter() + +type WorkoutPresentationComponentProps = { + workout: Workout; + dataExercise: Workout[]; + router: Router; // Typage précis recommandé selon ta navigation +}; + +export default function WorkoutPresentationComponent({ workout}: WorkoutPresentationComponentProps) { + const router = useRouter(); return ( @@ -30,14 +34,15 @@ export default function WorkoutPresentationComponent(workout: Workout, dataExerc {/* Texte en bas */} - Exercise 1 + {workout.nbSeries} x {workout.nbRepetitions} - Back Warmup + + {workout.name} {/* Barre de progression */} - + diff --git a/hook/useExercices.jsx b/hook/useExercices.jsx new file mode 100644 index 0000000..28c7968 --- /dev/null +++ b/hook/useExercices.jsx @@ -0,0 +1,19 @@ +export const useExercices = () => { + const [exercices, setExercices] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + useEffect(() => { + const fetchExercices = async () => { + try { + const response = await apiClient.get(EXERCICES.GETALL); + setExercices(response.data); + setLoading(false); + } catch (error) { + setError(error); + setLoading(false); + } + }; + fetchExercices(); + }, []); + return { exercices, loading, error }; +} \ No newline at end of file diff --git a/model/Workout.ts b/model/Workout.ts index 4665d23..087d8e4 100644 --- a/model/Workout.ts +++ b/model/Workout.ts @@ -1,43 +1,10 @@ -export class Workout { - - private _name: string - private _duration: number - private _calories: number - private _repetitions: string - private _image: string - private _level: string - - - get name(): string { - return this._name; - } - - get duration(): number { - return this._duration; - } - - get calories(): number { - return this._calories; - } - - get repetitions(): string { - return this._repetitions; - } - - get image(): string { - return this._image; - } - - get level(): string { - return this._level; - } - - constructor(name: string, duration: number, repetition: string, calories: number, image: string, level: string) { - this._name = name; - this._duration = duration; - this._repetitions = repetition - this._calories = calories; - this._image = image; - this._level = level; - } -} \ No newline at end of file +export interface Workout { + id: string; + name: string; + description: string; + duration: number; + image: string; + video: string; + nbSeries: number; + nbRepetitions: number; +} diff --git a/package-lock.json b/package-lock.json index 17898f0..6bf7e0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@react-navigation/native": "^7.0.14", "@react-navigation/native-stack": "^7.2.0", "@react-navigation/stack": "^7.1.1", + "axios": "^1.8.3", "dayjs": "^1.11.13", "expo": "^52.0.24", "expo-asset": "^11.0.2", @@ -4633,6 +4634,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz", + "integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", @@ -6477,6 +6504,21 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -7373,6 +7415,26 @@ "node": ">=0.4.0" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/fontfaceobserver": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", @@ -11863,6 +11925,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/psl": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", diff --git a/package.json b/package.json index 9e47516..3c10115 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@react-navigation/native": "^7.0.14", "@react-navigation/native-stack": "^7.2.0", "@react-navigation/stack": "^7.1.1", + "axios": "^1.8.3", "dayjs": "^1.11.13", "expo": "^52.0.24", "expo-asset": "^11.0.2",