+ {isStarting ? (
+
Start
+ ) : (
+
Pas start
+ )}
+ {clicks.map((click, index) => (
+
+ ))}
+
+
+ {isStarting && !gameOver ? (
+ <>
+
+ >
+ ) : (
+ <>
+
+ >
+ )}
+
+ {gameOver && (
+
+ Bravo tu as été rapide ! Score : {score}
+
+ )}
+
+ );
+};
+
+export default RunnerGame;
diff --git a/client/src/components/map/FlamiLocation.tsx b/client/src/components/map/FlamiLocation.tsx
index 0b6a16c..9bf47b4 100644
--- a/client/src/components/map/FlamiLocation.tsx
+++ b/client/src/components/map/FlamiLocation.tsx
@@ -1,18 +1,22 @@
-const FlamiLocation = () => {
+const FlamiLocation = ({ location }: { location: {
+ ville: string;
+ dept: string;
+ region: string;
+} | undefined}) => {
return (
<>
setSide(!side)}>
-
-
+ const [side, setSide] = useState(false);
+ return (
+
setSide(!side)}
+ >
+
+
- );
+ );
};
-export default BadgeDisplay;
\ No newline at end of file
+export default BadgeDisplay;
diff --git a/client/src/components/topbar/TopBar.tsx b/client/src/components/topbar/TopBar.tsx
index e8e6fc3..27fbd4a 100644
--- a/client/src/components/topbar/TopBar.tsx
+++ b/client/src/components/topbar/TopBar.tsx
@@ -37,4 +37,4 @@ const TopBar = ({
);
};
-export default TopBar;
+export default TopBar;
\ No newline at end of file
diff --git a/client/src/interfaces/badge.interface.ts b/client/src/interfaces/badge.interface.ts
index b6cf489..e8fc0f4 100644
--- a/client/src/interfaces/badge.interface.ts
+++ b/client/src/interfaces/badge.interface.ts
@@ -1,8 +1,8 @@
export interface Badge {
- name: string;
- url: string;
- url_cover: string;
- description: string;
- region: string;
- }
-
\ No newline at end of file
+ name: string;
+ url: string;
+ url_cover: string;
+ description: string;
+ region: string;
+ owned?: boolean;
+}
\ No newline at end of file
diff --git a/client/src/interfaces/cosmetic.interface.ts b/client/src/interfaces/cosmetic.interface.ts
new file mode 100644
index 0000000..af5c1b2
--- /dev/null
+++ b/client/src/interfaces/cosmetic.interface.ts
@@ -0,0 +1,6 @@
+export interface Cosmetic {
+ name: string,
+ description: string;
+ url: string;
+ place: number;
+}
\ No newline at end of file
diff --git a/client/src/interfaces/flami.interface.ts b/client/src/interfaces/flami.interface.ts
new file mode 100644
index 0000000..3ceb7ac
--- /dev/null
+++ b/client/src/interfaces/flami.interface.ts
@@ -0,0 +1,21 @@
+import { Cosmetic } from "./cosmetic.interface"
+
+export interface Flami {
+ name: string,
+ owner: string,
+ cosmetics: Cosmetic[],
+ stamina: number,
+ stats: {
+ strength: number,
+ speed: number,
+ dexterity: number
+ },
+ location: {
+ lat: number,
+ long: number
+ },
+ last_action: Date,
+ last_share: string,
+ shared_flami: Flami | null,
+ _id: string
+}
\ No newline at end of file
diff --git a/client/src/pages/activities/TrainingPage.tsx b/client/src/pages/activities/TrainingPage.tsx
new file mode 100644
index 0000000..e355753
--- /dev/null
+++ b/client/src/pages/activities/TrainingPage.tsx
@@ -0,0 +1,11 @@
+import RunnerGame from "../../components/game/RunnerGame";
+
+const TrainingPage = () => {
+ return (
+ <>
+
+ >
+ );
+};
+
+export default TrainingPage;
diff --git a/client/src/pages/auth/WelcomePage.tsx b/client/src/pages/auth/WelcomePage.tsx
index 823da57..db0b2d4 100644
--- a/client/src/pages/auth/WelcomePage.tsx
+++ b/client/src/pages/auth/WelcomePage.tsx
@@ -1,7 +1,17 @@
import { Link } from "react-router-dom";
import { Button, LinkComponent } from "../../components/ui";
+import { usePwa } from "@dotmind/react-use-pwa";
+import { useCallback } from "react";
const WelcomePage = () => {
+ const { installPrompt, isInstalled, canInstall } = usePwa();
+
+ const handleInstallPrompt = useCallback(() => {
+ if (canInstall) {
+ installPrompt();
+ }
+ }, [canInstall, installPrompt]);
+
return (
@@ -16,7 +26,14 @@ const WelcomePage = () => {
Créer son compte
-
Télécharger l'application
+ {canInstall || !isInstalled ? (
+
+ Télécharger l'application
+
+ ) : (
+ ""
+ )}
+
Tu as deja un compte ?{" "}
{
- return
FlamiPage
;
-};
+ const { token } = useAuth();
+ const [flami, setFlami] = useState
();
+ const navigate = useNavigate();
+
+ const getFlami = useCallback(() => {
+ APIHandler("/my/flami", false, "GET", undefined, token).then(
+ (res) => {
+ setFlami(res.data);
+ }
+ );
+ }, [token]);
+
+ useEffect(() => {
+ getFlami();
+ }, [getFlami]);
+
+ console.log(flami?.last_share, new Date().toDateString());
+
+ return (
+
+
+
+
+
+
+ {
+ flami?.cosmetics.map((cosmetic: Cosmetic) => (
))
+ }
+
+ { flami?.shared_flami ?
+ (
+
{`Flami de ${flami.shared_flami.owner}`}
+
+ {
+ flami.shared_flami.cosmetics.map((cosmetic: Cosmetic) => (
))
+ }
+
)
+ : null }
+
+
navigate("/share")}>
+ Partager
+
+
+
+
+
Mes activités
+
+
navigate("/cosmetics")}
+ className="bg-alabaster-900 border-midnight-moss-300 border-3 shadow-midnight-300 flex flex-col items-center gap-2 rounded-xl hover:brightness-90 active:shadow-none active:translate-y-1"
+ >
+
+ Cosmétiques
+
+
navigate("/training")}
+ className="bg-alabaster-900 border-mahogany-300 border-3 shadow-mahogany-300 flex flex-col items-center gap-2 rounded-xl hover:brightness-90 active:shadow-none active:translate-y-1"
+ >
+
+ Entrainements
+
+
navigate("/competition")}
+ className="bg-alabaster-900 col-span-2 border-tree-poppy-300 shadow-tree-poppy-300 border-3 flex flex-col items-center gap-2 rounded-xl hover:brightness-90 active:shadow-none active:translate-y-1"
+ >
+
+ Compétition
+
+
+
+
+
Statistiques de Flami
+
+
+
+
+ );
+}
-export default FlamiPage;
+export default FlamiPage;
\ No newline at end of file
diff --git a/client/src/pages/flami/ScanPage.tsx b/client/src/pages/flami/ScanPage.tsx
new file mode 100644
index 0000000..5b6e130
--- /dev/null
+++ b/client/src/pages/flami/ScanPage.tsx
@@ -0,0 +1,70 @@
+import TopBar from "../../components/topbar/TopBar";
+import { useAuth } from "../../hooks/useAuth";
+import QrReader from "react-qr-reader-es6";
+import { APIHandler } from "../../utils/api/api-handler";
+import { Flami } from "../../interfaces/flami.interface";
+import { useNavigate } from "react-router";
+import toast from "react-hot-toast";
+import { useCallback } from "react";
+import { useGeolocated } from "react-geolocated";
+
+const ScanPage = () => {
+ const { token } = useAuth();
+
+ const navigate = useNavigate();
+
+ const { coords } =
+ useGeolocated({
+ positionOptions: {
+ enableHighAccuracy: false,
+ },
+ userDecisionTimeout: 5000,
+ });
+
+ let shareFlami = useCallback((data: string) => {
+ const { id, location } = JSON.parse(data);
+ APIHandler("/my/flami/share", false, "POST", {
+ flami_id: id,
+ location_shared: location,
+ location: {
+ lat: coords?.latitude || null,
+ long: coords?.longitude || null
+ }
+ }, token).then(
+ (res) => {
+ console.log(res);
+ navigate("/");
+ toast.success(`${res.data.name} reçu !`, {
+ style: {
+ background: "#3D3D3D",
+ color: "#FAFAFA",
+ borderRadius: "12px",
+ },
+ });
+ }
+ ).catch(() => {
+ navigate("/share/scan");
+ });
+ }, [token]);
+
+ return (
+
+
+ {
+ if (!!result && token) {
+ shareFlami(result);
+ shareFlami = () => null;
+ }
+ }}
+ onError={(error) => console.error(error)}
+ />
+ Centrez le QR code de votre ami dans le carré et attendez qu'il soit détecté.
+
+ );
+};
+
+export default ScanPage;
diff --git a/client/src/pages/flami/SharePage.tsx b/client/src/pages/flami/SharePage.tsx
new file mode 100644
index 0000000..2280449
--- /dev/null
+++ b/client/src/pages/flami/SharePage.tsx
@@ -0,0 +1,84 @@
+import { useCallback, useEffect, useState } from "react";
+import TopBar from "../../components/topbar/TopBar";
+import { APIHandler } from "../../utils/api/api-handler";
+import { useAuth } from "../../hooks/useAuth";
+import QRCode from "react-qr-code";
+import { Flami } from "../../interfaces/flami.interface";
+import { useNavigate } from "react-router";
+import { Button } from "../../components/ui";
+import { useGeolocated } from "react-geolocated";
+
+const SharePage = () => {
+ const { token } = useAuth();
+ const [flami, setFlami] = useState();
+ const navigate = useNavigate();
+
+ const getFlami = useCallback(() => {
+ APIHandler("/my/flami", false, "GET", undefined, token).then(
+ (res) => {
+ setFlami(res.data);
+ }
+ );
+ }, [token]);
+
+ useEffect(() => {
+ getFlami();
+ }, [getFlami]);
+
+ const { coords } =
+ useGeolocated({
+ positionOptions: {
+ enableHighAccuracy: false,
+ },
+ userDecisionTimeout: 5000,
+ });
+
+ return (
+
+
+
+
+
+
+ {
+ flami?.shared_flami ? (
+ <>
+
Relaie le Flami de
+
{flami?.owner}
+ >
+ ) : (
+
+ Partage ton Flami
+
+ )
+ }
+
En fesant scanner ce QR code à un ami.
+
+
+
+
+
+
+ navigate("/share/scan")}>
+ Scanner le QR code d'un ami
+
+
+
+
+ );
+};
+
+export default SharePage;
diff --git a/client/src/pages/map/MapPage.tsx b/client/src/pages/map/MapPage.tsx
index 21dd4a6..695fcd0 100644
--- a/client/src/pages/map/MapPage.tsx
+++ b/client/src/pages/map/MapPage.tsx
@@ -1,16 +1,21 @@
-import { useEffect, useState } from "react";
+import { useCallback, useEffect, useState } from "react";
import "leaflet/dist/leaflet.css";
import { APIHandler } from "../../utils/api/api-handler";
import { Step } from "../../interfaces/step.interface";
import Map from "../../components/map/Map";
import FlameLocation from "../../components/map/FlameLocation";
import FlamiLocation from "../../components/map/FlamiLocation";
+import { useAuth } from "../../hooks/useAuth";
+import { Flami } from "../../interfaces/flami.interface";
const MapPage = () => {
const [steps, setSteps] = useState([]);
const [currentFlameLocation, setCurrentFlameLocation] = useState();
const [nextFlameLocation, setNextFlameLocation] = useState();
const polylinePath: [number, number][] = [];
+ const { token } = useAuth();
+
+ const [flamiLocation, setFlamiLocation] = useState();
const handleSteps = () => {
APIHandler("/etapes", true)
@@ -33,30 +38,62 @@ const MapPage = () => {
setCurrentFlameLocation(res.data);
handleNextStep(res.data.etape_numero);
});
- }
+ };
+
+ const getFlamiLocation = useCallback(() => {
+ APIHandler("/my/flami", false, "GET", undefined, token).then(
+ async (res) => {
+ if(!res.data || !res.data.location || res.data.location.lat === undefined || res.data.location.long === undefined) return setFlamiLocation(null);
+ await fetch(`https://api-adresse.data.gouv.fr/reverse/?lat=${res.data.location.lat}&lon=${res.data.location.long}`).then(res => res.json().then(
+ (data) => {
+ console.log(data);
+ if(data.features?.length > 0) {
+ let context = data.features[0]["properties"]["context"].split(", ");
+ console.log(context);
+ setFlamiLocation({
+ ville: data.features[0]["properties"]["city"],
+ dept: `${context[1]} (${context[0]})`,
+ region: context[2]
+ });
+ } else {
+ setFlamiLocation(null);
+ }
+ }
+ )).catch(() => setFlamiLocation(null));
+ }
+ );
+ }, [token]);
+
+ console.log(flamiLocation);
useEffect(() => {
handleSteps();
handleCurrentStep();
+ getFlamiLocation();
}, []);
- if(currentFlameLocation) {
+ if (currentFlameLocation) {
steps.forEach((step) => {
- if(currentFlameLocation && step.etape_numero > currentFlameLocation.etape_numero) return;
+ if (
+ currentFlameLocation &&
+ step.etape_numero > currentFlameLocation.etape_numero
+ )
+ return;
polylinePath.push([
step.geolocalisation.latitude,
step.geolocalisation.longitude,
]);
});
}
-
- console.log(currentFlameLocation);
-
return (
Parcours de la flamme
-
+
Où est la flamme
@@ -67,7 +104,9 @@ const MapPage = () => {
Où est mon Flami
-
+ {
+ flamiLocation !== null ? (
) : (Aucune position trouvé.
)
+ }
diff --git a/client/src/pages/profile/AllBadgesPage.tsx b/client/src/pages/profile/AllBadgesPage.tsx
new file mode 100644
index 0000000..ade5155
--- /dev/null
+++ b/client/src/pages/profile/AllBadgesPage.tsx
@@ -0,0 +1,71 @@
+import { useCallback, useState, useEffect } from "react";
+import TopBar from "../../components/topbar/TopBar";
+import { APIHandler } from "../../utils/api/api-handler";
+import { useAuth } from "../../hooks/useAuth";
+import { Badge } from "../../interfaces/badge.interface";
+import { CloseIcon } from "react-line-awesome";
+import BadgeDisplay from "../../components/profile/BadgeDisplay";
+
+const AllBadgesPage = () => {
+ const { token } = useAuth();
+ const [badges, setBadges] = useState
();
+ const [infoBadge, setInfoBadge] = useState();
+
+ const selectBadge = (badge: Badge | null) => {
+ infoBadge ? setInfoBadge(null) : setInfoBadge(badge);
+ };
+
+ const getBadges = useCallback(() => {
+ APIHandler("/my/badges", false, "GET", undefined, token).then(
+ (res) => {
+ setBadges(res.data);
+ }
+ );
+ }, [token]);
+
+ useEffect(() => {
+ getBadges();
+ }, [getBadges]);
+
+ return (
+
+
+ {infoBadge ? (
+
+ selectBadge(null)}
+ className="text-3xl text-alabaster-50 cursor-pointer px-2 py-1 hover:bg-alabaster-300/20 rounded-xl ease-out duration-100 place-self-end"
+ />
+
+ {infoBadge.name}
+ {infoBadge.description}
+
+ ) : (
+
+ Badges villes étapes
+
+ {badges &&
+ badges.map((badge: Badge) =>
+ badge.owned ? (
+
selectBadge(badge)}
+ className="w-full cursor-pointer"
+ src={badge.url}
+ alt={`Badge de ${badge.name}`}
+ />
+ ) : (
+
+ )
+ )}
+
+
+ )}
+
+ );
+};
+
+export default AllBadgesPage;
diff --git a/client/src/pages/profile/ProfilePage.tsx b/client/src/pages/profile/ProfilePage.tsx
index f453bf5..0a9998c 100644
--- a/client/src/pages/profile/ProfilePage.tsx
+++ b/client/src/pages/profile/ProfilePage.tsx
@@ -6,6 +6,7 @@ import { APIHandler } from "../../utils/api/api-handler";
import { User } from "../../interfaces/user.interface";
import { getReadableDate } from "../../utils/getReadableDate";
import BadgeDisplay from "../../components/profile/BadgeDisplay";
+import { Badge } from "../../interfaces/badge.interface";
const ProfilePage = () => {
const { signout, token } = useAuth();
@@ -22,7 +23,6 @@ const ProfilePage = () => {
useEffect(() => {
getUser();
}, [getUser]);
- console.log(user?.badges);
return (
@@ -46,13 +46,18 @@ const ProfilePage = () => {
Mes badges
-
+
{user && user.badges?.length !== 0 ? (
- user.badges?.map((badge) => (
-
+ user.badges?.map((badge: Badge) => (
+ //
+
))
) : (
-
Tu n'as pas de badges !
+
Tu n'as pas de badges !
)}
{
+ it("should pass", () => {
+ expect(true).toBeTruthy();
+ });
+});
diff --git a/server/controllers/auth.controller.js b/server/controllers/auth.controller.js
index 6d0e37f..8fb2315 100644
--- a/server/controllers/auth.controller.js
+++ b/server/controllers/auth.controller.js
@@ -120,8 +120,8 @@ const authController = {
}
} catch (error) {
return res
- .status(404)
- .json({ message: "Une erreur s'est produite.", error: 404 });
+ .status(401)
+ .json({ message: "Une erreur s'est produite.", error: 401 });
}
},
};
diff --git a/server/controllers/flami.controller.js b/server/controllers/flami.controller.js
index d9a4b38..a9f3557 100644
--- a/server/controllers/flami.controller.js
+++ b/server/controllers/flami.controller.js
@@ -1,18 +1,154 @@
+import { readFile } from "fs/promises";
+import flamiModel from "../models/flami.model.js";
+import userModel from "../models/user.model.js";
+
const flamiController = {
- getFlami: (req, res) => {
+ getFlami: async (req, res) => {
+ let userdata = res.locals.user;
- },
- getCosmetics: (req, res) => {
+ let flami = await flamiModel.findById(userdata.flami_id);
+
+ let shared_flami = await flamiModel.findById(userdata.shared_flami.id);
+ let sharer_user;
+
+ if(shared_flami) {
+ sharer_user = await userModel.findById(shared_flami.owner_id);
+ }
+
+ let content = await readFile("./data/cosmetics.json", { encoding: "utf8" });
+ let json = JSON.parse(content);
+ return res.status(200).json({
+ data: {
+ name: flami.name,
+ owner: userdata.name,
+ cosmetics: flami.cosmetics.map((id) => json[id] || json[0]),
+ stamina: flami.stamina,
+ stats: flami.stats,
+ location: flami.location,
+ last_action: flami.last_action_time,
+ last_share: userdata.shared_flami?.shared_date || null,
+ _id: flami._id,
+ shared_flami: shared_flami ? {
+ name: shared_flami.name,
+ owner: sharer_user.name,
+ cosmetics: shared_flami.cosmetics.map((id) => json[id] || json[0]),
+ location: shared_flami.location,
+ stamina: shared_flami.stamina,
+ stats: shared_flami.stats,
+ last_action: shared_flami.last_action_time,
+ _id: shared_flami._id
+ } : null
+ }
+ });
},
- share: (req, res) => {
+ share: async (req, res) => {
+ let userdata = res.locals.user;
+ const { flami_id, location, location_shared } = req.body;
+
+ let user_flami = await flamiModel.findById(userdata.shared_flami?.id || userdata.flami_id);
+ let shared_flami = await flamiModel.findById(flami_id);
+ let sharer_user;
+
+ if(shared_flami) {
+ sharer_user = await userModel.findById(shared_flami.current_sharer_id || shared_flami.owner_id);
+
+ if(!sharer_user) {
+ return res.status(404).json({
+ message: `Cet utilisateur n'existe pas.`,
+ error: 404
+ });
+ }
+
+ if(sharer_user._id == userdata._id) {
+ return res.status(409).json({
+ message: `Ces utilisateurs sont identiques.`,
+ error: 409
+ });
+ }
+ if(user_flami._id == shared_flami._id) {
+ return res.status(409).json({
+ message: `Ce sont les mêmes Flami..?`,
+ error: 409
+ });
+ }
+
+ if(user_flami.shared_date == new Date().toDateString()) {
+ return res.status(409).json({
+ message: `Votre Flami a déjà été échangé aujourd'hui.`,
+ error: 409
+ });
+ }
+
+ if(shared_flami.shared_date == new Date().toDateString()) {
+ return res.status(409).json({
+ message: `Le ${shared_flami.name} a déjà été échangé aujourd'hui.`,
+ error: 409
+ });
+ }
+
+ await userModel.updateOne({ _id: userdata._id }, {
+ shared_flami: {
+ id: shared_flami._id,
+ shared_date: new Date().toDateString()
+ }
+ });
+
+ await userModel.updateOne({ _id: sharer_user._id }, {
+ shared_flami: {
+ id: user_flami._id,
+ shared_date: new Date().toDateString()
+ }
+ });
+
+ await flamiModel.updateOne({ _id: user_flami._id }, {
+ current_sharer_id: sharer_user._id,
+ location: {
+ lat: location_shared.lat,
+ long: location_shared.long
+ }
+ });
+
+ await flamiModel.updateOne({ _id: shared_flami._id }, {
+ current_sharer_id: userdata._id,
+ location: {
+ lat: location.lat,
+ long: location.long
+ }
+ });
+
+ return res.status(202).json({
+ data: {
+ name: shared_flami.name,
+ owner: sharer_user.name,
+ location: shared_flami.location,
+ _id: shared_flami._id
+ }
+ });
+ } else {
+ return res.status(404).json({
+ message: `Ce Flami n'existe pas.`,
+ error: 404
+ });
+ }
},
competition: (req, res) => {
},
- training: (req, res) => {
+ training: async (req, res) => {
+ let userdata = res.locals.user;
+ const { worked_stat } = req.body;
+
+ const f = await flamiModel.findOne({ _id: userdata.flami_id });
+ f["stats"][worked_stat]++;
+ f.save();
+ return res.status(202).json({
+ data: {
+ message: `Flami a gagner en ${worked_stat} !`
+ }
+ });
}
};
diff --git a/server/controllers/misc.controller.js b/server/controllers/misc.controller.js
new file mode 100644
index 0000000..a4338b2
--- /dev/null
+++ b/server/controllers/misc.controller.js
@@ -0,0 +1,4 @@
+import { readFile } from "fs/promises";
+
+const miscController = {
+}
\ No newline at end of file
diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js
index 49ed527..53c850b 100644
--- a/server/controllers/user.controller.js
+++ b/server/controllers/user.controller.js
@@ -14,7 +14,7 @@ const userController = {
email: userdata.email,
badges: userdata.badges
.slice(Math.max(0, userdata.badges.length - 3))
- .map((id) => json[id] ?? json[0]),
+ .map((id) => json[id] || json[0]),
created_at: new Date(userdata.date).toDateString(),
},
});
@@ -24,9 +24,10 @@ const userController = {
let content = await readFile("./data/badges.json", { encoding: "utf8" });
let json = JSON.parse(content);
return res.status(200).json({
- data: {
- badges: userdata.badges.map((id) => json[id] ?? json[0]),
- },
+ data: json.map((item, id) => {
+ userdata.badges.includes(id) ? item.owned = true : item.owned = false
+ return item;
+ })
});
},
updateAccount: async (req, res) => {
@@ -47,7 +48,7 @@ const userController = {
await userModel.updateOne({ _id: userdata._id }, patch);
- let token = auth.encode({ email: email ?? userdata.email });
+ let token = auth.encode({ email: email || userdata.email });
return res.status(200).json({
data: {
message: "Informations de compte misent à jour.",
diff --git a/server/data/badges.json b/server/data/badges.json
index 506500d..076f1cf 100644
--- a/server/data/badges.json
+++ b/server/data/badges.json
@@ -1,85 +1,85 @@
[
{
- "name": "Marseille",
- "url": "/assets/img/badges/PACA/medaille-40.svg",
- "url_cover": "/assets/img/badges/PACA/medaille_Médaille PACA (36-41).svg",
- "description": "START OF PARCOURS",
+ "name": "Départ de la flamme",
+ "url": "/assets/img/badges/depart_marseille.svg",
+ "url_cover": "/assets/img/badges/paca_cover.svg",
+ "description": "Prologue - Grande arrivée de la flamme à Marseille",
"region": "PACA"
},
{
"name": "Marseille",
- "url": "/assets/img/badges/PACA/medaille-40.svg",
- "url_cover": "/assets/img/badges/PACA/medaille_Médaille PACA (36-41).svg",
- "description": "",
+ "url": "/assets/img/badges/marseille_blason.svg",
+ "url_cover": "/assets/img/badges/paca_cover.svg",
+ "description": "Marseille est bien établie comme une ville capitale du transit méditerranéen de voyageurs et biens marchand. Cela est réellement ancré dans l'histoire de la ville avec son héritage maritime riche qui remonte même jusqu'à l'antiquité,à l'époque nommé Massalia. La ville a toujours été pleine de bien des richesses et cela est toujours visible aujourd'hui, notamment grâce au vieux quartier du panier, qui tient son nom d'une auberge qui arbore un panier comme enseigne, ce quartier existe depuis les premiers fondements de la ville et est aussi embelli qu'il sert de véritable capsule temporelle vers un temps ancien.",
"region": "PACA"
},
{
"name": "Toulon",
- "url": "/assets/img/badges/PACA/medaille-39.svg",
- "url_cover": "/assets/img/badges/PACA/medaille_Médaille PACA (36-41).svg",
- "description": "",
+ "url": "/assets/img/badges/toulon_blason.svg",
+ "url_cover": "/assets/img/badges/paca_cover.svg",
+ "description": "La ville de Toulon cache au sein de ses coutumes culinaires un hommage insolite et secret bien caché. Une des spécialités originaires de la ville est un gâteau nommé le Chanteclair. Cette pâtisserie à base de meringue, d'un mélange de crème chantilly et crème pâtissière glacée, parfumée de praline et de moka, et décoré d'un coq, tient son nom d'une pièce de théâtre créé en 1910 nommée Chantecler. Cette pièce d'Edmond Rostand, auteur de Cyrano de Bergerac, est retenue de par son envergure pour l'époque et les moyens mis en oeuvre pour la réalisé, comportant plus de 70 personnages et 195 costumes complets d'animaux, principalement des volailles. La pièce évoque l'histoire d'un coq de basse-cour et sa vanité, par la suite perdue mais retrouvée par le biais de sacrifices douloureux, histoire qui écho encore aujourd'hui grâce à cette pâtisserie Toulonnaise.",
"region": "PACA"
},
{
"name": "Manosque",
- "url": "/assets/img/badges/PACA/medaille-41.svg",
- "url_cover": "/assets/img/badges/PACA/medaille_Médaille PACA (36-41).svg",
- "description": "",
+ "url": "/assets/img/badges/manosque_blason.svg",
+ "url_cover": "/assets/img/badges/paca_cover.svg",
+ "description": "La ville de Manosque accueille chaque année, depuis 1999, le Festival des correspondances. C'est un festival de littérature qui célèbre les grands auteurs et promeut les nouveaux écrivains, organise des lectures et lectures croisées publiques et cherche à mettre la littérature en relation avec d'autres formes artistiques pour de nouvelles créations originales. C'est un évènement qui attire plus de 16 000 personnes chaque année et qui se déroule pendant plusieurs jours.",
"region": "PACA"
},
{
"name": "Arles",
- "url": "/assets/img/badges/PACA/medaille-38.svg",
- "url_cover": "/assets/img/badges/PACA/medaille_Médaille PACA (36-41).svg",
- "description": "",
+ "url": "/assets/img/badges/arles_blason.svg",
+ "url_cover": "/assets/img/badges/paca_cover.svg",
+ "description": "Au coeur de la ville d'Arles se trouve un amphithéâtre romain, l'un des mieux conservé au monde, et cela est dû au fait qu'il est toujours un lieu très attractif de par son activité. ici, le taureau Camargue est à l'honneur, et de véritable corrida française s'organise régulièrement, où les jeunes gens de la région affrontent les taureaux pour décrocher les cocardes des cornes de la bête. Les taureaux aussi sont récompensés, et les meilleurs sont immortalisés par le biais de titres et de statues commémoratives.",
"region": "PACA"
},
{
"name": "Montpellier",
- "url": "/assets/img/badges/Occitanie/medaille-29.svg",
- "url_cover": "/assets/img/badges/Occitanie/medaille_Médaille Occitanie (24-29).svg",
+ "url": "/assets/img/badges/montpellier_blason.svg",
+ "url_cover": "/assets/img/badges/occitanie_cover.svg",
"description": "",
"region": "Occitanie"
},
{
"name": "Bastia",
- "url": "/assets/img/badges/",
- "url_cover": "/assets/img/badges/",
+ "url": "/assets/img/badges/placeholder.svg",
+ "url_cover": "/assets/img/badges/placeholder.svg",
"description": "",
"region": "Corse"
},
{
"name": "Perpignan",
- "url": "/assets/img/badges/Occitanie/medaille-25.svg",
- "url_cover": "/assets/img/badges/Occitanie/medaille_Médaille Occitanie (24-29).svg",
+ "url": "/assets/img/badges/perpignan_blason.svg",
+ "url_cover": "/assets/img/badges/occitanie_cover.svg",
"description": "",
"region": "Occitanie"
},
{
- "name": "Carcassone",
- "url": "/assets/img/badges/Occitanie/medaille-24.svg",
- "url_cover": "/assets/img/badges/Occitanie/medaille_Médaille Occitanie (24-29).svg",
+ "name": "Carcassonne",
+ "url": "/assets/img/badges/carcassonne_blason.svg",
+ "url_cover": "/assets/img/badges/occitanie_cover.svg",
"description": "",
"region": "Occitanie"
},
{
"name": "Toulouse",
- "url": "/assets/img/badges/Occitanie/medaille-26.svg",
- "url_cover": "/assets/img/badges/Occitanie/medaille_Médaille Occitanie (24-29).svg",
+ "url": "/assets/img/badges/toulouse_blason.svg",
+ "url_cover": "/assets/img/badges/occitanie_cover.svg",
"description": "",
"region": "Occitanie"
},
{
"name": "Auch",
- "url": "/assets/img/badges/Occitanie/medaille-27.svg",
- "url_cover": "/assets/img/badges/Occitanie/medaille_Médaille Occitanie (24-29).svg",
+ "url": "/assets/img/badges/auch_blason.svg",
+ "url_cover": "/assets/img/badges/occitanie_cover.svg",
"description": "",
"region": "Occitanie"
},
{
"name": "Tarbes",
- "url": "/assets/img/badges/Occitanie/medaille-28.svg",
- "url_cover": "/assets/img/badges/Occitanie/medaille_Médaille Occitanie (24-29).svg",
+ "url": "/assets/img/badges/tarbes_blason.svg",
+ "url_cover": "/assets/img/badges/occitanie_cover.svg",
"description": "",
"region": "Occitanie"
}
diff --git a/server/data/cosmetics.json b/server/data/cosmetics.json
index b0a65f5..d76f469 100644
--- a/server/data/cosmetics.json
+++ b/server/data/cosmetics.json
@@ -2,37 +2,37 @@
{
"name": "Gants de boxe",
"description": "Des gants de boxe d'une grande qualité, donné aux utilisateurs aimant le sport de combat.",
- "url": "",
+ "url": "/assets/img/cosmetics/boxes-gloves.png",
"place": 2
},
{
"name": "Turbo-Chaussures",
"description": "Des baskets qui courts vite, donné aux utilisateurs aimant le sport de course.",
- "url": "",
+ "url": "/assets/img/cosmetics/turbo-chaussures.png",
"place": 4
},
{
"name": "Bonnet de bain et lunettes de plongé",
"description": "Quelle allure ! Donné aux utilisateurs aimant le sport aquatique.",
- "url": "",
+ "url": "/assets/img/cosmetics/bonnetbain.png",
"place": 1
},
{
"name": "Ballon de basket-ball",
"description": "Un ballon de basket-ball bien gonflé, donné aux utilisateurs aimant le sport collectif.",
- "url": "",
+ "url": "/assets/img/cosmetics/basket-ball.png",
"place": 3
},
{
"name": "Ballon de volley-ball",
"description": "Un ballon de volley-ball bien gonflé, donné aux utilisateurs aimant le sport de plage.",
- "url": "",
+ "url": "/assets/img/cosmetics/volley-ball.png",
"place": 3
},
{
"name": "Altère pesant son poids",
"description": "Une altère d'au moins 200kg, donné aux utilisateurs aimant le sport de force.",
- "url": "",
+ "url": "/assets/img/cosmetics/altere.png",
"place": 3
}
]
\ No newline at end of file
diff --git a/server/helpers/authMiddleware.js b/server/helpers/authMiddleware.js
index 5ded9a7..32f7e79 100644
--- a/server/helpers/authMiddleware.js
+++ b/server/helpers/authMiddleware.js
@@ -3,7 +3,7 @@ import userModel from "../models/user.model.js";
const auth = {
encode: (data) => {
- return jwt.sign(data, process.env.PRIVATE, { expiresIn: 60 * 15 });
+ return jwt.sign(data, process.env.PRIVATE, { expiresIn: "15m" });
},
require: async (req, res, next) => {
try {
@@ -40,8 +40,8 @@ const auth = {
return next();
} catch (error) {
return res
- .status(error.code ?? 401)
- .json({ message: "Une erreur s'est produite.", error: error.code ?? 401 });
+ .status(401)
+ .json({ message: "Une erreur s'est produite.", error: 401 });
}
},
};
diff --git a/server/mail/IdleAnim.gif b/server/mail/IdleAnim.gif
new file mode 100644
index 0000000..2bd2177
Binary files /dev/null and b/server/mail/IdleAnim.gif differ
diff --git a/server/mail/mailSender.js b/server/mail/mailSender.js
index e73cc72..c57b027 100644
--- a/server/mail/mailSender.js
+++ b/server/mail/mailSender.js
@@ -19,7 +19,7 @@ export const mailSender = async (email, subject, message) => {
html: message,
attachments: [{
filename: "flami-logo.png",
- path: './mail/flami-logo.png',
+ path: './mail/IdleAnim.gif', // './mail/flami-logo.png'
cid: 'logo-flami@cid'
}]
});
diff --git a/server/models/flami.model.js b/server/models/flami.model.js
index f674522..3022cfc 100644
--- a/server/models/flami.model.js
+++ b/server/models/flami.model.js
@@ -4,10 +4,10 @@ const flamiShema = new mongoose.Schema({
name: {
type: String
},
- owner: {
+ owner_id: {
type: mongoose.Types.ObjectId
},
- current_friend: {
+ current_sharer_id: {
type: mongoose.Types.ObjectId,
},
date: {
@@ -25,15 +25,15 @@ const flamiShema = new mongoose.Schema({
stats: {
strength: {
type: Number,
- default: 0
+ default: 1
},
speed: {
type: Number,
- default: 0
+ default: 1
},
dexterity: {
type: Number,
- default: 0
+ default: 1
}
},
stamina: {
diff --git a/server/models/user.model.js b/server/models/user.model.js
index 2962b97..961fd7c 100644
--- a/server/models/user.model.js
+++ b/server/models/user.model.js
@@ -29,11 +29,20 @@ const userSchema = new mongoose.Schema({
required: true,
min: 13
},
+ owned_cosmetics: {
+ type: Array,
+ default: []
+ },
flami_id: {
type: mongoose.Types.ObjectId
},
- friend_flami_id: {
- type: mongoose.Types.ObjectId
+ shared_flami: {
+ id: {
+ type: mongoose.Types.ObjectId
+ },
+ shared_date: {
+ type: String
+ }
},
badges: {
type: Array,
@@ -64,12 +73,14 @@ const userSchema = new mongoose.Schema({
userSchema.post('validate', async function () {
if(await this.constructor.findByEmail(this.email)) return;
let sports = { "Sport de combat": 0, "Sport de course": 1, "Sport aquatique": 2, "Sport collectif": 3, "Sport de plage": 4, "Sport de force": 5 }
+ let givenCosmetics = sports[this.metadata.favorite_sport] !== undefined ? [sports[this.metadata.favorite_sport]] : [];
let flami = await flamiModel.create({
name: `Flami de ${this.name}`,
- owner: this._id,
- cosmetics: sports[this.metadata.favorite_sport] ? [sports[this.metadata.favorite_sport]] : []
+ owner_id: this._id,
+ cosmetics: givenCosmetics
});
this.flami_id = flami._id;
+ this.owned_cosmetics = givenCosmetics;
});
export default mongoose.model("User", userSchema);
\ No newline at end of file
diff --git a/server/routes/flami.routes.js b/server/routes/flami.routes.js
index b978c82..ee517cd 100644
--- a/server/routes/flami.routes.js
+++ b/server/routes/flami.routes.js
@@ -8,6 +8,5 @@ router.patch("/competition", flamiController.competition);
router.patch("/training", flamiController.training);
router.post("/share", flamiController.share);
-router.get("/cosmetics", flamiController.getCosmetics);
export default router;
\ No newline at end of file
diff --git a/server/routes/misc.routes.js b/server/routes/misc.routes.js
index fdc48c7..fb1a751 100644
--- a/server/routes/misc.routes.js
+++ b/server/routes/misc.routes.js
@@ -1,8 +1,7 @@
import Router from "express";
-import userController from "../controllers/user.controller.js";
const router = Router();
-router.get("/map", userController.getProfile);
+// router.get("/badges", miscController.getAllBadges);
export default router;
\ No newline at end of file
diff --git a/server/routes/users.routes.js b/server/routes/users.routes.js
index fa0dd83..baa5c15 100644
--- a/server/routes/users.routes.js
+++ b/server/routes/users.routes.js
@@ -4,8 +4,8 @@ import flamiController from "../controllers/flami.controller.js";
const router = Router();
-router.get("/flami", flamiController.getFlami);
-router.get("/badges", userController.getBadges);
-router.get("/profile", userController.getProfile);
+// router.get("/flami", flamiController.getFlami);
+// router.get("/badges", userController.getBadges);
+// router.get("/profile", userController.getProfile);
export default router;