@ -1,8 +0,0 @@
|
|||||||
export const AUTH = {
|
|
||||||
LOGIN: "/login",
|
|
||||||
REFRESH_TOKEN: "/refresh-token",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const EXERCICES = {
|
|
||||||
GETALL: "/exercices",
|
|
||||||
};
|
|
@ -0,0 +1,111 @@
|
|||||||
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { getItemAsync } from "expo-secure-store";
|
||||||
|
import apiClient from "./service.api.client";
|
||||||
|
import {
|
||||||
|
ACCESS_TOKEN_PATH,
|
||||||
|
API_URL,
|
||||||
|
CLIENT_ID,
|
||||||
|
CLIENT_SECRET,
|
||||||
|
ENDPOINTS,
|
||||||
|
REFRESH_TOKEN_PATH,
|
||||||
|
} from "./service.api.constant";
|
||||||
|
|
||||||
|
type RequestOption = {
|
||||||
|
method?: string;
|
||||||
|
body?: any;
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export abstract class AbstractServiceApi {
|
||||||
|
protected async request(path: string, options?: RequestOption): Promise<any> {
|
||||||
|
const token = await getItemAsync(ACCESS_TOKEN_PATH);
|
||||||
|
const headers = this.buildHeaders(token, options?.headers);
|
||||||
|
|
||||||
|
const fetchOptions: RequestInit = {
|
||||||
|
method: options?.method ?? "GET",
|
||||||
|
headers,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options?.body && fetchOptions.method !== "GET") {
|
||||||
|
fetchOptions.body = JSON.stringify(options.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(`${API_URL}${path}`, fetchOptions);
|
||||||
|
|
||||||
|
return await this.checkStatus(path, res, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildHeaders(
|
||||||
|
token?: string | null,
|
||||||
|
headers?: Record<string, string>
|
||||||
|
): Record<string, string> {
|
||||||
|
return {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(headers || {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkStatus(
|
||||||
|
path: string,
|
||||||
|
res: Response,
|
||||||
|
options?: RequestOption
|
||||||
|
): Promise<any> {
|
||||||
|
switch (res.status) {
|
||||||
|
case 401:
|
||||||
|
await this.tryRefreshToken();
|
||||||
|
return this.request(path, options);
|
||||||
|
case 403:
|
||||||
|
router.replace("/(error)/NotAllowedProblem");
|
||||||
|
return;
|
||||||
|
case 500:
|
||||||
|
router.replace("/(error)/InternalErrorProblem");
|
||||||
|
return;
|
||||||
|
case 503:
|
||||||
|
router.replace("/(error)/BlockedProblem");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async tryRefreshToken(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const refreshToken = await AsyncStorage.getItem(REFRESH_TOKEN_PATH);
|
||||||
|
|
||||||
|
if (!refreshToken) return false;
|
||||||
|
|
||||||
|
const response = await this.getRefreshTokenResponse(refreshToken);
|
||||||
|
|
||||||
|
if (!response.ok) return false;
|
||||||
|
|
||||||
|
const { accessToken, refreshToken: newRefreshToken } =
|
||||||
|
await response.json();
|
||||||
|
|
||||||
|
await AsyncStorage.setItem(ACCESS_TOKEN_PATH, accessToken);
|
||||||
|
await AsyncStorage.setItem(REFRESH_TOKEN_PATH, newRefreshToken);
|
||||||
|
|
||||||
|
apiClient.defaults.headers.common[
|
||||||
|
"Authorization"
|
||||||
|
] = `Bearer ${accessToken}`;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getRefreshTokenResponse(
|
||||||
|
refreshToken: string
|
||||||
|
): Promise<Response> {
|
||||||
|
return await fetch(`${API_URL}/${ENDPOINTS.REFRESH_TOKEN}`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ refresh_token: refreshToken }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
import { ESearchExerciceFilter } from "@/enum/enum.search-filter.exercice";
|
||||||
|
import { UpdateExerciceDTO } from "../dto/dto.catalog";
|
||||||
|
import { DeleteDTO } from "../dto/dto.generic";
|
||||||
|
import { ExerciceDTO } from "../dto/dto.training";
|
||||||
|
import { ICatalogService } from "../interface/service.interface.catalog";
|
||||||
|
import { AbstractServiceApi } from "./service.api.abstract";
|
||||||
|
import { ENDPOINTS } from "./service.api.constant";
|
||||||
|
|
||||||
|
export class CatalogServiceApi
|
||||||
|
extends AbstractServiceApi
|
||||||
|
implements ICatalogService
|
||||||
|
{
|
||||||
|
async getAllExercices(): Promise<ExerciceDTO[]> {
|
||||||
|
const data = await this.request(ENDPOINTS.CATALOG);
|
||||||
|
return data as ExerciceDTO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getExercices(spec: ESearchExerciceFilter): Promise<ExerciceDTO[]> {
|
||||||
|
const param = new URLSearchParams({ spec: spec });
|
||||||
|
const data = await this.request(`${ENDPOINTS.CATALOG}?${param}`);
|
||||||
|
return data as ExerciceDTO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getExercice(id: string): Promise<ExerciceDTO | undefined> {
|
||||||
|
const param = new URLSearchParams({ id });
|
||||||
|
const data = await this.request(`${ENDPOINTS.CATALOG}?${param}`);
|
||||||
|
return data as ExerciceDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addExercice(exercice: ExerciceDTO): Promise<ExerciceDTO> {
|
||||||
|
const data = await this.request(ENDPOINTS.CATALOG, {
|
||||||
|
method: "POST",
|
||||||
|
body: exercice,
|
||||||
|
});
|
||||||
|
return data as ExerciceDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
async editExercice(
|
||||||
|
id: string,
|
||||||
|
exercice: UpdateExerciceDTO
|
||||||
|
): Promise<UpdateExerciceDTO | undefined> {
|
||||||
|
const param = new URLSearchParams({ id: id });
|
||||||
|
const data = await this.request(`${ENDPOINTS.CATALOG}?${param}`, {
|
||||||
|
method: "PUT",
|
||||||
|
body: exercice,
|
||||||
|
});
|
||||||
|
return data as UpdateExerciceDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteExercice(id: string): Promise<DeleteDTO> {
|
||||||
|
const param = new URLSearchParams({ id: id });
|
||||||
|
const data = await this.request(`${ENDPOINTS.CATALOG}?${param}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
});
|
||||||
|
return data as DeleteDTO;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
export const IDP_URL =
|
||||||
|
"https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1";
|
||||||
|
export const API_URL =
|
||||||
|
"https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1";
|
||||||
|
|
||||||
|
export const CLIENT_ID = "mobile-app";
|
||||||
|
export const CLIENT_SECRET = "super-secret";
|
||||||
|
|
||||||
|
export const SCOPES =
|
||||||
|
"openid profile training.generate training.read offline_access";
|
||||||
|
|
||||||
|
export const ACCESS_TOKEN_PATH = "access-token";
|
||||||
|
export const REFRESH_TOKEN_PATH = "refresh-token";
|
||||||
|
|
||||||
|
export const ENDPOINTS = {
|
||||||
|
// User
|
||||||
|
LOGIN: "/login",
|
||||||
|
REFRESH_TOKEN: "/refresh-token",
|
||||||
|
|
||||||
|
// Exercice
|
||||||
|
CATALOG: "/exercices",
|
||||||
|
|
||||||
|
// Training
|
||||||
|
TRAINING: "/trainings",
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EndpointType = keyof typeof ENDPOINTS;
|
@ -0,0 +1,44 @@
|
|||||||
|
import { ESearchTrainingFilter } from "@/enum/enum.search-filter.training";
|
||||||
|
import {
|
||||||
|
ExerciceDTO,
|
||||||
|
SessionDTO,
|
||||||
|
TrainingDTO,
|
||||||
|
UpdateTrainingDTO,
|
||||||
|
} from "../dto/dto.training";
|
||||||
|
import { ITrainingService } from "../interface/service.interface.training";
|
||||||
|
import { AbstractServiceApi } from "./service.api.abstract";
|
||||||
|
|
||||||
|
export class TrainingServiceApi
|
||||||
|
extends AbstractServiceApi
|
||||||
|
implements ITrainingService
|
||||||
|
{
|
||||||
|
getAllTrainings(): Promise<TrainingDTO[]> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getTrainings(spec: ESearchTrainingFilter): Promise<TrainingDTO[]> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getTraining(id: string): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getSession(id: string): Promise<SessionDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getExercice(id: string): Promise<ExerciceDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
createTraining(training: TrainingDTO): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
editTraining(
|
||||||
|
training: UpdateTrainingDTO
|
||||||
|
): Promise<UpdateTrainingDTO> | undefined {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
duplicateTraining(id: string): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
deleteTraining(id: string): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import { User } from "@/model/User";
|
import { User } from "@/model/User";
|
||||||
import { setItemAsync } from "expo-secure-store";
|
import { setItemAsync } from "expo-secure-store";
|
||||||
import { AbstractService as AbstractAPIService } from "../abstract.service";
|
import { IUserService } from "../interface/service.interface.user";
|
||||||
import { IUserService } from "./user.service.interface";
|
import { AbstractServiceApi } from "./service.api.abstract";
|
||||||
|
|
||||||
export class UserAPIService extends AbstractAPIService implements IUserService {
|
export class UserServiceApi extends AbstractServiceApi implements IUserService {
|
||||||
async login(email: string, password: string): Promise<User> {
|
async login(email: string, password: string): Promise<User> {
|
||||||
const body = new URLSearchParams({
|
const body = new URLSearchParams({
|
||||||
grant_type: "password",
|
grant_type: "password",
|
@ -0,0 +1,19 @@
|
|||||||
|
import { ETarget } from "@/enum/enum.target";
|
||||||
|
|
||||||
|
export type ExerciceTemplateDTO = {
|
||||||
|
Id: string;
|
||||||
|
Name: string;
|
||||||
|
Description: string;
|
||||||
|
Target: ETarget;
|
||||||
|
Image: string;
|
||||||
|
Video: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateExerciceDTO = {
|
||||||
|
Id: string;
|
||||||
|
Name?: string;
|
||||||
|
Description?: string;
|
||||||
|
Target?: ETarget;
|
||||||
|
Image?: string;
|
||||||
|
Video?: string;
|
||||||
|
};
|
@ -0,0 +1,3 @@
|
|||||||
|
export type DeleteDTO = {
|
||||||
|
Id: string;
|
||||||
|
};
|
@ -0,0 +1,54 @@
|
|||||||
|
import { ECategory } from "@/enum/enum.category";
|
||||||
|
import { ETarget } from "@/enum/enum.target";
|
||||||
|
|
||||||
|
export type ExerciceDTO = {
|
||||||
|
Id: string;
|
||||||
|
Name: string;
|
||||||
|
Description: string;
|
||||||
|
Target: ETarget;
|
||||||
|
Image: string;
|
||||||
|
Video: string;
|
||||||
|
Duration: number;
|
||||||
|
NbSet: number;
|
||||||
|
RestTime: number;
|
||||||
|
NbRep: number;
|
||||||
|
Weight?: number;
|
||||||
|
Passed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SessionDTO = {
|
||||||
|
Id: string;
|
||||||
|
Name: string;
|
||||||
|
Description: string;
|
||||||
|
Category: ECategory;
|
||||||
|
Exercices: ExerciceDTO[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TrainingDTO = {
|
||||||
|
Id: string;
|
||||||
|
Name: string;
|
||||||
|
Description: string;
|
||||||
|
Sessions: SessionDTO[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateSessionDTO = {
|
||||||
|
Name: string;
|
||||||
|
Description: string;
|
||||||
|
Category: ECategory;
|
||||||
|
Exercices: ExerciceDTO[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateTrainingDTO = {
|
||||||
|
Name: string;
|
||||||
|
description: string;
|
||||||
|
Category: ECategory;
|
||||||
|
Exercices: ExerciceDTO[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateTrainingDTO = {
|
||||||
|
Id: string;
|
||||||
|
Name?: string;
|
||||||
|
description?: string;
|
||||||
|
Category?: ECategory;
|
||||||
|
Exercices?: ExerciceDTO[];
|
||||||
|
};
|
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
EHealthProblem,
|
||||||
|
ESleepLevel,
|
||||||
|
ESport,
|
||||||
|
ESportLevel,
|
||||||
|
} from "@/model/enums/Enums";
|
||||||
|
|
||||||
|
export type UserDTO = {
|
||||||
|
Name: string;
|
||||||
|
Age: number;
|
||||||
|
Weight: number;
|
||||||
|
Height: number;
|
||||||
|
Sexe: boolean; // true = Male, false = Female
|
||||||
|
ProfilePict: string;
|
||||||
|
NbSessionPerWeek: number;
|
||||||
|
Goal: string;
|
||||||
|
SleepLevel: ESleepLevel;
|
||||||
|
SportLevel: ESportLevel;
|
||||||
|
Sport: ESport[];
|
||||||
|
HealthProblems: EHealthProblem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateUserDTO = {
|
||||||
|
Id?: string;
|
||||||
|
Name?: string;
|
||||||
|
Age?: number;
|
||||||
|
Weight?: number;
|
||||||
|
Height?: number;
|
||||||
|
Sexe?: boolean; // true = Male, false = Female
|
||||||
|
ProfilePict?: string;
|
||||||
|
NbSessionPerWeek?: number;
|
||||||
|
Goal?: string;
|
||||||
|
SleepLevel?: ESleepLevel;
|
||||||
|
SportLevel?: ESportLevel;
|
||||||
|
Sport?: ESport[];
|
||||||
|
HealthProblems?: EHealthProblem[];
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
import { ESearchExerciceFilter } from "@/enum/enum.search-filter.exercice";
|
||||||
|
import { UpdateExerciceDTO } from "../dto/dto.catalog";
|
||||||
|
import { DeleteDTO } from "../dto/dto.generic";
|
||||||
|
import { ExerciceDTO } from "../dto/dto.training";
|
||||||
|
|
||||||
|
export interface ICatalogService {
|
||||||
|
getAllExercices(): Promise<ExerciceDTO[]>;
|
||||||
|
getExercices(spec: ESearchExerciceFilter): Promise<ExerciceDTO[]>;
|
||||||
|
getExercice(id: string): Promise<ExerciceDTO | undefined>;
|
||||||
|
addExercice(exercice: ExerciceDTO): Promise<ExerciceDTO>;
|
||||||
|
editExercice(
|
||||||
|
id: string,
|
||||||
|
exercice: UpdateExerciceDTO
|
||||||
|
): Promise<UpdateExerciceDTO | undefined>;
|
||||||
|
deleteExercice(id: string): Promise<DeleteDTO>;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { ESearchTrainingFilter } from "@/enum/enum.search-filter.training";
|
||||||
|
import {
|
||||||
|
ExerciceDTO,
|
||||||
|
SessionDTO,
|
||||||
|
TrainingDTO,
|
||||||
|
UpdateTrainingDTO,
|
||||||
|
} from "../dto/dto.training";
|
||||||
|
|
||||||
|
export interface ITrainingService {
|
||||||
|
getAllTrainings(): Promise<TrainingDTO[]>;
|
||||||
|
getTrainings(spec: ESearchTrainingFilter): Promise<TrainingDTO[]>;
|
||||||
|
getTraining(id: string): Promise<TrainingDTO | undefined>;
|
||||||
|
getSession(id: string): Promise<SessionDTO | undefined>;
|
||||||
|
getExercice(id: string): Promise<ExerciceDTO | undefined>;
|
||||||
|
createTraining(training: TrainingDTO): Promise<TrainingDTO | undefined>;
|
||||||
|
editTraining(
|
||||||
|
training: UpdateTrainingDTO
|
||||||
|
): Promise<UpdateTrainingDTO> | undefined;
|
||||||
|
duplicateTraining(id: string): Promise<TrainingDTO | undefined>;
|
||||||
|
deleteTraining(id: string): Promise<TrainingDTO | undefined>;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { ICatalogService } from "./interface/service.interface.catalog";
|
||||||
|
import { ITrainingService } from "./interface/service.interface.training";
|
||||||
|
import { IUserService } from "./interface/service.interface.user";
|
||||||
|
import { CatalogServiceStub } from "./stub/service.stub.catalog";
|
||||||
|
import { TrainingServiceStub } from "./stub/service.stub.training";
|
||||||
|
import { UserServiceStub } from "./stub/service.stub.user";
|
||||||
|
|
||||||
|
export const CatalogServiceRef: ICatalogService = new CatalogServiceStub();
|
||||||
|
export const UserServiceRef: IUserService = new UserServiceStub();
|
||||||
|
export const TrainingServiceRef: ITrainingService = new TrainingServiceStub();
|
@ -0,0 +1,120 @@
|
|||||||
|
import { ESearchExerciceFilter } from "@/enum/enum.search-filter.exercice";
|
||||||
|
import { AbstractServiceApi } from "../api/service.api.abstract";
|
||||||
|
import { UpdateExerciceDTO } from "../dto/dto.catalog";
|
||||||
|
import { DeleteDTO } from "../dto/dto.generic";
|
||||||
|
import { ExerciceDTO } from "../dto/dto.training";
|
||||||
|
import { ICatalogService } from "../interface/service.interface.catalog";
|
||||||
|
|
||||||
|
export class CatalogServiceStub
|
||||||
|
extends AbstractServiceApi
|
||||||
|
implements ICatalogService
|
||||||
|
{
|
||||||
|
exercices: ExerciceDTO[] = [
|
||||||
|
{
|
||||||
|
Id: "1",
|
||||||
|
Name: "Pompes",
|
||||||
|
Description:
|
||||||
|
"Exercice classique de renforcement des pectoraux et triceps.",
|
||||||
|
Duration: 60,
|
||||||
|
Image: "https://example.com/images/pompes.jpg",
|
||||||
|
Video: "https://example.com/videos/pompes.mp4",
|
||||||
|
NbSet: 3,
|
||||||
|
NbRep: 15,
|
||||||
|
Target: "ARM",
|
||||||
|
RestTime: 0,
|
||||||
|
Passed: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "2",
|
||||||
|
Name: "Squats",
|
||||||
|
Description: "Travail les jambes, les fessiers et le tronc.",
|
||||||
|
Duration: 90,
|
||||||
|
Image: "https://example.com/images/squats.jpg",
|
||||||
|
Video: "https://example.com/videos/squats.mp4",
|
||||||
|
NbSet: 4,
|
||||||
|
NbRep: 20,
|
||||||
|
Target: "LEG",
|
||||||
|
RestTime: 0,
|
||||||
|
Passed: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "3",
|
||||||
|
Name: "Gainage",
|
||||||
|
Description: "Renforcement du tronc, gainage statique.",
|
||||||
|
Duration: 45,
|
||||||
|
Image: "https://example.com/images/gainage.jpg",
|
||||||
|
Video: "https://example.com/videos/gainage.mp4",
|
||||||
|
NbSet: 3,
|
||||||
|
NbRep: 1,
|
||||||
|
Target: "CARDIO",
|
||||||
|
RestTime: 0,
|
||||||
|
Passed: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "4",
|
||||||
|
Name: "Fentes",
|
||||||
|
Description: "Renforcement des jambes, bon pour l'équilibre.",
|
||||||
|
Duration: 80,
|
||||||
|
Image: "https://example.com/images/fentes.jpg",
|
||||||
|
Video: "https://example.com/videos/fentes.mp4",
|
||||||
|
NbSet: 3,
|
||||||
|
NbRep: 12,
|
||||||
|
Target: "LEG",
|
||||||
|
RestTime: 0,
|
||||||
|
Passed: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "5",
|
||||||
|
Name: "Abdominaux",
|
||||||
|
Description: "Travail des muscles abdominaux avec crunchs.",
|
||||||
|
Duration: 60,
|
||||||
|
Image: "https://example.com/images/abdos.jpg",
|
||||||
|
Video: "https://example.com/videos/abdos.mp4",
|
||||||
|
NbSet: 4,
|
||||||
|
NbRep: 20,
|
||||||
|
Target: "ARM",
|
||||||
|
RestTime: 0,
|
||||||
|
Passed: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
getAllExercices(): Promise<ExerciceDTO[]> {
|
||||||
|
return Promise.resolve(this.exercices);
|
||||||
|
}
|
||||||
|
|
||||||
|
getExercices(spec: ESearchExerciceFilter): Promise<ExerciceDTO[]> {
|
||||||
|
return Promise.resolve(this.exercices);
|
||||||
|
}
|
||||||
|
|
||||||
|
getExercice(id: string): Promise<ExerciceDTO | undefined> {
|
||||||
|
return Promise.resolve(this.exercices.find((x) => x.Id === id));
|
||||||
|
}
|
||||||
|
|
||||||
|
addExercice(exercice: ExerciceDTO): Promise<ExerciceDTO> {
|
||||||
|
this.exercices.push(exercice);
|
||||||
|
return Promise.resolve(exercice);
|
||||||
|
}
|
||||||
|
|
||||||
|
editExercice(
|
||||||
|
id: string,
|
||||||
|
exercice: UpdateExerciceDTO
|
||||||
|
): Promise<UpdateExerciceDTO | undefined> {
|
||||||
|
const ex = this.exercices.find((x) => x.Id === id);
|
||||||
|
if (ex != null) {
|
||||||
|
Object.entries(exercice).forEach(([key, value]) => {
|
||||||
|
if (value !== undefined) {
|
||||||
|
// @ts-ignore : typage des clés non dynamique
|
||||||
|
ex[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteExercice(id: string): Promise<DeleteDTO> {
|
||||||
|
const dto: DeleteDTO = {
|
||||||
|
Id: id,
|
||||||
|
};
|
||||||
|
return Promise.resolve(dto);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { ESearchTrainingFilter } from "@/enum/enum.search-filter.training";
|
||||||
|
import {
|
||||||
|
ExerciceDTO,
|
||||||
|
SessionDTO,
|
||||||
|
TrainingDTO,
|
||||||
|
UpdateTrainingDTO,
|
||||||
|
} from "../dto/dto.training";
|
||||||
|
import { ITrainingService } from "../interface/service.interface.training";
|
||||||
|
|
||||||
|
export class TrainingServiceStub implements ITrainingService {
|
||||||
|
getAllTrainings(): Promise<TrainingDTO[]> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getTrainings(spec: ESearchTrainingFilter): Promise<TrainingDTO[]> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getTraining(id: string): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getSession(id: string): Promise<SessionDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getExercice(id: string): Promise<ExerciceDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
createTraining(training: TrainingDTO): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
editTraining(
|
||||||
|
training: UpdateTrainingDTO
|
||||||
|
): Promise<UpdateTrainingDTO> | undefined {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
duplicateTraining(id: string): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
deleteTraining(id: string): Promise<TrainingDTO | undefined> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
}
|
@ -1,77 +0,0 @@
|
|||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
||||||
import { router } from "expo-router";
|
|
||||||
import { getItemAsync } from "expo-secure-store";
|
|
||||||
import apiClient from "../client";
|
|
||||||
import { AUTH } from "../endpoints";
|
|
||||||
|
|
||||||
export abstract class AbstractService {
|
|
||||||
protected IDP_URL =
|
|
||||||
"https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1";
|
|
||||||
protected URL =
|
|
||||||
"https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1";
|
|
||||||
|
|
||||||
protected CLIENT_ID = "mobile-app";
|
|
||||||
protected CLIENT_SECRET = "super-secret";
|
|
||||||
|
|
||||||
protected SCOPES =
|
|
||||||
"openid profile training.generate training.read offline_access";
|
|
||||||
|
|
||||||
protected ACCESS_TOKEN_PATH = "access-token";
|
|
||||||
protected REFRESH_TOKEN_PATH = "refresh-token";
|
|
||||||
|
|
||||||
protected async request(
|
|
||||||
path: string,
|
|
||||||
options: RequestInit = {}
|
|
||||||
): Promise<any> {
|
|
||||||
const token = await getItemAsync(this.ACCESS_TOKEN_PATH);
|
|
||||||
const res = await fetch(`${this.URL}${path}`, {
|
|
||||||
...options,
|
|
||||||
headers: {
|
|
||||||
...(options.headers || {}),
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (res.status) {
|
|
||||||
case 401:
|
|
||||||
await this.tryRefreshToken();
|
|
||||||
return this.request(path, options);
|
|
||||||
case 403:
|
|
||||||
router.replace("/(error)/NotAllowedProblem");
|
|
||||||
return;
|
|
||||||
case 500:
|
|
||||||
router.replace("/(error)/InternalErrorProblem");
|
|
||||||
return;
|
|
||||||
case 503:
|
|
||||||
router.replace("/(error)/BlockedProblem");
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async tryRefreshToken(): Promise<boolean> {
|
|
||||||
try {
|
|
||||||
const refreshToken = await AsyncStorage.getItem(this.REFRESH_TOKEN_PATH);
|
|
||||||
|
|
||||||
if (!refreshToken) return false;
|
|
||||||
|
|
||||||
const response = await apiClient.post(AUTH.REFRESH_TOKEN, {
|
|
||||||
refreshToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { accessToken, refreshToken: newRefreshToken } = response.data;
|
|
||||||
|
|
||||||
await AsyncStorage.setItem(this.ACCESS_TOKEN_PATH, accessToken);
|
|
||||||
await AsyncStorage.setItem(this.REFRESH_TOKEN_PATH, newRefreshToken);
|
|
||||||
|
|
||||||
apiClient.defaults.headers.common[
|
|
||||||
"Authorization"
|
|
||||||
] = `Bearer ${accessToken}`;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { EXERCICES } from "@/api/endpoints";
|
|
||||||
import { Workout } from "@/model/Workout";
|
|
||||||
import { AbstractService } from "../abstract.service";
|
|
||||||
import { IExerciceService } from "./exercice.service.interface";
|
|
||||||
|
|
||||||
export class ExerciceAPIService
|
|
||||||
extends AbstractService
|
|
||||||
implements IExerciceService
|
|
||||||
{
|
|
||||||
async getExercices(): Promise<Workout[]> {
|
|
||||||
const data = await this.request(EXERCICES.GETALL);
|
|
||||||
return data.data.map((item: any) => Workout.fromJson(item));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export interface IExerciceService {
|
|
||||||
getExercices(): Promise<any>;
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import { IExerciceService } from "./exercice/exercice.service.interface";
|
|
||||||
import { ExerciceStubService } from "./exercice/exercice.service.stub";
|
|
||||||
import { IUserService } from "./user/user.service.interface";
|
|
||||||
import { UserStubService } from "./user/user.service.stub";
|
|
||||||
|
|
||||||
export const ExerciceServiceRef: IExerciceService = new ExerciceStubService();
|
|
||||||
export const UserServiceRef: IUserService = new UserStubService();
|
|
@ -0,0 +1,10 @@
|
|||||||
|
export const ECategory = {
|
||||||
|
WARM_UP: "WARM_UP",
|
||||||
|
TRAINING: "TRAINING",
|
||||||
|
STRETCHING: "STRETCHING",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ECategory = keyof typeof ECategory;
|
||||||
|
|
||||||
|
export const Categories: ECategory[] = Object.values(ECategory);
|
@ -0,0 +1,12 @@
|
|||||||
|
export const EGoal = {
|
||||||
|
WEIGHT_LOSS: "WEIGHT_LOSS",
|
||||||
|
MASS_GAIN: "MASS_GAIN",
|
||||||
|
FITNESS: "FITNESS",
|
||||||
|
IMPROVE_STAMINA: "IMPROVE_STAMINA",
|
||||||
|
KEEP_FIT: "KEEP_FIT",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type EGoal = keyof typeof EGoal;
|
||||||
|
|
||||||
|
export const Goals: EGoal[] = Object.values(EGoal);
|
@ -0,0 +1,9 @@
|
|||||||
|
export const EHealthProblem = {
|
||||||
|
ARTHROSE: "ARTHROSE",
|
||||||
|
MIGRAINE: "MIGRAINE",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type EHealthProblem = keyof typeof EHealthProblem;
|
||||||
|
|
||||||
|
export const HealthProblems: EHealthProblem[] = Object.values(EHealthProblem);
|
@ -0,0 +1,11 @@
|
|||||||
|
export const ESearchExerciceFilter = {
|
||||||
|
NAME: "NAME",
|
||||||
|
TARGET: "TARGET",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ESearchExerciceFilter = keyof typeof ESearchExerciceFilter;
|
||||||
|
|
||||||
|
export const searchExerciceFilters: ESearchExerciceFilter[] = Object.values(
|
||||||
|
ESearchExerciceFilter
|
||||||
|
);
|
@ -0,0 +1,12 @@
|
|||||||
|
export const ESearchTrainingFilter = {
|
||||||
|
NAME: "NAME",
|
||||||
|
DATE: "DATE",
|
||||||
|
DESCRIPTION: "DESCRIPTION",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ESearchTrainingFilter = keyof typeof ESearchTrainingFilter;
|
||||||
|
|
||||||
|
export const SearchTrainingFilters: ESearchTrainingFilter[] = Object.values(
|
||||||
|
ESearchTrainingFilter
|
||||||
|
);
|
@ -0,0 +1,12 @@
|
|||||||
|
export const ESleepLevel = {
|
||||||
|
EXCELLENT: "EXCELLENT",
|
||||||
|
GOOD: "GOOD",
|
||||||
|
BAD: "BAD",
|
||||||
|
VERY_BAD: "VERY_BAD",
|
||||||
|
TERRIBLE: "TERRIBLE",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ESleepLevel = keyof typeof ESleepLevel;
|
||||||
|
|
||||||
|
export const SleepLevels: ESleepLevel[] = Object.values(ESleepLevel);
|
@ -0,0 +1,11 @@
|
|||||||
|
export const ESportLevel = {
|
||||||
|
VERY_SPORTY: "VERY_SPORTY",
|
||||||
|
SPORTY: "SPORTY",
|
||||||
|
BEGINNER: "BEGINNER",
|
||||||
|
NOT_SPORTY: "NOT_SPORTY",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ESportLevel = keyof typeof ESportLevel;
|
||||||
|
|
||||||
|
export const SportLevels: ESportLevel[] = Object.values(ESportLevel);
|
@ -0,0 +1,17 @@
|
|||||||
|
export const Esport = {
|
||||||
|
FOOTBALL: "FOOTBALL",
|
||||||
|
BASKETBALL: "BASKETBALL",
|
||||||
|
HANDBALL: "HANDBALL",
|
||||||
|
TENNIS: "TENNIS",
|
||||||
|
WALKING: "WALKING",
|
||||||
|
RUNNING: "RUNNING",
|
||||||
|
SKATEBOARD: "SKATEBOARD",
|
||||||
|
BIKING: "BIKING",
|
||||||
|
YOGA: "YOGA",
|
||||||
|
ELSE: "ELSE",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ESport = keyof typeof Esport;
|
||||||
|
|
||||||
|
export const Sports: ESport[] = Object.values(Esport);
|
@ -0,0 +1,11 @@
|
|||||||
|
export const ETarget = {
|
||||||
|
LEG: "LEG",
|
||||||
|
ARM: "ARM",
|
||||||
|
CARDIO: "CARDIO",
|
||||||
|
BACK: "BACK",
|
||||||
|
NONE: "NONE",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ETarget = keyof typeof ETarget;
|
||||||
|
|
||||||
|
export const Target: ETarget[] = Object.values(ETarget);
|
@ -1,118 +0,0 @@
|
|||||||
export class Workout {
|
|
||||||
private _id?: string;
|
|
||||||
private _name?: string;
|
|
||||||
private _description?: string;
|
|
||||||
private _duration?: number;
|
|
||||||
private _image?: string;
|
|
||||||
private _video?: string;
|
|
||||||
private _nbSeries?: number;
|
|
||||||
private _nbRepetitions?: number;
|
|
||||||
|
|
||||||
constructor({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
duration,
|
|
||||||
image,
|
|
||||||
video,
|
|
||||||
nbSeries,
|
|
||||||
nbRepetitions,
|
|
||||||
}: {
|
|
||||||
id?: string;
|
|
||||||
name?: string;
|
|
||||||
description?: string;
|
|
||||||
duration?: number;
|
|
||||||
image?: string;
|
|
||||||
video?: string;
|
|
||||||
nbSeries?: number;
|
|
||||||
nbRepetitions?: number;
|
|
||||||
} = {}) {
|
|
||||||
this._id = id;
|
|
||||||
this._name = name;
|
|
||||||
this._description = description;
|
|
||||||
this._duration = duration;
|
|
||||||
this._image = image;
|
|
||||||
this._video = video;
|
|
||||||
this._nbSeries = nbSeries;
|
|
||||||
this._nbRepetitions = nbRepetitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
get id(): string | undefined {
|
|
||||||
return this._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name(): string | undefined {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get description(): string | undefined {
|
|
||||||
return this._description;
|
|
||||||
}
|
|
||||||
|
|
||||||
get duration(): number | undefined {
|
|
||||||
return this._duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
get image(): string | undefined {
|
|
||||||
return this._image;
|
|
||||||
}
|
|
||||||
|
|
||||||
get video(): string | undefined {
|
|
||||||
return this._video;
|
|
||||||
}
|
|
||||||
|
|
||||||
get nbSeries(): number | undefined {
|
|
||||||
return this._nbSeries;
|
|
||||||
}
|
|
||||||
|
|
||||||
get nbRepetitions(): number | undefined {
|
|
||||||
return this._nbRepetitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setters
|
|
||||||
set id(value: string | undefined) {
|
|
||||||
this._id = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set name(value: string | undefined) {
|
|
||||||
this._name = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set description(value: string | undefined) {
|
|
||||||
this._description = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set duration(value: number | undefined) {
|
|
||||||
this._duration = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set image(value: string | undefined) {
|
|
||||||
this._image = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set video(value: string | undefined) {
|
|
||||||
this._video = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set nbSeries(value: number | undefined) {
|
|
||||||
this._nbSeries = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set nbRepetitions(value: number | undefined) {
|
|
||||||
this._nbRepetitions = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromJson(json: any): Workout {
|
|
||||||
return new Workout({
|
|
||||||
id: json.id,
|
|
||||||
name: json.name,
|
|
||||||
description: json.description,
|
|
||||||
duration: json.duration,
|
|
||||||
image: json.image,
|
|
||||||
video: json.video,
|
|
||||||
nbSeries: json.nbSeries,
|
|
||||||
nbRepetitions: json.nbRepetitions,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
export const Goals = [
|
|
||||||
"WEIGHT_LOSE",
|
|
||||||
"IMPROVE_MUSCLE",
|
|
||||||
"WEIGHT_GAIN",
|
|
||||||
"IMPROVE_STAMINA",
|
|
||||||
"KEEP_FIT",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export const SportLevels = [
|
|
||||||
"NOT_SPORTY",
|
|
||||||
"BEGINNER",
|
|
||||||
"SPORTY",
|
|
||||||
"VERY_SPORTY",
|
|
||||||
"PERFORMER",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export const Sports = [
|
|
||||||
"RUNNING",
|
|
||||||
"WALKING",
|
|
||||||
"RANDO",
|
|
||||||
"SKATEBOARD",
|
|
||||||
"BIKING",
|
|
||||||
"BASKETBALL",
|
|
||||||
"CARDIO",
|
|
||||||
"YOGA",
|
|
||||||
"ELSE",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export const SleepLevels = [
|
|
||||||
"TERRIBLE",
|
|
||||||
"VERY_BAD",
|
|
||||||
"BAD",
|
|
||||||
"GOOD",
|
|
||||||
"EXCELLENT",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export type EGoal = (typeof Goals)[number];
|
|
||||||
export type ESportLevel = (typeof SportLevels)[number];
|
|
||||||
export type ESport = (typeof Sports)[number];
|
|
||||||
export type ESleepLevel = (typeof SleepLevels)[number];
|
|
||||||
|
|
||||||
export type EHealthProblem = "ARTHROSE" | "MIGRAINE";
|
|
Loading…
Reference in new issue