From b67e4d3b91ec3c37f03504e3d1ba89dd116a0dab Mon Sep 17 00:00:00 2001
From: Neo Ryo
Date: Mon, 22 Apr 2024 11:24:29 +0200
Subject: [PATCH] fixing countries WIP
---
server/controllers/activity.ts | 8 +-
server/controllers/user.ts | 2 +-
server/manager/activity.ts | 4 +-
server/middlewares/setVillage.ts | 4 +-
src/api/countries/countries.get.ts | 18 +++++
src/components/Flag.tsx | 8 +-
src/components/Navigation.tsx | 4 +-
src/components/WelcomeModal/FirstPhase.tsx | 2 +-
src/components/WorldMap/UserPopover.tsx | 2 +-
.../WorldMap/world/world.constants.ts | 1 +
src/components/accueil/Accueil.tsx | 18 ++++-
src/components/accueil/Filters/Filters.tsx | 11 +--
src/components/accueil/RightNavigation.tsx | 4 +-
.../activities/ActivityCard/index.tsx | 2 +-
.../ActivityComments/CommentCard.tsx | 2 +-
.../activities/ActivityView/index.tsx | 2 +-
src/components/activities/GameStats.tsx | 5 +-
src/contexts/countryContext.tsx | 29 +++++++
src/pages/_app.tsx | 79 ++++++++++---------
src/pages/admin/users/edit/[id].tsx | 9 ++-
src/pages/admin/users/new.tsx | 8 +-
src/pages/admin/villages/edit/[id].tsx | 10 ++-
src/pages/creer-un-jeu/mimique/jouer.tsx | 11 +--
src/services/useActivities.ts | 2 +-
types/country.type.ts | 1 +
25 files changed, 161 insertions(+), 85 deletions(-)
create mode 100644 src/api/countries/countries.get.ts
create mode 100644 src/contexts/countryContext.tsx
diff --git a/server/controllers/activity.ts b/server/controllers/activity.ts
index b2f10f504..1ae3b395b 100644
--- a/server/controllers/activity.ts
+++ b/server/controllers/activity.ts
@@ -25,17 +25,13 @@ const activityController = new Controller('/activities');
// --- Get all activities. ---
activityController.get({ path: '', userType: UserType.OBSERVATOR }, async (req: Request, res: Response) => {
if (!req.user) throw new AppError('Forbidden', ErrorCode.UNKNOWN);
+ console.log(req.query);
const activities = await getActivities({
limit: req.query.limit ? Number(getQueryString(req.query.limit)) || 200 : undefined,
page: req.query.page ? Number(getQueryString(req.query.page)) || 0 : undefined,
villageId: req.query.villageId ? Number(getQueryString(req.query.villageId)) || 0 : undefined,
- countries:
- req.query.countries !== undefined
- ? req.query.countries.length === 0
- ? []
- : (getQueryString(req.query.countries) || '').split(',')
- : undefined,
+ countries: req.query.countries && req.query.countries.length ? (req.query.countries as string[]).map((e) => Number(e)) : [],
pelico: req.query.pelico ? req.query.pelico !== 'false' : undefined,
type: req.query.type ? (getQueryString(req.query.type) || '').split(',') : undefined,
subType: req.query.subType ? Number(getQueryString(req.query.subType)) || 0 : undefined,
diff --git a/server/controllers/user.ts b/server/controllers/user.ts
index cba135e30..b5c2eb0e3 100644
--- a/server/controllers/user.ts
+++ b/server/controllers/user.ts
@@ -94,7 +94,7 @@ userController.get({ path: '', userType: UserType.OBSERVATOR }, async (req: Requ
userController.get({ path: '/:id', userType: UserType.TEACHER }, async (req: Request, res: Response, next: NextFunction) => {
const id = parseInt(req.params.id, 10) || 0;
- const user = await AppDataSource.getRepository(User).findOne({ where: { id } });
+ const user = await AppDataSource.getRepository(User).findOne({ where: { id }, relations: { country: true } });
const isSelfProfile = req.user && req.user.id === id;
const isAdmin = req.user && req.user.type <= UserType.ADMIN;
if (user === null || (!isSelfProfile && !isAdmin)) {
diff --git a/server/manager/activity.ts b/server/manager/activity.ts
index c54994433..f72cc3099 100644
--- a/server/manager/activity.ts
+++ b/server/manager/activity.ts
@@ -13,7 +13,7 @@ type ActivityGetter = {
villageId?: number;
type?: string[];
subType?: number | null;
- countries?: string[];
+ countries?: number[];
pelico?: boolean;
userId?: number;
status?: number;
@@ -80,7 +80,7 @@ export const getActivities = async ({
} else if (pelico && countries !== undefined && countries.length > 0) {
subQueryBuilder = subQueryBuilder
.innerJoin('activity.user', 'user')
- .andWhere('((user.countryCode IN (:countries) AND user.type >= :userType) OR user.type <= :userType2)', {
+ .andWhere('((user.countryId IN (:countries) AND user.type >= :userType) OR user.type <= :userType2)', {
countries,
userType: UserType.TEACHER,
userType2: UserType.MEDIATOR,
diff --git a/server/middlewares/setVillage.ts b/server/middlewares/setVillage.ts
index 47762ade7..2295171ca 100644
--- a/server/middlewares/setVillage.ts
+++ b/server/middlewares/setVillage.ts
@@ -13,7 +13,9 @@ export async function setVillage(req: Request, res: Response, next: NextFunction
villageId = req.cookies?.['village-id'] || -1;
}
if (villageId !== -1 || (user && user.type !== UserType.TEACHER)) {
- const villages = await AppDataSource.getRepository(Village).find(villageId !== -1 ? { where: { id: villageId } } : { order: { id: 'ASC' } });
+ const villages = await AppDataSource.getRepository(Village).find(
+ villageId !== -1 ? { where: { id: villageId }, relations: { countries: true } } : { order: { id: 'ASC' } },
+ );
req.village = villages[0];
}
if (villageId === -1 && req.village !== undefined) {
diff --git a/src/api/countries/countries.get.ts b/src/api/countries/countries.get.ts
new file mode 100644
index 000000000..9c123f92a
--- /dev/null
+++ b/src/api/countries/countries.get.ts
@@ -0,0 +1,18 @@
+import { useQuery } from 'react-query';
+import type { Country } from 'server/entities/country';
+
+import { axiosRequest } from 'src/utils/axiosRequest';
+
+async function getCountries(): Promise {
+ return (
+ await axiosRequest({
+ method: 'GET',
+ baseURL: '/api',
+ url: '/countries',
+ })
+ ).data;
+}
+
+export const useGetCountries = () => {
+ return useQuery(['countries'], () => getCountries());
+};
diff --git a/src/components/Flag.tsx b/src/components/Flag.tsx
index 8c23ca027..0c3e2dbbe 100644
--- a/src/components/Flag.tsx
+++ b/src/components/Flag.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import type { Country } from 'server/entities/country';
import MysteryFlag from 'src/svg/mystery-flag.svg';
@@ -9,7 +10,7 @@ const sizes = {
interface FlagProps {
isMistery?: boolean;
- country?: string;
+ country?: Country;
size?: 'small' | 'medium';
style?: React.CSSProperties;
}
@@ -20,6 +21,9 @@ export const Flag = ({ country, isMistery = false, size = 'medium', style = {} }
return (
// Small SVG, no need of improvments
// eslint-disable-next-line @next/next/no-img-element
-
+
);
};
diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx
index 05d841bc8..b42bb2ce8 100644
--- a/src/components/Navigation.tsx
+++ b/src/components/Navigation.tsx
@@ -258,7 +258,7 @@ export const Navigation = (): JSX.Element => {
{
{
{user ? user.country?.name : ''}
- {user && }
+ {user && }
)}
diff --git a/src/components/activities/ActivityView/index.tsx b/src/components/activities/ActivityView/index.tsx
index f564aa36d..6ef79f58a 100644
--- a/src/components/activities/ActivityView/index.tsx
+++ b/src/components/activities/ActivityView/index.tsx
@@ -54,7 +54,7 @@ export const ActivityView = ({ activity, user }: ActivityViewProps) => {
{isPelico ? (
) : (
-
+
)}
diff --git a/src/components/activities/GameStats.tsx b/src/components/activities/GameStats.tsx
index 9bff9d612..25059fba7 100644
--- a/src/components/activities/GameStats.tsx
+++ b/src/components/activities/GameStats.tsx
@@ -2,6 +2,7 @@ import React, { useMemo } from 'react';
import { AvatarImg } from '../Avatar';
import { Flag } from '../Flag';
+import type { Country } from 'types/country.type';
import type { GameResponse } from 'types/gameResponse.type';
import { UserType } from 'types/user.type';
import type { User } from 'types/user.type';
@@ -9,7 +10,7 @@ import type { User } from 'types/user.type';
type GameStatsProps = {
gameResponses: GameResponse[];
choices: number[];
- country: string;
+ country?: Country;
userMap: { [key: number]: number };
users: User[];
position: number;
@@ -22,7 +23,7 @@ const POSITION = [
];
const GameStats = ({ gameResponses, choices, country, userMap, users, position }: GameStatsProps) => {
const countryResponses = useMemo(() => {
- return gameResponses.filter((responseGame) => users[userMap[responseGame.userId]]?.country?.isoCode === country);
+ return gameResponses.filter((responseGame) => users[userMap[responseGame.userId]]?.country?.isoCode === country?.isoCode);
}, [country, gameResponses, userMap, users]);
const responseCount = countryResponses.length;
diff --git a/src/contexts/countryContext.tsx b/src/contexts/countryContext.tsx
new file mode 100644
index 000000000..da5f300ea
--- /dev/null
+++ b/src/contexts/countryContext.tsx
@@ -0,0 +1,29 @@
+import type { ReactNode } from 'react';
+import React, { useCallback, createContext, useState } from 'react';
+import type { Country } from 'server/entities/country';
+
+import { CircularProgress } from '@mui/material';
+
+import { useGetCountries } from 'src/api/countries/countries.get';
+
+interface CountryContextValue {
+ countries: Country[];
+}
+export const CountryContext = createContext({
+ countries: [],
+});
+
+interface Props {
+ children?: ReactNode;
+}
+export function CountryContextProvider({ children }: Props) {
+ const [countries, setCountries] = useState([]);
+ const countriesFetch = useGetCountries();
+ useCallback(() => {
+ if (countriesFetch.data) setCountries(countriesFetch.data);
+ }, [countriesFetch.data]);
+ if (countriesFetch.isLoading || countriesFetch.isIdle) {
+ return ;
+ }
+ return {children};
+}
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 10fc19676..c79b50f89 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -37,6 +37,7 @@ import { NewAdminHeader } from 'src/components/admin/NewAdminHeader';
import { NewAdminNavigation } from 'src/components/admin/NewAdminNavigation';
import { ActivityContextProvider } from 'src/contexts/activityContext';
import { ClassroomContextProvider } from 'src/contexts/classroomContext';
+import { CountryContextProvider } from 'src/contexts/countryContext';
import { UserContextProvider } from 'src/contexts/userContext';
import { VillageContextProvider } from 'src/contexts/villageContext';
import { useAnalytics } from 'src/hooks/useAnalytics';
@@ -136,49 +137,51 @@ const MyApp: React.FunctionComponent & {
-
- {isOnAdmin ? (
- router.pathname.startsWith('/admin/newportal') ? (
-
-
-
-
-
-
-
+
+
+ {isOnAdmin ? (
+ router.pathname.startsWith('/admin/newportal') ? (
+
-
- ) : (
-
-
-
-
-
-
+ ) : (
+
+ )
+ ) : user !== null &&
+ router.pathname !== '/inscription' &&
+ router.pathname !== '/connexion' &&
+ router.pathname !== '/login' &&
+ router.pathname !== '/user-verified' &&
+ router.pathname !== '/reset-password' &&
+ router.pathname !== '/update-password' &&
+ router.pathname !== '/404' ? (
+
+
+
+
- )
- ) : user !== null &&
- router.pathname !== '/inscription' &&
- router.pathname !== '/connexion' &&
- router.pathname !== '/login' &&
- router.pathname !== '/user-verified' &&
- router.pathname !== '/reset-password' &&
- router.pathname !== '/update-password' &&
- router.pathname !== '/404' ? (
-
-
+ ) : (
-
-
- ) : (
-
- )}
-
+ )}
+
+
diff --git a/src/pages/admin/users/edit/[id].tsx b/src/pages/admin/users/edit/[id].tsx
index 8a09790d6..2f289bc68 100644
--- a/src/pages/admin/users/edit/[id].tsx
+++ b/src/pages/admin/users/edit/[id].tsx
@@ -1,7 +1,7 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useSnackbar } from 'notistack';
-import React from 'react';
+import React, { useContext } from 'react';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import Breadcrumbs from '@mui/material/Breadcrumbs';
@@ -15,6 +15,7 @@ import TextField from '@mui/material/TextField';
import { AdminTile } from 'src/components/admin/AdminTile';
import { CountrySelector } from 'src/components/selectors/CountrySelector';
+import { CountryContext } from 'src/contexts/countryContext';
import { useUserRequests } from 'src/services/useUsers';
import { useVillages } from 'src/services/useVillages';
import { getQueryString } from 'src/utils';
@@ -34,6 +35,7 @@ const Required = (label: string) => (
const EditUser = () => {
const router = useRouter();
+ const { countries } = useContext(CountryContext);
const { villages } = useVillages();
const { editUser } = useUserRequests();
@@ -228,7 +230,10 @@ const EditUser = () => {
label={Required('Pays')}
value={user.country?.isoCode}
onChange={(countryCode) => {
- setUser((u) => (!u ? null : { ...u, country: { isoCode: countryCode, name: '' } }));
+ const foundCoundry = countries.find((c) => c.isoCode === countryCode);
+ if (foundCoundry) {
+ setUser((u) => (!u ? null : { ...u, country: foundCoundry }));
+ }
}}
filterCountries={
user.villageId ? villages.find((v) => v.id === user.villageId)?.countries?.map((c) => c.isoCode) || undefined : undefined
diff --git a/src/pages/admin/users/new.tsx b/src/pages/admin/users/new.tsx
index ba22bd668..688c62c5e 100644
--- a/src/pages/admin/users/new.tsx
+++ b/src/pages/admin/users/new.tsx
@@ -1,7 +1,7 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useSnackbar } from 'notistack';
-import React from 'react';
+import React, { useContext } from 'react';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import Breadcrumbs from '@mui/material/Breadcrumbs';
@@ -15,6 +15,7 @@ import TextField from '@mui/material/TextField';
import { AdminTile } from 'src/components/admin/AdminTile';
import { CountrySelector } from 'src/components/selectors/CountrySelector';
+import { CountryContext } from 'src/contexts/countryContext';
import { useUserRequests } from 'src/services/useUsers';
import { useVillages } from 'src/services/useVillages';
import { defaultOutlinedButtonStyle } from 'src/styles/variables.const';
@@ -32,6 +33,7 @@ const Required = (label: string) => (
);
const NewUser = () => {
+ const { countries } = useContext(CountryContext);
const router = useRouter();
const { villages } = useVillages();
const { addUser } = useUserRequests();
@@ -47,6 +49,7 @@ const NewUser = () => {
type: UserType.TEACHER,
villageId: 0,
country: {
+ id: -1,
isoCode: '',
name: '',
},
@@ -211,7 +214,8 @@ const NewUser = () => {
label={Required('Pays')}
value={newUser.country?.isoCode || ''}
onChange={(countryCode) => {
- setNewUser((u) => ({ ...u, country: { isoCode: countryCode, name: '' } }));
+ const countryFound = countries.find((c) => c.isoCode === countryCode);
+ if (countryFound) setNewUser((u) => ({ ...u, country: countryFound }));
}}
filterCountries={
newUser.villageId ? villages.find((v) => v.id === newUser.villageId)?.countries?.map((c) => c.isoCode) || undefined : undefined
diff --git a/src/pages/admin/villages/edit/[id].tsx b/src/pages/admin/villages/edit/[id].tsx
index 8f7bb6544..fd2f0089c 100644
--- a/src/pages/admin/villages/edit/[id].tsx
+++ b/src/pages/admin/villages/edit/[id].tsx
@@ -1,6 +1,6 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
-import React from 'react';
+import React, { useContext } from 'react';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import { Button, TextField } from '@mui/material';
@@ -9,6 +9,7 @@ import MaterialLink from '@mui/material/Link';
import { AdminTile } from 'src/components/admin/AdminTile';
import { CountrySelector } from 'src/components/selectors/CountrySelector';
+import { CountryContext } from 'src/contexts/countryContext';
import { useVillageRequests } from 'src/services/useVillages';
import { defaultOutlinedButtonStyle } from 'src/styles/variables.const';
import { getQueryString } from 'src/utils';
@@ -17,6 +18,7 @@ import type { Village } from 'types/village.type';
const EditVillage = () => {
const router = useRouter();
+ const { countries } = useContext(CountryContext);
const { editVillage } = useVillageRequests();
const villageId = React.useMemo(() => parseInt(getQueryString(router.query.id), 10) || 0, [router]);
@@ -80,7 +82,8 @@ const EditVillage = () => {
{
- setVillage((v) => (!v ? null : { ...v, countries: [{ isoCode: newValue, name: '' }, village.countries[1]] }));
+ const foundCountry = countries.find((c) => c.isoCode === newValue);
+ if (foundCountry) setVillage((v) => (!v ? null : { ...v, countries: [foundCountry, village.countries[1]] }));
}}
label="Pays 1"
style={{ width: '100%', marginBottom: '1rem' }}
@@ -88,7 +91,8 @@ const EditVillage = () => {
{
- setVillage((v) => (!v ? null : { ...v, countries: [village.countries[0], { isoCode: newValue, name: '' }] }));
+ const foundCountry = countries.find((c) => c.isoCode === newValue);
+ if (foundCountry) setVillage((v) => (!v ? null : { ...v, countries: [village.countries[0], foundCountry] }));
}}
label="Pays 2"
style={{ width: '100%', marginBottom: '1rem' }}
diff --git a/src/pages/creer-un-jeu/mimique/jouer.tsx b/src/pages/creer-un-jeu/mimique/jouer.tsx
index 54b989d56..d7e41fcd3 100644
--- a/src/pages/creer-un-jeu/mimique/jouer.tsx
+++ b/src/pages/creer-un-jeu/mimique/jouer.tsx
@@ -343,7 +343,8 @@ const PlayMimic = () => {
{gameCreatorIsPelico ? (
) : (
- gameCreator && gameCreator.country &&
+ gameCreator &&
+ gameCreator.country &&
)}
)}
@@ -418,7 +419,7 @@ const PlayMimic = () => {
{
gameResponses={gameResponses}
choices={choices}
position={1}
- country={
- userIsPelico
- ? village.countries[1].isoCode
- : village.countries.map((c) => c.isoCode).find((i) => i !== user.country?.isoCode) || ''
- }
+ country={userIsPelico ? village.countries[1] : village.countries.find((c) => c.id !== user.country?.id)}
userMap={userMap}
users={users}
/>
diff --git a/src/services/useActivities.ts b/src/services/useActivities.ts
index e1f8ed19f..b7402c581 100644
--- a/src/services/useActivities.ts
+++ b/src/services/useActivities.ts
@@ -14,7 +14,7 @@ import { UserType } from 'types/user.type';
export type Args = {
limit?: number;
page?: number;
- countries?: string[];
+ countries?: number[];
pelico?: boolean;
type?: number | number[];
userId?: number;
diff --git a/types/country.type.ts b/types/country.type.ts
index 3fa9a16d8..f6b3efcc3 100644
--- a/types/country.type.ts
+++ b/types/country.type.ts
@@ -1,4 +1,5 @@
export interface Country {
+ id: number;
isoCode: string;
name: string;
}