add store for API connection :spakles:

pull/14/head
Tony Fages 4 weeks ago committed by Anthony RICHARD
parent 10edfba92b
commit 3993466b4d

@ -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;

@ -0,0 +1,5 @@
export const EXERCICES = {
GETALL: '/exercices',
}

@ -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;
}
};

@ -1,47 +1,54 @@
import {FlatList, SafeAreaView, Text, View} from "react-native"; import React, { useEffect, useState } from 'react';
import React from "react"; import { FlatList, Text, TouchableOpacity, View } from 'react-native';
import HeaderProfileComponent from "@/components/HeaderProfileComponent"; import { getExercices } from "@/api/services/ExercicesServices";
import Screen from "@/components/ui/Screen"; import { useRouter } from "expo-router";
import { Workout } from "@/model/Workout";
import WorkoutCardComponent from "@/components/WorkoutCardComponent"; 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() { export default function ExercicesScreen() {
const [text, onChangeText] = React.useState(""); const [exercices, setExercices] = useState<Workout[]>([]);
const exercise = [new Workout("Développé couché", 25,"8 Series Workout", 412, "assets/images/Sigma-2.png","Intense" ), const [loading, setLoading] = useState(true);
new Workout("Curl halterné", 30, "8 Series Workout", 342, "assets/images/Sigma.jpg","Medium" ), const [error, setError] = useState(null);
new Workout("Tirage Vertival", 29, "8 Series Workout", 793, "assets/images/Sigma.jpg","Easy" )]; const router = useRouter();
return ( useEffect(() => {
<View className="h-full p-2 mt-11"> const fetchData = async () => {
try {
<FlatList const data = await getExercices();
ListHeaderComponent={ setExercices(data);
<> } catch (err: any) {
<View className=""> setError(err.message);
<HeaderProfileComponent/> } finally {
</View> setLoading(false);
<View className="mt-4">
<View className="flex-row justify-between items-center mb-4">
<Text className="text-lg font-bold text-black">Séance du jour</Text>
</View>
</View>
</>
} }
data={exercise} };
className="h-full"
renderItem={({ item }: { item: Workout }) =>
<View className="mt-2 h-52"> fetchData();
<WorkoutCardComponent exercise={item}/> }, []);
</View>
} if (loading) {
/> return <Text className="text-white">Chargement...</Text>;
}
</View> if (error) {
return <Text className="text-red-500">Erreur : {error}</Text>;
}
return (
<View className="p-4">
<FlatList
data={exercices}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<TouchableOpacity
className="p-4 mb-2 bg-gray-800 rounded-lg"
onPress={() => router.push({ pathname: "/WorkoutScreen", params: { workout: JSON.stringify(item) } })}
>
<WorkoutCardComponent exercise={item} background={"black"} />
</TouchableOpacity>
)}
/>
</View>
); );
} }

@ -1,23 +1,53 @@
import * as React from 'react';
import LinearTimer from 'react-native-linear-timer'; import React, { useEffect, useState } from 'react';
import {Button, Image, ImageBackground, SafeAreaView, Text, TouchableOpacity, View} from "react-native"; import { View, ActivityIndicator, Text } from 'react-native';
import Screen from "@/components/ui/Screen"; import { useRouter } from 'expo-router';
import {Background} from "@react-navigation/elements";
import {AntDesign} from "@expo/vector-icons";
import {router, useRouter} from "expo-router";
import WelcomeComponent from "@/components/WelcomeComponent";
import WorkoutPresentationComponent from "@/components/WorkoutPresentationComponent"; 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(); useEffect(() => {
return ( const loadExercices = async () => {
try {
const data = await getExercices();
setExercices(data);
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
};
loadExercices();
}, []);
<View className=" h-full rounded-2xl "> if (loading) {
<WorkoutPresentationComponent/> return (
<View className="flex-1 justify-center items-center bg-black">
<ActivityIndicator size="large" color="#fff" />
</View> </View>
) );
}
if (error) {
return (
<View className="flex-1 justify-center items-center bg-black">
<Text className="text-red-500 text-xl">{error}</Text>
</View>
);
}
const workout = exercices[1]; // Choisis lexercice que tu souhaites afficher
} return (
<View className="h-full rounded-2xl">
<WorkoutPresentationComponent workout={workout} dataExercise={exercices} router={router} />
</View>
);
}

@ -1,15 +1,34 @@
import {SafeAreaView, ScrollView, Text, View} from "react-native"; import {SafeAreaView, ScrollView, Text, View} from "react-native";
import React from "react"; import React, {useEffect, useState} from "react";
import WorkoutCardComponent from "@/components/WorkoutCardComponent"; import WorkoutCardComponent from "@/components/WorkoutCardComponent";
import Screen from "@/components/ui/Screen"; import Screen from "@/components/ui/Screen";
import CalendarComponent from "@/components/CalendarComponent"; import CalendarComponent from "@/components/CalendarComponent";
import WelcomeComponent from "@/components/WelcomeComponent"; import WelcomeComponent from "@/components/WelcomeComponent";
import ActivitiesComponent from "@/components/ActivitiesComponent"; import ActivitiesComponent from "@/components/ActivitiesComponent";
import {Workout} from "@/model/Workout"; 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<Workout[]>([]);
export default function HomeScreen() { const getRandomNumber = (min: number, max: number) => {
const exercise = new Workout("Faire caca par terre", 25,"8 Series Workout", 412, "assets/images/Sigma-2.png","Intense" ); 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 ( return (
<ScrollView className="h-full "> <ScrollView className="h-full ">
@ -41,7 +60,7 @@ export default function HomeScreen() {
See All See All
</Text> </Text>
</View> </View>
<WorkoutCardComponent exercise={exercise} background="bg-black" /> <WorkoutCardComponent exercise={exercices[getRandomNumber(0,3)]} background="bg-black" />
</View> </View>
<View className="h-1/5 mt-8"> <View className="h-1/5 mt-8">

@ -5,7 +5,7 @@ import {Workout} from "@/model/Workout";
import {Link, useRouter} from "expo-router"; import {Link, useRouter} from "expo-router";
interface WorkoutCardComponentProps { interface WorkoutCardComponentProps {
exercise: Workout, exercise?: Workout,
background?: String, background?: String,
height?: number, height?: number,
@ -34,23 +34,23 @@ export default function WorkoutCardComponent({exercise, height, background}: Wor
<View className="flex-row justify-between p-4"> <View className="flex-row justify-between p-4">
<View className="flex-row space-x-4 h-44 items-top justify-center "> <View className="flex-row space-x-4 h-44 items-top justify-center ">
<View className="flex-row items-top"> <View className="flex-row items-top">
<Text className="text-white text-sm ml-1">{exercise.duration} min</Text> <Text className="text-white text-sm ml-1">{exercise?.duration} min</Text>
</View> </View>
<View className="flex-row justify-center"> <View className="flex-row justify-center">
<MaterialCommunityIcons name="square-rounded" size={8} color="white"/> <MaterialCommunityIcons name="square-rounded" size={8} color="white"/>
</View> </View>
<View className="flex-row"> <View className="flex-row">
<Text className="text-white text-sm ml-1">{exercise.calories} kcal</Text> <Text className="text-white text-sm ml-1">{exercise?.name} kcal</Text>
</View> </View>
</View> </View>
</View> </View>
<View className="absolute bottom-0 left-0 right-0 p-4 bg-opacity-50"> <View className="absolute bottom-0 left-0 right-0 p-4 bg-opacity-50">
<Text className="text-white text-lg font-bold">{exercise.name}</Text> <Text className="text-white text-lg font-bold">{exercise?.name}</Text>
<Text className="text-gray-300 text-sm">{exercise.repetitions}</Text> <Text className="text-gray-300 text-sm">{exercise?.nbRepetitions}</Text>
<View className="flex-row items-center mt-2"> <View className="flex-row items-center mt-2">
<Text className="text-white text-xs bg-gray-800 py-1 px-3 rounded-full"> <Text className="text-white text-xs bg-gray-800 py-1 px-3 rounded-full">
{exercise.level} {exercise?.name}
</Text> </Text>
</View> </View>
</View> </View>

@ -2,15 +2,19 @@ import {ImageBackground, TouchableOpacity, View, Text} from "react-native";
import Screen from "@/components/ui/Screen"; import Screen from "@/components/ui/Screen";
import * as React from "react"; import * as React from "react";
import {Ionicons} from "@expo/vector-icons"; import {Ionicons} from "@expo/vector-icons";
import {useRouter} from "expo-router"; import {Router, useRouter} from "expo-router";
import LinearProgressBar from "@/components/LinearProgressBar"; import LinearProgressBar from "@/components/LinearProgressBar";
import {Workout} from "@/model/Workout"; 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 ( return (
<ImageBackground className="h-full w-full" <ImageBackground className="h-full w-full"
source={require("assets/images/backgroundWourkout.jpg")}> source={require("assets/images/backgroundWourkout.jpg")}>
@ -30,14 +34,15 @@ export default function WorkoutPresentationComponent(workout: Workout, dataExerc
{/* Texte en bas */} {/* Texte en bas */}
<View className="items-center mb-10"> <View className="items-center mb-10">
<Text className="text-white bg-transparent border-2 border-white px-3 py-1 rounded-full text-2xl font-bold"> <Text className="text-white bg-transparent border-2 border-white px-3 py-1 rounded-full text-2xl font-bold">
Exercise 1 {workout.nbSeries} x {workout.nbRepetitions}
</Text> </Text>
<Text className="text-white text-4xl font-bold mt-2">Back Warmup</Text>
<Text className="text-white text-4xl font-bold mt-2">{workout.name}</Text>
</View> </View>
{/* Barre de progression */} {/* Barre de progression */}
<View className="mb-5"> <View className="mb-5">
<LinearProgressBar duration={12} /> <LinearProgressBar duration={workout.duration} />
</View> </View>
</View> </View>

@ -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 };
}

@ -1,43 +1,10 @@
export class Workout { export interface Workout {
id: string;
private _name: string name: string;
private _duration: number description: string;
private _calories: number duration: number;
private _repetitions: string image: string;
private _image: string video: string;
private _level: string nbSeries: number;
nbRepetitions: number;
}
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;
}
}

68
package-lock.json generated

@ -14,6 +14,7 @@
"@react-navigation/native": "^7.0.14", "@react-navigation/native": "^7.0.14",
"@react-navigation/native-stack": "^7.2.0", "@react-navigation/native-stack": "^7.2.0",
"@react-navigation/stack": "^7.1.1", "@react-navigation/stack": "^7.1.1",
"axios": "^1.8.3",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"expo": "^52.0.24", "expo": "^52.0.24",
"expo-asset": "^11.0.2", "expo-asset": "^11.0.2",
@ -4633,6 +4634,32 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/babel-core": {
"version": "7.0.0-bridge.0", "version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@ -6477,6 +6504,21 @@
"node": ">= 0.4" "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": { "node_modules/escalade": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@ -7373,6 +7415,26 @@
"node": ">=0.4.0" "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": { "node_modules/fontfaceobserver": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz",
@ -11863,6 +11925,12 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT" "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": { "node_modules/psl": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",

@ -21,6 +21,7 @@
"@react-navigation/native": "^7.0.14", "@react-navigation/native": "^7.0.14",
"@react-navigation/native-stack": "^7.2.0", "@react-navigation/native-stack": "^7.2.0",
"@react-navigation/stack": "^7.1.1", "@react-navigation/stack": "^7.1.1",
"axios": "^1.8.3",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"expo": "^52.0.24", "expo": "^52.0.24",
"expo-asset": "^11.0.2", "expo-asset": "^11.0.2",

Loading…
Cancel
Save