mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-09 09:04:20 +02:00
Fix tests & improve pre-register
This commit is contained in:
parent
fde48e6cbb
commit
d63f906206
@ -41,9 +41,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "yarn dev:build && nodemon ./public/server",
|
"dev": "yarn dev:build && nodemon ./public/server",
|
||||||
"dev:build": "cross-env NODE_ENV=development webpack --config ./webpack/server.config.ts",
|
"dev:build": "cross-env NODE_ENV=development webpack --config ./webpack/server.config.ts",
|
||||||
"local-start": "cross-env LOCAL=true node ./public/server",
|
"local-start": "cross-env LOCAL=true yarn build && node ./public/server",
|
||||||
"start": "node ./public/server",
|
"start": "node ./public/server",
|
||||||
"local-build": "cross-env LOCAL=true run-s build:*",
|
|
||||||
"build": "run-s build:*",
|
"build": "run-s build:*",
|
||||||
"build:server": "cross-env NODE_ENV=production webpack --config ./webpack/server.config.ts",
|
"build:server": "cross-env NODE_ENV=production webpack --config ./webpack/server.config.ts",
|
||||||
"build:client": "cross-env NODE_ENV=production webpack --config ./webpack/client.config.ts",
|
"build:client": "cross-env NODE_ENV=production webpack --config ./webpack/client.config.ts",
|
||||||
|
@ -9,52 +9,52 @@ exports[`<AddEnvie /> renders 1`] = `
|
|||||||
</h2>
|
</h2>
|
||||||
<form>
|
<form>
|
||||||
<label
|
<label
|
||||||
for="postDomaine"
|
for="postDomain"
|
||||||
>
|
>
|
||||||
Domaine:
|
Domaine:
|
||||||
<input
|
<input
|
||||||
id="postDomaine"
|
id="postDomain"
|
||||||
name="postDomaine"
|
name="postDomain"
|
||||||
type="text"
|
type="text"
|
||||||
value=""
|
value=""
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
for="postEnvies"
|
for="postWish"
|
||||||
>
|
>
|
||||||
Envies:
|
Envies:
|
||||||
<textarea
|
<textarea
|
||||||
id="postEnvies"
|
id="postWish"
|
||||||
name="postEnvies"
|
name="postWish"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
for="postPrecisions"
|
for="postDetails"
|
||||||
>
|
>
|
||||||
Precisions:
|
Precisions:
|
||||||
<textarea
|
<textarea
|
||||||
id="postPrecisions"
|
id="postDetails"
|
||||||
name="postPrecisions"
|
name="postDetails"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
for="postEquipes"
|
for="postTeams"
|
||||||
>
|
>
|
||||||
Equipes:
|
Equipes:
|
||||||
<input
|
<input
|
||||||
id="postEquipes"
|
id="postTeams"
|
||||||
name="postEquipes"
|
name="postTeams"
|
||||||
type="text"
|
type="text"
|
||||||
value=""
|
value=""
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
for="postDateAjout"
|
for="postAddedDate"
|
||||||
>
|
>
|
||||||
DateAjout:
|
Date dajout:
|
||||||
<input
|
<input
|
||||||
id="postDateAjout"
|
id="postAddedDate"
|
||||||
name="postDateAjout"
|
name="postAddedDate"
|
||||||
type="date"
|
type="date"
|
||||||
value=""
|
value=""
|
||||||
/>
|
/>
|
||||||
|
@ -1,50 +1,49 @@
|
|||||||
import React, { useState, memo } from "react"
|
import React, { useState, memo } from "react"
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
|
import styles from "./styles.module.scss"
|
||||||
|
|
||||||
import { AppDispatch } from "../../store"
|
import { AppDispatch } from "../../store"
|
||||||
|
|
||||||
import { fetchEnvieAdd } from "../../store/envieAdd"
|
import { fetchEnvieAdd } from "../../store/envieAdd"
|
||||||
import styles from "./styles.module.scss"
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
dispatch: AppDispatch
|
dispatch: AppDispatch
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddEnvie = ({ dispatch }: Props) => {
|
const AddEnvie = ({ dispatch }: Props) => {
|
||||||
const [domaine, setDomaine] = useState("")
|
const [domain, setDomain] = useState("")
|
||||||
const [envies, setEnvies] = useState("")
|
const [wish, setWish] = useState("")
|
||||||
const [precisions, setPrecisions] = useState("")
|
const [details, setDetails] = useState("")
|
||||||
const [equipes, setEquipes] = useState([""])
|
const [teams, setTeams] = useState([""])
|
||||||
const [dateAjout, setDateAjout] = useState("")
|
const [addedDate, setAddedDate] = useState("")
|
||||||
|
|
||||||
const onDomaineChanged = (e: React.ChangeEvent<HTMLInputElement>) => setDomaine(e.target.value)
|
const onDomainChanged = (e: React.ChangeEvent<HTMLInputElement>) => setDomain(e.target.value)
|
||||||
const onEnviesChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => setEnvies(e.target.value)
|
const onWishChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => setWish(e.target.value)
|
||||||
const onPrecisionsChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
const onDetailsChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||||
setPrecisions(e.target.value)
|
setDetails(e.target.value)
|
||||||
const onEquipesChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
const onTeamsChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
setEquipes(e.target.value.split(/, ?/))
|
setTeams(e.target.value.split(/, ?/))
|
||||||
const onDateAjoutChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
const onAddedDateChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
setDateAjout(e.target.value)
|
setAddedDate(e.target.value)
|
||||||
|
|
||||||
const onSavePostClicked = () => {
|
const onSavePostClicked = () => {
|
||||||
if (domaine && envies) {
|
if (domain && wish) {
|
||||||
dispatch(
|
dispatch(
|
||||||
fetchEnvieAdd({
|
fetchEnvieAdd({
|
||||||
domaine,
|
domain,
|
||||||
envies,
|
wish,
|
||||||
precisions,
|
details,
|
||||||
equipes,
|
teams,
|
||||||
dateAjout,
|
addedDate,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
setDomaine("")
|
setDomain("")
|
||||||
setEnvies("")
|
setWish("")
|
||||||
setPrecisions("")
|
setDetails("")
|
||||||
setEquipes([""])
|
setTeams([""])
|
||||||
setDateAjout("")
|
setAddedDate("")
|
||||||
} else {
|
} else {
|
||||||
toast.warning("Il faut au moins préciser un domaine et l'envie", {
|
toast.warning("Il faut au moins préciser un domain et l'envie", {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
autoClose: 6000,
|
autoClose: 6000,
|
||||||
hideProgressBar: true,
|
hideProgressBar: true,
|
||||||
@ -59,52 +58,47 @@ const AddEnvie = ({ dispatch }: Props) => {
|
|||||||
<section className={styles.EnvieList}>
|
<section className={styles.EnvieList}>
|
||||||
<h2>Ajouter une nouvelle envie</h2>
|
<h2>Ajouter une nouvelle envie</h2>
|
||||||
<form>
|
<form>
|
||||||
<label htmlFor="postDomaine">
|
<label htmlFor="postDomain">
|
||||||
Domaine:
|
Domaine:
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="postDomaine"
|
id="postDomain"
|
||||||
name="postDomaine"
|
name="postDomain"
|
||||||
value={domaine}
|
value={domain}
|
||||||
onChange={onDomaineChanged}
|
onChange={onDomainChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="postEnvies">
|
<label htmlFor="postWish">
|
||||||
Envies:
|
Envies:
|
||||||
<textarea
|
<textarea id="postWish" name="postWish" value={wish} onChange={onWishChanged} />
|
||||||
id="postEnvies"
|
|
||||||
name="postEnvies"
|
|
||||||
value={envies}
|
|
||||||
onChange={onEnviesChanged}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="postPrecisions">
|
<label htmlFor="postDetails">
|
||||||
Precisions:
|
Precisions:
|
||||||
<textarea
|
<textarea
|
||||||
id="postPrecisions"
|
id="postDetails"
|
||||||
name="postPrecisions"
|
name="postDetails"
|
||||||
value={precisions}
|
value={details}
|
||||||
onChange={onPrecisionsChanged}
|
onChange={onDetailsChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="postEquipes">
|
<label htmlFor="postTeams">
|
||||||
Equipes:
|
Equipes:
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="postEquipes"
|
id="postTeams"
|
||||||
name="postEquipes"
|
name="postTeams"
|
||||||
value={equipes.join(", ")}
|
value={teams.join(", ")}
|
||||||
onChange={onEquipesChanged}
|
onChange={onTeamsChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="postDateAjout">
|
<label htmlFor="postAddedDate">
|
||||||
DateAjout:
|
Date dajout:
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
id="postDateAjout"
|
id="postAddedDate"
|
||||||
name="postDateAjout"
|
name="postAddedDate"
|
||||||
value={dateAjout}
|
value={addedDate}
|
||||||
onChange={onDateAjoutChanged}
|
onChange={onAddedDateChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onClick={onSavePostClicked}>
|
<button type="button" onClick={onSavePostClicked}>
|
||||||
|
@ -28,21 +28,20 @@ describe("<List />", () => {
|
|||||||
entities: {
|
entities: {
|
||||||
"5": {
|
"5": {
|
||||||
id: 5,
|
id: 5,
|
||||||
titre: "6 qui prend!",
|
title: "6 qui prend!",
|
||||||
auteur: "Wolfgang Kramer",
|
author: "Wolfgang Kramer",
|
||||||
editeur: "(uncredited) , Design Edge , B",
|
editor: "(uncredited) , Design Edge , B",
|
||||||
minJoueurs: 2,
|
playersMin: 2,
|
||||||
maxJoueurs: 10,
|
playersMax: 10,
|
||||||
duree: 45,
|
duration: 45,
|
||||||
type: "Ambiance",
|
type: "Ambiance",
|
||||||
poufpaf: "0-9-2/6-qui-prend-6-nimmt",
|
poufpaf: "0-9-2/6-qui-prend-6-nimmt",
|
||||||
photo: "https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
|
bggPhoto:
|
||||||
bggPhoto: "",
|
"https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
|
||||||
bggId: 432,
|
bggId: 432,
|
||||||
exemplaires: 1,
|
copies: 1,
|
||||||
dispoPret: 1,
|
lendAvailability: 1,
|
||||||
nonRangee: 0,
|
notStored: 0,
|
||||||
horodatage: "0000-00-00",
|
|
||||||
ean: "3421272101313",
|
ean: "3421272101313",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -21,10 +21,10 @@ const JeuJavList = ({ ids }: Props) => {
|
|||||||
if (!jeu) {
|
if (!jeu) {
|
||||||
return <li key={id}>Le jeu #{id} n'existe pas</li>
|
return <li key={id}>Le jeu #{id} n'existe pas</li>
|
||||||
}
|
}
|
||||||
const { titre, bggId } = jeu
|
const { title, bggId } = jeu
|
||||||
return (
|
return (
|
||||||
<li key={id}>
|
<li key={id}>
|
||||||
{titre} - [{bggId}]
|
{title} - [{bggId}]
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -13,18 +13,18 @@ describe("<MembreInfo />", () => {
|
|||||||
<MembreInfo
|
<MembreInfo
|
||||||
item={{
|
item={{
|
||||||
id: 1,
|
id: 1,
|
||||||
nom: "Aupeix",
|
firstname: "Aupeix",
|
||||||
prenom: "Amélie",
|
lastname: "Amélie",
|
||||||
mail: "pakouille.lakouille@yahoo.fr",
|
email: "pakouille.lakouille@yahoo.fr",
|
||||||
telephone: "0675650392",
|
mobile: "0675650392",
|
||||||
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
||||||
alimentation: "Végétarien",
|
food: "Végétarien",
|
||||||
majeur: 1,
|
adult: 1,
|
||||||
privilege: 0,
|
privileges: 0,
|
||||||
actif: 0,
|
active: 0,
|
||||||
commentaire: "",
|
comment: "",
|
||||||
horodatage: "0000-00-00",
|
timestamp: "0000-00-00",
|
||||||
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
password: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPkdq9d5fqpbl8ASimSjNj4SR.9O",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
|
@ -10,11 +10,11 @@ exports[`<MembreInfo /> renders 1`] = `
|
|||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
Prénom:
|
Prénom:
|
||||||
Amélie
|
Aupeix
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Nom:
|
Nom:
|
||||||
Aupeix
|
Amélie
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,8 +11,8 @@ const MembreInfo = ({ item }: Props) => (
|
|||||||
<div className={styles.MembreCard}>
|
<div className={styles.MembreCard}>
|
||||||
<h4>Membre Info</h4>
|
<h4>Membre Info</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Prénom: {item.prenom}</li>
|
<li>Prénom: {item.firstname}</li>
|
||||||
<li>Nom: {item.nom}</li>
|
<li>Nom: {item.lastname}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -14,18 +14,19 @@ describe("<MembreList />", () => {
|
|||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
nom: "Aupeix",
|
firstname: "Aupeix",
|
||||||
prenom: "Amélie",
|
lastname: "Amélie",
|
||||||
mail: "pakouille.lakouille@yahoo.fr",
|
email: "pakouille.lakouille@yahoo.fr",
|
||||||
telephone: "0675650392",
|
mobile: "0675650392",
|
||||||
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
||||||
alimentation: "Végétarien",
|
food: "Végétarien",
|
||||||
majeur: 1,
|
adult: 1,
|
||||||
privilege: 0,
|
privileges: 0,
|
||||||
actif: 0,
|
active: 0,
|
||||||
commentaire: "",
|
comment: "",
|
||||||
horodatage: "0000-00-00",
|
timestamp: "0000-00-00",
|
||||||
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
password:
|
||||||
|
"$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPkdq9d5fqpbl8ASimSjNj4SR.9O",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -13,10 +13,10 @@ exports[`<MembreList /> renders 1`] = `
|
|||||||
href="/Membre/1"
|
href="/Membre/1"
|
||||||
>
|
>
|
||||||
<b>
|
<b>
|
||||||
Amélie
|
Aupeix
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
Aupeix
|
Amélie
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -12,10 +12,10 @@ const MembreList = ({ items }: Props) => (
|
|||||||
<div className={styles["user-list"]}>
|
<div className={styles["user-list"]}>
|
||||||
<h4>Membre List</h4>
|
<h4>Membre List</h4>
|
||||||
<ul>
|
<ul>
|
||||||
{items.map(({ id, nom, prenom }) => (
|
{items.map(({ id, lastname, firstname }) => (
|
||||||
<li key={id}>
|
<li key={id}>
|
||||||
<Link to={`/Membre/${id}`}>
|
<Link to={`/Membre/${id}`}>
|
||||||
<b>{prenom}</b> {nom}
|
<b>{firstname}</b> {lastname}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
@ -15,18 +15,18 @@ describe("<SetMembre />", () => {
|
|||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
membre={{
|
membre={{
|
||||||
id: 1,
|
id: 1,
|
||||||
nom: "Aupeix",
|
firstname: "Aupeix",
|
||||||
prenom: "Amélie",
|
lastname: "Amélie",
|
||||||
mail: "pakouille.lakouille@yahoo.fr",
|
email: "pakouille.lakouille@yahoo.fr",
|
||||||
telephone: "0675650392",
|
mobile: "0675650392",
|
||||||
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
||||||
alimentation: "Végétarien",
|
food: "Végétarien",
|
||||||
majeur: 1,
|
adult: 1,
|
||||||
privilege: 0,
|
privileges: 0,
|
||||||
actif: 0,
|
active: 0,
|
||||||
commentaire: "",
|
comment: "",
|
||||||
horodatage: "0000-00-00",
|
timestamp: "0000-00-00",
|
||||||
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
password: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPkdq9d5fqpbl8ASimSjNj4SR.9O",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
|
@ -9,34 +9,34 @@ exports[`<SetMembre /> renders 1`] = `
|
|||||||
</h2>
|
</h2>
|
||||||
<form>
|
<form>
|
||||||
<label
|
<label
|
||||||
for="postPrenom"
|
for="postFirstname"
|
||||||
>
|
>
|
||||||
Prenom:
|
Prénom:
|
||||||
<input
|
<input
|
||||||
id="postPrenom"
|
id="postFirstname"
|
||||||
name="postPrenom"
|
name="postFirstname"
|
||||||
type="text"
|
|
||||||
value="Amélie"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postNom"
|
|
||||||
>
|
|
||||||
Nom:
|
|
||||||
<input
|
|
||||||
id="postNom"
|
|
||||||
name="postNom"
|
|
||||||
type="text"
|
type="text"
|
||||||
value="Aupeix"
|
value="Aupeix"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
for="postMajeur"
|
for="postName"
|
||||||
|
>
|
||||||
|
Nom:
|
||||||
|
<input
|
||||||
|
id="postName"
|
||||||
|
name="postName"
|
||||||
|
type="text"
|
||||||
|
value="Amélie"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postAdult"
|
||||||
>
|
>
|
||||||
Majeur:
|
Majeur:
|
||||||
<input
|
<input
|
||||||
id="postMajeur"
|
id="postAdult"
|
||||||
name="postMajeur"
|
name="postAdult"
|
||||||
type="text"
|
type="text"
|
||||||
value="1"
|
value="1"
|
||||||
/>
|
/>
|
||||||
|
@ -13,22 +13,23 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MembreSet = ({ dispatch, membre }: Props) => {
|
const MembreSet = ({ dispatch, membre }: Props) => {
|
||||||
const [prenom, setPrenom] = useState(membre.prenom)
|
const [firstname, setFirstname] = useState(membre.firstname)
|
||||||
const [nom, setNom] = useState(membre.nom)
|
const [lastname, setName] = useState(membre.lastname)
|
||||||
const [majeur, setMajeur] = useState(membre.majeur)
|
const [adult, setAdult] = useState(membre.adult)
|
||||||
|
|
||||||
const onPrenomChanged = (e: React.ChangeEvent<HTMLInputElement>) => setPrenom(e.target.value)
|
const onFirstnameChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
const onNomChanged = (e: React.ChangeEvent<HTMLInputElement>) => setNom(e.target.value)
|
setFirstname(e.target.value)
|
||||||
const onMajeurChanged = (e: React.ChangeEvent<HTMLInputElement>) => setMajeur(+e.target.value)
|
const onNameChanged = (e: React.ChangeEvent<HTMLInputElement>) => setName(e.target.value)
|
||||||
|
const onAdultChanged = (e: React.ChangeEvent<HTMLInputElement>) => setAdult(+e.target.value)
|
||||||
|
|
||||||
const onSavePostClicked = () => {
|
const onSavePostClicked = () => {
|
||||||
if (prenom && nom) {
|
if (firstname && lastname) {
|
||||||
dispatch(
|
dispatch(
|
||||||
fetchMembreSet({
|
fetchMembreSet({
|
||||||
...membre,
|
...membre,
|
||||||
prenom,
|
firstname,
|
||||||
nom,
|
lastname,
|
||||||
majeur,
|
adult,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -47,34 +48,34 @@ const MembreSet = ({ dispatch, membre }: Props) => {
|
|||||||
<section className={styles.MembreList}>
|
<section className={styles.MembreList}>
|
||||||
<h2>Modifier un membre</h2>
|
<h2>Modifier un membre</h2>
|
||||||
<form>
|
<form>
|
||||||
<label htmlFor="postPrenom">
|
<label htmlFor="postFirstname">
|
||||||
Prenom:
|
Prénom:
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="postPrenom"
|
id="postFirstname"
|
||||||
name="postPrenom"
|
name="postFirstname"
|
||||||
value={prenom}
|
value={firstname}
|
||||||
onChange={onPrenomChanged}
|
onChange={onFirstnameChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="postNom">
|
<label htmlFor="postName">
|
||||||
Nom:
|
Nom:
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="postNom"
|
id="postName"
|
||||||
name="postNom"
|
name="postName"
|
||||||
value={nom}
|
value={lastname}
|
||||||
onChange={onNomChanged}
|
onChange={onNameChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="postMajeur">
|
<label htmlFor="postAdult">
|
||||||
Majeur:
|
Majeur:
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="postMajeur"
|
id="postAdult"
|
||||||
name="postMajeur"
|
name="postAdult"
|
||||||
value={majeur}
|
value={adult}
|
||||||
onChange={onMajeurChanged}
|
onChange={onAdultChanged}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onClick={onSavePostClicked}>
|
<button type="button" onClick={onSavePostClicked}>
|
||||||
|
@ -1,28 +1,93 @@
|
|||||||
import React, { memo, useCallback } from "react"
|
import React, { memo, useState } from "react"
|
||||||
|
import { useSelector, shallowEqual } from "react-redux"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
import _ from "lodash"
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
|
|
||||||
const RegisterForm = (): JSX.Element => {
|
import { fetchPreMemberAdd } from "../../store/preMemberAdd"
|
||||||
const onSubmit = useCallback((event: React.SyntheticEvent): void => {
|
import { AppDispatch, AppState } from "../../store"
|
||||||
event.preventDefault()
|
|
||||||
const target = event.target as typeof event.target & {
|
interface Props {
|
||||||
firstname: { value: string }
|
dispatch: AppDispatch
|
||||||
lastname: { value: string }
|
}
|
||||||
email: { value: string }
|
|
||||||
phone: { value: string }
|
const RegisterForm = ({ dispatch }: Props): JSX.Element => {
|
||||||
|
const [firstname, setFirstname] = useState("")
|
||||||
|
const [lastname, setLastname] = useState("")
|
||||||
|
const [email, setEmail] = useState("")
|
||||||
|
const [mobile, setMobile] = useState("")
|
||||||
|
const [alreadyVolunteer, setAlreadyVolunteer] = useState(false)
|
||||||
|
const [comment, setComment] = useState("")
|
||||||
|
const [sending, setSending] = useState(false)
|
||||||
|
|
||||||
|
const onFirstnameChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setFirstname(e.target.value)
|
||||||
|
const onLastnameChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setLastname(e.target.value)
|
||||||
|
const onEmailChanged = (e: React.ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)
|
||||||
|
const onMobileChanged = (e: React.ChangeEvent<HTMLInputElement>) => setMobile(e.target.value)
|
||||||
|
const onAlreadyVolunteer = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setAlreadyVolunteer(!!e.target.value)
|
||||||
|
const onNotYesVolunteer = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setAlreadyVolunteer(!e.target.value)
|
||||||
|
const onCommentChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||||
|
setComment(e.target.value)
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
if (firstname && lastname && email && mobile && !sending) {
|
||||||
|
dispatch(
|
||||||
|
fetchPreMemberAdd({
|
||||||
|
firstname,
|
||||||
|
lastname,
|
||||||
|
email,
|
||||||
|
mobile,
|
||||||
|
alreadyVolunteer,
|
||||||
|
comment,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
setSending(true)
|
||||||
|
} else {
|
||||||
|
toast.warning("Il faut remplir tous les champs (sauf le dernier)", {
|
||||||
|
position: "top-center",
|
||||||
|
autoClose: 6000,
|
||||||
|
hideProgressBar: true,
|
||||||
|
closeOnClick: true,
|
||||||
|
pauseOnHover: true,
|
||||||
|
draggable: true,
|
||||||
|
progress: undefined,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const firstname = target.firstname.value
|
}
|
||||||
const lastname = target.lastname.value
|
|
||||||
const email = target.email.value
|
|
||||||
const phone = target.phone.value
|
|
||||||
|
|
||||||
console.log("register fields checked", firstname, lastname, email, phone)
|
const { error, entities: preMember } = useSelector(
|
||||||
|
(state: AppState) => state.preMemberAdd,
|
||||||
|
shallowEqual
|
||||||
|
)
|
||||||
|
|
||||||
// call service with fields
|
let sendSuccess
|
||||||
}, [])
|
if (!_.isEmpty(preMember)) {
|
||||||
|
if (sending) {
|
||||||
|
setSending(false)
|
||||||
|
}
|
||||||
|
sendSuccess = <span className={styles.success}>Formulaire envoyé !</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
let sendError
|
||||||
|
if (error && _.isEmpty(preMember)) {
|
||||||
|
if (sending) {
|
||||||
|
setSending(false)
|
||||||
|
}
|
||||||
|
sendError = <span className={styles.error}>{error}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
let sendingElement
|
||||||
|
if (sending) {
|
||||||
|
sendingElement = <span className={styles.sending}>Envoi en cours...</span>
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
prenom
|
firstname
|
||||||
nom
|
lastname
|
||||||
mail
|
mail
|
||||||
tel
|
tel
|
||||||
j'ai déjà été bénévole pour PEL
|
j'ai déjà été bénévole pour PEL
|
||||||
@ -35,8 +100,8 @@ const RegisterForm = (): JSX.Element => {
|
|||||||
<dt>Qu'est-ce que Paris est Ludique ?</dt>
|
<dt>Qu'est-ce que Paris est Ludique ?</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p>
|
<p>
|
||||||
Cette grande fête est dédiée aux <b>jeux de société modernes</b> sous toutes
|
Un festival en plein air dédiée aux <b>jeux de société modernes</b> sous
|
||||||
leurs formes.
|
toutes leurs formes.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
En 2019 lors de la dernière édition, ce sont <b>16 000</b> joueurs qui se
|
En 2019 lors de la dernière édition, ce sont <b>16 000</b> joueurs qui se
|
||||||
@ -53,60 +118,88 @@ const RegisterForm = (): JSX.Element => {
|
|||||||
<dd>
|
<dd>
|
||||||
<p>
|
<p>
|
||||||
L'organisation du festival est <b>entièrement gérée par nous</b>, les
|
L'organisation du festival est <b>entièrement gérée par nous</b>, les
|
||||||
bénévoles. À aucun moment ça ne doit devenir une corvée, donc nous faisons
|
bénévoles. À aucun moment ça ne ressemble à du travail : nous faisons tout
|
||||||
tout pour passer <b>un aussi bon moment que les visiteurs</b> :)
|
pour passer <b>un aussi bon moment que les visiteurs</b> :)
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
C'est pour ça que chaque mois, ceux qui sont dispo prennent
|
D'ailleurs, un soir par mois nous nous réunissons pour un apéro ludique
|
||||||
l'apéro tous ensemble en jouant et discutant de l'organisation.
|
où discuter de l'organisation ! On joue autant que les visiteurs, mais
|
||||||
|
sur toute l'année ^^
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Pendant le festival de 2019, nous étions <b>187 bénévoles</b> organisés en
|
Pendant le festival de 2019, nous étions <b>187 bénévoles</b> organisés en
|
||||||
équipes spécialisées qui chouchoutent les visiteurs en les accueillant, en
|
équipes qui chouchoutent les visiteurs en les accueillant, en
|
||||||
s'assurant que tout se passe bien, ou en expliquant des règles de jeux.
|
s'assurant que tout se passe bien, ou encore en expliquant des règles
|
||||||
|
de jeux.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Une équipe s'occupe même du bien être des bénévoles en leur servant à
|
Une équipe est même dédiée au bien être des bénévoles en leur servant à
|
||||||
boire et à manger dans un espace à part où faire des pauses régulières.
|
boire et à manger dans un espace à part où faire des pauses régulières. Et
|
||||||
|
puis nous hébergeons ceux d'entre nous qui habitent loin de Paris. Le
|
||||||
|
confort avant tout !
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Les deux jours avant et le jour après le festival, ceux qui le peuvent
|
Certains bénévoles sont visiteurs le samedi ou le dimanche pour vivre le
|
||||||
viennent tout préparer et ranger. Certains ne sont disponibles que ces jours
|
festival de l'intérieur. Les deux jours avant et le jour après le
|
||||||
là et c'est déjà d'une grande aide !
|
festival, ceux qui le peuvent viennent préparer et ranger. Bref, chacun
|
||||||
|
participe à la hauteur de ses envies et disponibilités !
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Nous nous arrangeons pour héberger les bénévoles qui habitent loin de Paris,
|
Le samedi soir quand les visiteurs sont partis, nous prolongeons la fête en
|
||||||
et certains ne viennent qu'un seul jour du weekend pour être visiteur
|
dînant avec les auteurs, illustrateurs et éditeurs présents sur le festival.
|
||||||
l'autre.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Le samedi soir, cerise sur le gâteau, nous prenons un{" "}
|
|
||||||
<b>dîner avec les auteurs, illustrateurs et éditeurs</b> qui sont présents
|
|
||||||
sur le festival !
|
|
||||||
</p>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
Si l'expérience vous tente, n'hésitez pas à remplir le formulaire
|
Si l'expérience pourrait vous tenter, remplissez le formulaire suivant pour
|
||||||
suivant pour nous rencontrer lors d'un des gros apéros mensuels !<br />
|
en discuter lors d'un des gros apéros mensuels !<br />
|
||||||
|
Cette inscription ne vous oblige en rien il s'agit juste d'une prise
|
||||||
|
de contact.
|
||||||
|
<br />
|
||||||
Les prochains sont les 21 décembre et 27 janvier, mais nous vous appelerons
|
Les prochains sont les 21 décembre et 27 janvier, mais nous vous appelerons
|
||||||
d'ici là pour discuter :)
|
d'ici là pour les détails :)
|
||||||
|
<br />
|
||||||
|
<span className={styles.lightTitle}>(Déjà au moins 8 inscrits !)</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div className={styles.formLine} key="line-firstname">
|
<div className={styles.formLine} key="line-firstname">
|
||||||
<label htmlFor="firstname">Prénom</label>
|
<label htmlFor="firstname">Prénom</label>
|
||||||
<input type="text" id="firstname" />
|
<input
|
||||||
|
type="text"
|
||||||
|
id="firstname"
|
||||||
|
required
|
||||||
|
value={firstname}
|
||||||
|
onChange={onFirstnameChanged}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.formLine} key="line-lastname">
|
<div className={styles.formLine} key="line-lastname">
|
||||||
<label htmlFor="lastname">Nom</label>
|
<label htmlFor="lastname">Nom</label>
|
||||||
<input type="text" id="lastname" />
|
<input
|
||||||
|
type="text"
|
||||||
|
id="lastname"
|
||||||
|
required
|
||||||
|
value={lastname}
|
||||||
|
onChange={onLastnameChanged}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.formLine} key="line-email">
|
<div className={styles.formLine} key="line-email">
|
||||||
<label htmlFor="email">Email</label>
|
<label htmlFor="email">Email</label>
|
||||||
<input type="email" id="email" />
|
<input
|
||||||
|
type="email"
|
||||||
|
id="email"
|
||||||
|
required
|
||||||
|
value={email}
|
||||||
|
onChange={onEmailChanged}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.formLine} key="line-phone">
|
<div className={styles.formLine} key="line-mobile">
|
||||||
<label htmlFor="phone">Téléphone</label>
|
<label htmlFor="mobile">Téléphone</label>
|
||||||
<input type="text" id="phone" />
|
<input
|
||||||
|
type="text"
|
||||||
|
id="mobile"
|
||||||
|
required
|
||||||
|
value={mobile}
|
||||||
|
onChange={onMobileChanged}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.formLine} key="line-already-volunteer">
|
<div className={styles.formLine} key="line-already-volunteer">
|
||||||
<div>
|
<div>
|
||||||
@ -116,6 +209,8 @@ const RegisterForm = (): JSX.Element => {
|
|||||||
name="alreadyVolunteer"
|
name="alreadyVolunteer"
|
||||||
id="alreadyVolunteer-yes"
|
id="alreadyVolunteer-yes"
|
||||||
className={styles.inputRadio}
|
className={styles.inputRadio}
|
||||||
|
checked={alreadyVolunteer}
|
||||||
|
onChange={onAlreadyVolunteer}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="alreadyVolunteer-yes">Oui</label>
|
<label htmlFor="alreadyVolunteer-yes">Oui</label>
|
||||||
<input
|
<input
|
||||||
@ -123,6 +218,8 @@ const RegisterForm = (): JSX.Element => {
|
|||||||
name="alreadyVolunteer"
|
name="alreadyVolunteer"
|
||||||
id="alreadyVolunteer-no"
|
id="alreadyVolunteer-no"
|
||||||
className={styles.inputRadio}
|
className={styles.inputRadio}
|
||||||
|
checked={!alreadyVolunteer}
|
||||||
|
onChange={onNotYesVolunteer}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="alreadyVolunteer-no">Non</label>
|
<label htmlFor="alreadyVolunteer-no">Non</label>
|
||||||
</div>
|
</div>
|
||||||
@ -132,10 +229,19 @@ const RegisterForm = (): JSX.Element => {
|
|||||||
name="message"
|
name="message"
|
||||||
id="message"
|
id="message"
|
||||||
placeholder="Des petits mots sympas, questions, envies, des infos sur toi, des compétences dont tu aimerais te servir... ou rien de tout ça et nous en discuterons au téléphone :)"
|
placeholder="Des petits mots sympas, questions, envies, des infos sur toi, des compétences dont tu aimerais te servir... ou rien de tout ça et nous en discuterons au téléphone :)"
|
||||||
|
value={comment}
|
||||||
|
onChange={onCommentChanged}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.formButtons}>
|
<div className={styles.formButtons}>
|
||||||
<button type="submit">Envoyer</button>
|
<button type="button" onClick={onSubmit} disabled={sending}>
|
||||||
|
Envoyer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formReactions}>
|
||||||
|
{sendingElement}
|
||||||
|
{sendSuccess}
|
||||||
|
{sendError}
|
||||||
</div>
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lightTitle {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.formLine {
|
.formLine {
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
|
|
||||||
@ -48,4 +52,25 @@
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
[disabled="true"] {
|
||||||
|
background-color: #333333c0;
|
||||||
|
color: #cccccce7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.formReactions {
|
||||||
|
margin-top: 3px;
|
||||||
|
padding: 5px 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.sending {
|
||||||
|
color: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
.success {
|
||||||
|
color: rgb(0, 133, 0);
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: rgb(255, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const PORT = 4000
|
const PROTOCOL = (typeof window !== "undefined" && window?.location?.protocol) || "http:"
|
||||||
const API_URL = __DEV__ || __LOCAL__ ? `http://localhost:${PORT}` : "https://fo.parisestludique.fr"
|
const PORT = 4000 + (PROTOCOL === "https:" ? 2 : 0)
|
||||||
|
const API_URL =
|
||||||
|
__DEV__ || __LOCAL__ ? `${PROTOCOL}//localhost:${PORT}` : `${PROTOCOL}//fo.parisestludique.fr`
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
PORT,
|
PORT,
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
/**
|
|
||||||
* @jest-environment jsdom
|
|
||||||
*/
|
|
||||||
import { render } from "@testing-library/react"
|
|
||||||
import { MemoryRouter } from "react-router-dom"
|
|
||||||
|
|
||||||
import { fetchJeuJavListIfNeed } from "../../../store/jeuJavList"
|
|
||||||
import mockStore from "../../../utils/mockStore"
|
|
||||||
import Home from "../Home"
|
|
||||||
|
|
||||||
describe("<Home />", () => {
|
|
||||||
const renderHelper = (reducer = { readyStatus: "idle" }) => {
|
|
||||||
const { dispatch, ProviderWithStore } = mockStore({ jeuJavList: reducer })
|
|
||||||
const { container } = render(
|
|
||||||
<ProviderWithStore>
|
|
||||||
<MemoryRouter>
|
|
||||||
{/*
|
|
||||||
@ts-expect-error */}
|
|
||||||
<Home />
|
|
||||||
</MemoryRouter>
|
|
||||||
</ProviderWithStore>
|
|
||||||
)
|
|
||||||
|
|
||||||
return { dispatch, firstChild: container.firstChild }
|
|
||||||
}
|
|
||||||
|
|
||||||
it("should fetch data when page loaded", () => {
|
|
||||||
const { dispatch } = renderHelper()
|
|
||||||
|
|
||||||
expect(dispatch).toHaveBeenCalledTimes(1)
|
|
||||||
expect(dispatch.mock.calls[0][0].toString()).toBe(fetchJeuJavListIfNeed().toString())
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders the loading status if data invalid", () => {
|
|
||||||
expect(renderHelper().firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders the loading status if requesting data", () => {
|
|
||||||
const reducer = { readyStatus: "request" }
|
|
||||||
|
|
||||||
expect(renderHelper(reducer).firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders an error if loading failed", () => {
|
|
||||||
const reducer = { readyStatus: "failure" }
|
|
||||||
|
|
||||||
expect(renderHelper(reducer).firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders the <List /> if loading was successful", () => {
|
|
||||||
const reducer = {
|
|
||||||
readyStatus: "success",
|
|
||||||
ids: [5],
|
|
||||||
entities: {
|
|
||||||
"5": {
|
|
||||||
id: 5,
|
|
||||||
titre: "6 qui prend!",
|
|
||||||
auteur: "Wolfgang Kramer",
|
|
||||||
editeur: "(uncredited) , Design Edge , B",
|
|
||||||
minJoueurs: 2,
|
|
||||||
maxJoueurs: 10,
|
|
||||||
duree: 45,
|
|
||||||
type: "Ambiance",
|
|
||||||
poufpaf: "0-9-2/6-qui-prend-6-nimmt",
|
|
||||||
photo: "https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
|
|
||||||
bggPhoto: "",
|
|
||||||
bggId: 432,
|
|
||||||
exemplaires: 1,
|
|
||||||
dispoPret: 1,
|
|
||||||
nonRangee: 0,
|
|
||||||
horodatage: "0000-00-00",
|
|
||||||
ean: "3421272101313",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(renderHelper(reducer).firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,313 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<Home /> renders an error if loading failed 1`] = `
|
|
||||||
<div
|
|
||||||
class="home"
|
|
||||||
>
|
|
||||||
<section
|
|
||||||
class="EnvieList"
|
|
||||||
>
|
|
||||||
<h2>
|
|
||||||
Ajouter une nouvelle envie
|
|
||||||
</h2>
|
|
||||||
<form>
|
|
||||||
<label
|
|
||||||
for="postDomaine"
|
|
||||||
>
|
|
||||||
Domaine:
|
|
||||||
<input
|
|
||||||
id="postDomaine"
|
|
||||||
name="postDomaine"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEnvies"
|
|
||||||
>
|
|
||||||
Envies:
|
|
||||||
<textarea
|
|
||||||
id="postEnvies"
|
|
||||||
name="postEnvies"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postPrecisions"
|
|
||||||
>
|
|
||||||
Precisions:
|
|
||||||
<textarea
|
|
||||||
id="postPrecisions"
|
|
||||||
name="postPrecisions"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEquipes"
|
|
||||||
>
|
|
||||||
Equipes:
|
|
||||||
<input
|
|
||||||
id="postEquipes"
|
|
||||||
name="postEquipes"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postDateAjout"
|
|
||||||
>
|
|
||||||
DateAjout:
|
|
||||||
<input
|
|
||||||
id="postDateAjout"
|
|
||||||
name="postDateAjout"
|
|
||||||
type="date"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Save Post
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
<p>
|
|
||||||
Oops, Failed to load list!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Home /> renders the <List /> if loading was successful 1`] = `
|
|
||||||
<div
|
|
||||||
class="home"
|
|
||||||
>
|
|
||||||
<section
|
|
||||||
class="EnvieList"
|
|
||||||
>
|
|
||||||
<h2>
|
|
||||||
Ajouter une nouvelle envie
|
|
||||||
</h2>
|
|
||||||
<form>
|
|
||||||
<label
|
|
||||||
for="postDomaine"
|
|
||||||
>
|
|
||||||
Domaine:
|
|
||||||
<input
|
|
||||||
id="postDomaine"
|
|
||||||
name="postDomaine"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEnvies"
|
|
||||||
>
|
|
||||||
Envies:
|
|
||||||
<textarea
|
|
||||||
id="postEnvies"
|
|
||||||
name="postEnvies"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postPrecisions"
|
|
||||||
>
|
|
||||||
Precisions:
|
|
||||||
<textarea
|
|
||||||
id="postPrecisions"
|
|
||||||
name="postPrecisions"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEquipes"
|
|
||||||
>
|
|
||||||
Equipes:
|
|
||||||
<input
|
|
||||||
id="postEquipes"
|
|
||||||
name="postEquipes"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postDateAjout"
|
|
||||||
>
|
|
||||||
DateAjout:
|
|
||||||
<input
|
|
||||||
id="postDateAjout"
|
|
||||||
name="postDateAjout"
|
|
||||||
type="date"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Save Post
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
<div
|
|
||||||
class="JeuJavList"
|
|
||||||
>
|
|
||||||
<h4>
|
|
||||||
Jeux JAV
|
|
||||||
</h4>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
6 qui prend!
|
|
||||||
- [
|
|
||||||
432
|
|
||||||
]
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Home /> renders the loading status if data invalid 1`] = `
|
|
||||||
<div
|
|
||||||
class="home"
|
|
||||||
>
|
|
||||||
<section
|
|
||||||
class="EnvieList"
|
|
||||||
>
|
|
||||||
<h2>
|
|
||||||
Ajouter une nouvelle envie
|
|
||||||
</h2>
|
|
||||||
<form>
|
|
||||||
<label
|
|
||||||
for="postDomaine"
|
|
||||||
>
|
|
||||||
Domaine:
|
|
||||||
<input
|
|
||||||
id="postDomaine"
|
|
||||||
name="postDomaine"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEnvies"
|
|
||||||
>
|
|
||||||
Envies:
|
|
||||||
<textarea
|
|
||||||
id="postEnvies"
|
|
||||||
name="postEnvies"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postPrecisions"
|
|
||||||
>
|
|
||||||
Precisions:
|
|
||||||
<textarea
|
|
||||||
id="postPrecisions"
|
|
||||||
name="postPrecisions"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEquipes"
|
|
||||||
>
|
|
||||||
Equipes:
|
|
||||||
<input
|
|
||||||
id="postEquipes"
|
|
||||||
name="postEquipes"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postDateAjout"
|
|
||||||
>
|
|
||||||
DateAjout:
|
|
||||||
<input
|
|
||||||
id="postDateAjout"
|
|
||||||
name="postDateAjout"
|
|
||||||
type="date"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Save Post
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
<p>
|
|
||||||
Loading...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Home /> renders the loading status if requesting data 1`] = `
|
|
||||||
<div
|
|
||||||
class="home"
|
|
||||||
>
|
|
||||||
<section
|
|
||||||
class="EnvieList"
|
|
||||||
>
|
|
||||||
<h2>
|
|
||||||
Ajouter une nouvelle envie
|
|
||||||
</h2>
|
|
||||||
<form>
|
|
||||||
<label
|
|
||||||
for="postDomaine"
|
|
||||||
>
|
|
||||||
Domaine:
|
|
||||||
<input
|
|
||||||
id="postDomaine"
|
|
||||||
name="postDomaine"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEnvies"
|
|
||||||
>
|
|
||||||
Envies:
|
|
||||||
<textarea
|
|
||||||
id="postEnvies"
|
|
||||||
name="postEnvies"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postPrecisions"
|
|
||||||
>
|
|
||||||
Precisions:
|
|
||||||
<textarea
|
|
||||||
id="postPrecisions"
|
|
||||||
name="postPrecisions"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postEquipes"
|
|
||||||
>
|
|
||||||
Equipes:
|
|
||||||
<input
|
|
||||||
id="postEquipes"
|
|
||||||
name="postEquipes"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postDateAjout"
|
|
||||||
>
|
|
||||||
DateAjout:
|
|
||||||
<input
|
|
||||||
id="postDateAjout"
|
|
||||||
name="postDateAjout"
|
|
||||||
type="date"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Save Post
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
<p>
|
|
||||||
Loading...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* @jest-environment jsdom
|
|
||||||
*/
|
|
||||||
import { render } from "@testing-library/react"
|
|
||||||
import { MemoryRouter } from "react-router-dom"
|
|
||||||
|
|
||||||
import { fetchMembreIfNeed } from "../../../store/membre"
|
|
||||||
import mockStore from "../../../utils/mockStore"
|
|
||||||
import MembrePage from "../MembrePage"
|
|
||||||
|
|
||||||
describe("<MembrePage />", () => {
|
|
||||||
const mockData = {
|
|
||||||
id: 1,
|
|
||||||
nom: "Aupeix",
|
|
||||||
prenom: "Amélie",
|
|
||||||
mail: "pakouille.lakouille@yahoo.fr",
|
|
||||||
telephone: "0675650392",
|
|
||||||
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
|
||||||
alimentation: "Végétarien",
|
|
||||||
majeur: 1,
|
|
||||||
privilege: 0,
|
|
||||||
actif: 0,
|
|
||||||
commentaire: "",
|
|
||||||
horodatage: "0000-00-00",
|
|
||||||
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
|
||||||
}
|
|
||||||
const { id } = mockData
|
|
||||||
|
|
||||||
const renderHelper = (reducer = {}) => {
|
|
||||||
const { dispatch, ProviderWithStore } = mockStore({ membre: reducer })
|
|
||||||
const { container } = render(
|
|
||||||
<ProviderWithStore>
|
|
||||||
<MemoryRouter>
|
|
||||||
{/*
|
|
||||||
@ts-expect-error */}
|
|
||||||
<MembrePage match={{ params: { id } }} />
|
|
||||||
</MemoryRouter>
|
|
||||||
</ProviderWithStore>
|
|
||||||
)
|
|
||||||
|
|
||||||
return { dispatch, firstChild: container.firstChild }
|
|
||||||
}
|
|
||||||
|
|
||||||
it("should fetch data when page loaded", () => {
|
|
||||||
const { dispatch } = renderHelper()
|
|
||||||
|
|
||||||
expect(dispatch).toHaveBeenCalledTimes(1)
|
|
||||||
expect(dispatch.mock.calls[0][0].toString()).toBe(fetchMembreIfNeed(id).toString())
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders the loading status if data invalid", () => {
|
|
||||||
expect(renderHelper().firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders the loading status if requesting data", () => {
|
|
||||||
const reducer = { readyStatus: "request" }
|
|
||||||
|
|
||||||
expect(renderHelper(reducer).firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders an error if loading failed", () => {
|
|
||||||
const reducer = { readyStatus: "failure" }
|
|
||||||
|
|
||||||
expect(renderHelper(reducer).firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("renders the <Info /> if loading was successful", () => {
|
|
||||||
const reducer = { readyStatus: "success", entity: mockData }
|
|
||||||
|
|
||||||
expect(renderHelper(reducer).firstChild).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,104 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<MembrePage /> renders an error if loading failed 1`] = `
|
|
||||||
<div
|
|
||||||
class="membre"
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
Oops! Failed to load data.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<MembrePage /> renders the <Info /> if loading was successful 1`] = `
|
|
||||||
<div
|
|
||||||
class="membre"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="MembreCard"
|
|
||||||
>
|
|
||||||
<h4>
|
|
||||||
Membre Info
|
|
||||||
</h4>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Prénom:
|
|
||||||
Amélie
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Nom:
|
|
||||||
Aupeix
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<section
|
|
||||||
class="MembreList"
|
|
||||||
>
|
|
||||||
<h2>
|
|
||||||
Modifier un membre
|
|
||||||
</h2>
|
|
||||||
<form>
|
|
||||||
<label
|
|
||||||
for="postPrenom"
|
|
||||||
>
|
|
||||||
Prenom:
|
|
||||||
<input
|
|
||||||
id="postPrenom"
|
|
||||||
name="postPrenom"
|
|
||||||
type="text"
|
|
||||||
value="Amélie"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postNom"
|
|
||||||
>
|
|
||||||
Nom:
|
|
||||||
<input
|
|
||||||
id="postNom"
|
|
||||||
name="postNom"
|
|
||||||
type="text"
|
|
||||||
value="Aupeix"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
for="postMajeur"
|
|
||||||
>
|
|
||||||
Majeur:
|
|
||||||
<input
|
|
||||||
id="postMajeur"
|
|
||||||
name="postMajeur"
|
|
||||||
type="text"
|
|
||||||
value="1"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Save changes
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<MembrePage /> renders the loading status if data invalid 1`] = `
|
|
||||||
<div
|
|
||||||
class="membre"
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
Oops! Failed to load data.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<MembrePage /> renders the loading status if requesting data 1`] = `
|
|
||||||
<div
|
|
||||||
class="membre"
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
Loading...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
@ -1,18 +1,22 @@
|
|||||||
import { RouteComponentProps } from "react-router-dom"
|
import { RouteComponentProps } from "react-router-dom"
|
||||||
import React, { memo } from "react"
|
import { useDispatch } from "react-redux"
|
||||||
|
import { FC, memo } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet"
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
import RegisterForm from "../../components/RegisterForm/RegisterForm"
|
import RegisterForm from "../../components/RegisterForm/RegisterForm"
|
||||||
|
|
||||||
export type Props = RouteComponentProps
|
export type Props = RouteComponentProps
|
||||||
|
|
||||||
const RegisterPage: React.FC<Props> = (): JSX.Element => (
|
const RegisterPage: FC<Props> = (): JSX.Element => {
|
||||||
<div className={styles.registerPage}>
|
const dispatch = useDispatch()
|
||||||
<div className={styles.registerContent}>
|
return (
|
||||||
<Helmet title="RegisterPage" />
|
<div className={styles.registerPage}>
|
||||||
<RegisterForm />
|
<div className={styles.registerContent}>
|
||||||
|
<Helmet title="RegisterPage" />
|
||||||
|
<RegisterForm dispatch={dispatch} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
export default memo(RegisterPage)
|
export default memo(RegisterPage)
|
||||||
|
@ -13,6 +13,7 @@ export default [
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
|
exact: true,
|
||||||
component: Register,
|
component: Register,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -26,7 +27,6 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/register",
|
path: "/register",
|
||||||
exact: true,
|
|
||||||
component: AsyncHome,
|
component: AsyncHome,
|
||||||
loadData: loadHomeData,
|
loadData: loadHomeData,
|
||||||
},
|
},
|
||||||
|
@ -13,7 +13,12 @@ export default function getAccessors<
|
|||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
ElementNoId extends object,
|
ElementNoId extends object,
|
||||||
Element extends ElementNoId & ElementWithId
|
Element extends ElementNoId & ElementWithId
|
||||||
>(sheetName: string, specimen: Element): any {
|
>(sheetName: string, specimen: Element, translation: { [k in keyof Element]: string }): any {
|
||||||
|
const frenchSpecimen = _.mapValues(
|
||||||
|
_.invert(translation),
|
||||||
|
(englishProp: string) => (specimen as any)[englishProp]
|
||||||
|
) as Element
|
||||||
|
|
||||||
const addDBOperation = DBManager(sheetName)
|
const addDBOperation = DBManager(sheetName)
|
||||||
|
|
||||||
async function listGet(): Promise<Element[]> {
|
async function listGet(): Promise<Element[]> {
|
||||||
@ -27,10 +32,13 @@ export default function getAccessors<
|
|||||||
if (!rows[0]) {
|
if (!rows[0]) {
|
||||||
throw new Error(`No column types defined in sheet ${sheetName}`)
|
throw new Error(`No column types defined in sheet ${sheetName}`)
|
||||||
}
|
}
|
||||||
const types = _.pick(rows[0], Object.keys(specimen)) as Record<keyof Element, string>
|
const types = _.pick(rows[0], Object.values(translation)) as Record<
|
||||||
|
keyof Element,
|
||||||
|
string
|
||||||
|
>
|
||||||
rows.shift()
|
rows.shift()
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
const stringifiedElement = _.pick(row, Object.keys(specimen)) as Record<
|
const stringifiedElement = _.pick(row, Object.values(translation)) as Record<
|
||||||
keyof Element,
|
keyof Element,
|
||||||
string
|
string
|
||||||
>
|
>
|
||||||
@ -274,7 +282,7 @@ export default function getAccessors<
|
|||||||
}
|
}
|
||||||
return element
|
return element
|
||||||
},
|
},
|
||||||
JSON.parse(JSON.stringify(specimen))
|
JSON.parse(JSON.stringify(frenchSpecimen))
|
||||||
)
|
)
|
||||||
return fullElement
|
return fullElement
|
||||||
}
|
}
|
||||||
@ -365,7 +373,7 @@ export default function getAccessors<
|
|||||||
|
|
||||||
return stringifiedElement
|
return stringifiedElement
|
||||||
},
|
},
|
||||||
JSON.parse(JSON.stringify(element))
|
JSON.parse(JSON.stringify(frenchSpecimen))
|
||||||
)
|
)
|
||||||
|
|
||||||
return rawElement
|
return rawElement
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import getExpressAccessors from "./expressAccessors"
|
import getExpressAccessors from "./expressAccessors"
|
||||||
import { Envie, EnvieWithoutId } from "../../services/envies"
|
import { Envie, EnvieWithoutId, translationEnvie } from "../../services/envies"
|
||||||
|
|
||||||
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
||||||
EnvieWithoutId,
|
EnvieWithoutId,
|
||||||
Envie
|
Envie
|
||||||
>("Envies d'aider", new Envie())
|
>("Envies d'aider", new Envie(), translationEnvie)
|
||||||
|
|
||||||
export const envieListGet = listGetRequest()
|
export const envieListGet = listGetRequest()
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ export default function getExpressAccessors<
|
|||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
ElementNoId extends object,
|
ElementNoId extends object,
|
||||||
Element extends ElementNoId & ElementWithId
|
Element extends ElementNoId & ElementWithId
|
||||||
>(sheetName: string, specimen: Element): any {
|
>(sheetName: string, specimen: Element, translation: { [k in keyof Element]: string }): any {
|
||||||
const { get, listGet, add, set } = getAccessors(sheetName, specimen)
|
const { get, listGet, add, set } = getAccessors(sheetName, specimen, translation)
|
||||||
|
|
||||||
function listGetRequest() {
|
function listGetRequest() {
|
||||||
return async (
|
return async (
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import getExpressAccessors from "./expressAccessors"
|
import getExpressAccessors from "./expressAccessors"
|
||||||
import { JeuJav, JeuJavWithoutId } from "../../services/jeuxJav"
|
import { JeuJav, JeuJavWithoutId, translationJeuJav } from "../../services/jeuxJav"
|
||||||
|
|
||||||
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
||||||
JeuJavWithoutId,
|
JeuJavWithoutId,
|
||||||
JeuJav
|
JeuJav
|
||||||
>("Jeux JAV", new JeuJav())
|
>("Jeux JAV", new JeuJav(), translationJeuJav)
|
||||||
|
|
||||||
export const jeuJavListGet = listGetRequest()
|
export const jeuJavListGet = listGetRequest()
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import getExpressAccessors from "./expressAccessors"
|
import getExpressAccessors from "./expressAccessors"
|
||||||
import { Membre, MembreWithoutId } from "../../services/membres"
|
import { Membre, MembreWithoutId, translationMember } from "../../services/membres"
|
||||||
|
|
||||||
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
||||||
MembreWithoutId,
|
MembreWithoutId,
|
||||||
Membre
|
Membre
|
||||||
>("Membres", new Membre())
|
>("Membres", new Membre(), translationMember)
|
||||||
|
|
||||||
export const membreListGet = listGetRequest()
|
export const membreListGet = listGetRequest()
|
||||||
|
|
||||||
|
15
src/server/gsheets/preMembers.ts
Normal file
15
src/server/gsheets/preMembers.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import getExpressAccessors from "./expressAccessors"
|
||||||
|
import { PreMember, PreMemberWithoutId, translationPreMember } from "../../services/preMembers"
|
||||||
|
|
||||||
|
const { listGetRequest, getRequest, setRequest, addRequest } = getExpressAccessors<
|
||||||
|
PreMemberWithoutId,
|
||||||
|
PreMember
|
||||||
|
>("PreMembres", new PreMember(), translationPreMember)
|
||||||
|
|
||||||
|
export const preMemberListGet = listGetRequest()
|
||||||
|
|
||||||
|
export const preMemberGet = getRequest()
|
||||||
|
|
||||||
|
export const preMemberAdd = addRequest()
|
||||||
|
|
||||||
|
export const preMemberSet = setRequest()
|
@ -18,6 +18,7 @@ import certbotRouter from "../routes/certbot"
|
|||||||
import { secure } from "./secure"
|
import { secure } from "./secure"
|
||||||
import { jeuJavListGet } from "./gsheets/jeuJav"
|
import { jeuJavListGet } from "./gsheets/jeuJav"
|
||||||
import { envieListGet, envieAdd } from "./gsheets/envies"
|
import { envieListGet, envieAdd } from "./gsheets/envies"
|
||||||
|
import { preMemberAdd } from "./gsheets/preMembers"
|
||||||
import { membreGet, membreSet } from "./gsheets/membres"
|
import { membreGet, membreSet } from "./gsheets/membres"
|
||||||
import loginHandler from "./userManagement/login"
|
import loginHandler from "./userManagement/login"
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
@ -56,6 +57,7 @@ app.post("/api/user/login", loginHandler)
|
|||||||
app.get("/JeuJavListGet", jeuJavListGet)
|
app.get("/JeuJavListGet", jeuJavListGet)
|
||||||
app.get("/EnvieListGet", envieListGet)
|
app.get("/EnvieListGet", envieListGet)
|
||||||
app.post("/EnvieAdd", envieAdd)
|
app.post("/EnvieAdd", envieAdd)
|
||||||
|
app.post("/PreMemberAdd", preMemberAdd)
|
||||||
|
|
||||||
// Secured APIs
|
// Secured APIs
|
||||||
app.get("/MembreGet", secure as RequestHandler, membreGet)
|
app.get("/MembreGet", secure as RequestHandler, membreGet)
|
||||||
|
@ -10,9 +10,9 @@ import { login } from "../login"
|
|||||||
// Full test with Bearer: wget --header='Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoicGlraW91c3ViQGdlYWlsLmNvbSIsInBlcm1pc3Npb25zIjpbXSwiaWF0IjoxNjM4MjUzODgzLCJleHAiOjE2Mzg4NTg2ODN9.MknJ4NfcVlgW2ODeimfwZI1a4z8asdEXtHwHgViy6c4' http://localhost:3000/MembreGet?id=1
|
// Full test with Bearer: wget --header='Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoicGlraW91c3ViQGdlYWlsLmNvbSIsInBlcm1pc3Npb25zIjpbXSwiaWF0IjoxNjM4MjUzODgzLCJleHAiOjE2Mzg4NTg2ODN9.MknJ4NfcVlgW2ODeimfwZI1a4z8asdEXtHwHgViy6c4' http://localhost:3000/MembreGet?id=1
|
||||||
|
|
||||||
const mockUser = {
|
const mockUser = {
|
||||||
mail: "my.email@gmail.com",
|
email: "my.email@gmail.com",
|
||||||
passe: "$2y$10$cuKFHEow2IVSZSPtoVsw6uZFNFOOP/v1V7fubbyvrxhZdsnxLHr.2",
|
password: "$2y$10$cuKFHEow2IVSZSPtoVsw6uZFNFOOP/v1V7fubbyvrxhZdsnxLHr.2",
|
||||||
prenom: "monPrénom",
|
firstname: "monPrénom",
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.mock("../../gsheets/accessors", () => () => ({
|
jest.mock("../../gsheets/accessors", () => () => ({
|
||||||
@ -24,7 +24,7 @@ describe("login with", () => {
|
|||||||
const res = await login("my.email@gmail.com", "12345678")
|
const res = await login("my.email@gmail.com", "12345678")
|
||||||
expect(_.omit(res, "jwt")).toEqual({
|
expect(_.omit(res, "jwt")).toEqual({
|
||||||
membre: {
|
membre: {
|
||||||
prenom: mockUser.prenom,
|
firstname: mockUser.firstname,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
expect(res.jwt).toBeDefined()
|
expect(res.jwt).toBeDefined()
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
import { Request, Response, NextFunction } from "express"
|
import { Request, Response, NextFunction } from "express"
|
||||||
import bcrypt from "bcrypt"
|
import bcrypt from "bcrypt"
|
||||||
import { Membre, MemberLogin, emailRegexp, passwordMinLength } from "../../services/membres"
|
import {
|
||||||
|
Membre,
|
||||||
|
MemberLogin,
|
||||||
|
emailRegexp,
|
||||||
|
passwordMinLength,
|
||||||
|
translationMember,
|
||||||
|
} from "../../services/membres"
|
||||||
import getAccessors from "../gsheets/accessors"
|
import getAccessors from "../gsheets/accessors"
|
||||||
import { getJwt } from "../secure"
|
import { getJwt } from "../secure"
|
||||||
|
|
||||||
const { listGet } = getAccessors("Membres", new Membre())
|
const { listGet } = getAccessors("Membres", new Membre(), translationMember)
|
||||||
|
|
||||||
export default async function loginHandler(
|
export default async function loginHandler(
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -41,12 +47,12 @@ export async function login(rawEmail: string, rawPassword: string): Promise<Memb
|
|||||||
}
|
}
|
||||||
|
|
||||||
const membres: Membre[] = await listGet()
|
const membres: Membre[] = await listGet()
|
||||||
const membre = membres.find((m) => m.mail === email)
|
const membre = membres.find((m) => m.email === email)
|
||||||
if (!membre) {
|
if (!membre) {
|
||||||
throw Error("Cet email ne correspond à aucun utilisateur")
|
throw Error("Cet email ne correspond à aucun utilisateur")
|
||||||
}
|
}
|
||||||
|
|
||||||
const passwordMatch = await bcrypt.compare(password, membre.passe.replace(/^\$2y/, "$2a"))
|
const passwordMatch = await bcrypt.compare(password, membre.password.replace(/^\$2y/, "$2a"))
|
||||||
if (!passwordMatch) {
|
if (!passwordMatch) {
|
||||||
throw Error("Mauvais mot de passe pour cet email")
|
throw Error("Mauvais mot de passe pour cet email")
|
||||||
}
|
}
|
||||||
@ -55,7 +61,7 @@ export async function login(rawEmail: string, rawPassword: string): Promise<Memb
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
membre: {
|
membre: {
|
||||||
prenom: membre.prenom,
|
firstname: membre.firstname,
|
||||||
},
|
},
|
||||||
jwt,
|
jwt,
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
import _ from "lodash"
|
||||||
|
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
import { axiosConfig } from "./auth"
|
import { axiosConfig } from "./auth"
|
||||||
|
|
||||||
export type ElementWithId = unknown & { id: number }
|
export type ElementWithId = unknown & { id: number }
|
||||||
|
|
||||||
export function get<Element>(elementName: string): (id: number) => Promise<{
|
export type ElementTranslation = { [englishProp: string]: string }
|
||||||
|
|
||||||
|
export function get<Element>(
|
||||||
|
elementName: string,
|
||||||
|
translation: ElementTranslation
|
||||||
|
): (id: number) => Promise<{
|
||||||
data?: Element
|
data?: Element
|
||||||
error?: Error
|
error?: Error
|
||||||
}> {
|
}> {
|
||||||
@ -19,14 +25,24 @@ export function get<Element>(elementName: string): (id: number) => Promise<{
|
|||||||
...axiosConfig,
|
...axiosConfig,
|
||||||
params: { id },
|
params: { id },
|
||||||
})
|
})
|
||||||
return { data }
|
if (!data) {
|
||||||
|
return { data }
|
||||||
|
}
|
||||||
|
const englishData = _.mapValues(
|
||||||
|
translation,
|
||||||
|
(frenchProp: string) => data[frenchProp]
|
||||||
|
) as Element
|
||||||
|
return { data: englishData }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listGet<Element>(elementName: string): () => Promise<{
|
export function listGet<Element>(
|
||||||
|
elementName: string,
|
||||||
|
translation: ElementTranslation
|
||||||
|
): () => Promise<{
|
||||||
data?: Element[]
|
data?: Element[]
|
||||||
error?: Error
|
error?: Error
|
||||||
}> {
|
}> {
|
||||||
@ -37,7 +53,18 @@ export function listGet<Element>(elementName: string): () => Promise<{
|
|||||||
return async (): Promise<ElementListGetResponse> => {
|
return async (): Promise<ElementListGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${config.API_URL}/${elementName}ListGet`, axiosConfig)
|
const { data } = await axios.get(`${config.API_URL}/${elementName}ListGet`, axiosConfig)
|
||||||
return { data }
|
if (!data) {
|
||||||
|
return { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
const englishDataList = data.map(
|
||||||
|
(frenchData: any) =>
|
||||||
|
_.mapValues(
|
||||||
|
translation,
|
||||||
|
(frenchProp: string) => frenchData[frenchProp]
|
||||||
|
) as Element
|
||||||
|
)
|
||||||
|
return { data: englishDataList }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
}
|
}
|
||||||
@ -46,7 +73,8 @@ export function listGet<Element>(elementName: string): () => Promise<{
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
export function add<ElementNoId extends object, Element extends ElementNoId & ElementWithId>(
|
export function add<ElementNoId extends object, Element extends ElementNoId & ElementWithId>(
|
||||||
elementName: string
|
elementName: string,
|
||||||
|
translation: ElementTranslation
|
||||||
): (membreWithoutId: ElementNoId) => Promise<{
|
): (membreWithoutId: ElementNoId) => Promise<{
|
||||||
data?: Element
|
data?: Element
|
||||||
error?: Error
|
error?: Error
|
||||||
@ -57,19 +85,36 @@ export function add<ElementNoId extends object, Element extends ElementNoId & El
|
|||||||
}
|
}
|
||||||
return async (membreWithoutId: ElementNoId): Promise<ElementGetResponse> => {
|
return async (membreWithoutId: ElementNoId): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
|
const invertedTranslationWithoutId = _.invert(_.omit(translation, "id"))
|
||||||
|
const frenchDataWithoutId = _.mapValues(
|
||||||
|
invertedTranslationWithoutId,
|
||||||
|
(englishProp: string, _frenchProp: string) => (membreWithoutId as any)[englishProp]
|
||||||
|
)
|
||||||
|
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${config.API_URL}/${elementName}Add`,
|
`${config.API_URL}/${elementName}Add`,
|
||||||
membreWithoutId,
|
frenchDataWithoutId,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
return { data }
|
if (!data) {
|
||||||
|
return { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
const englishData = _.mapValues(
|
||||||
|
translation,
|
||||||
|
(frenchProp: string) => data[frenchProp]
|
||||||
|
) as Element
|
||||||
|
return { data: englishData }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set<Element>(elementName: string): (membre: Element) => Promise<{
|
export function set<Element>(
|
||||||
|
elementName: string,
|
||||||
|
translation: ElementTranslation
|
||||||
|
): (membre: Element) => Promise<{
|
||||||
data?: Element
|
data?: Element
|
||||||
error?: Error
|
error?: Error
|
||||||
}> {
|
}> {
|
||||||
@ -79,12 +124,26 @@ export function set<Element>(elementName: string): (membre: Element) => Promise<
|
|||||||
}
|
}
|
||||||
return async (membre: Element): Promise<ElementGetResponse> => {
|
return async (membre: Element): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
|
const invertedTranslation = _.invert(translation)
|
||||||
|
const frenchData = _.mapValues(
|
||||||
|
invertedTranslation,
|
||||||
|
(englishProp: string) => (membre as any)[englishProp]
|
||||||
|
)
|
||||||
|
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${config.API_URL}/${elementName}Set`,
|
`${config.API_URL}/${elementName}Set`,
|
||||||
membre,
|
frenchData,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
return { data }
|
if (!data) {
|
||||||
|
return { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
const englishData = _.mapValues(
|
||||||
|
translation,
|
||||||
|
(frenchProp: string) => data[frenchProp]
|
||||||
|
) as Element
|
||||||
|
return { data: englishData }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,34 @@ import { get, listGet, add, set } from "./accessors"
|
|||||||
export class Envie {
|
export class Envie {
|
||||||
id = 0
|
id = 0
|
||||||
|
|
||||||
domaine = ""
|
domain = ""
|
||||||
|
|
||||||
envies = ""
|
wish = ""
|
||||||
|
|
||||||
precisions = ""
|
details = ""
|
||||||
|
|
||||||
equipes: string[] = []
|
teams: string[] = []
|
||||||
|
|
||||||
dateAjout = ""
|
addedDate = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const translationEnvie: { [k in keyof Envie]: string } = {
|
||||||
|
id: "id",
|
||||||
|
domain: "domaine",
|
||||||
|
wish: "envies",
|
||||||
|
details: "precisions",
|
||||||
|
teams: "equipes",
|
||||||
|
addedDate: "dateAjout",
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementName = "Envie"
|
||||||
|
|
||||||
export type EnvieWithoutId = Omit<Envie, "id">
|
export type EnvieWithoutId = Omit<Envie, "id">
|
||||||
|
|
||||||
export const envieGet = get<Envie>("Envie")
|
export const envieGet = get<Envie>(elementName, translationEnvie)
|
||||||
|
|
||||||
export const envieListGet = listGet<Envie>("Envie")
|
export const envieListGet = listGet<Envie>(elementName, translationEnvie)
|
||||||
|
|
||||||
export const envieAdd = add<EnvieWithoutId, Envie>("Envie")
|
export const envieAdd = add<EnvieWithoutId, Envie>(elementName, translationEnvie)
|
||||||
|
|
||||||
export const envieSet = set<Envie>("Envie")
|
export const envieSet = set<Envie>(elementName, translationEnvie)
|
||||||
|
@ -3,17 +3,17 @@ import { get, listGet, add, set } from "./accessors"
|
|||||||
export class JeuJav {
|
export class JeuJav {
|
||||||
id = 0
|
id = 0
|
||||||
|
|
||||||
titre = ""
|
title = ""
|
||||||
|
|
||||||
auteur = ""
|
author = ""
|
||||||
|
|
||||||
editeur = ""
|
editor = ""
|
||||||
|
|
||||||
minJoueurs = 0
|
playersMin = 0
|
||||||
|
|
||||||
maxJoueurs = 0
|
playersMax = 0
|
||||||
|
|
||||||
duree = 0
|
duration = 0
|
||||||
|
|
||||||
type: "Ambiance" | "Famille" | "Expert" | "" = ""
|
type: "Ambiance" | "Famille" | "Expert" | "" = ""
|
||||||
|
|
||||||
@ -21,23 +21,43 @@ export class JeuJav {
|
|||||||
|
|
||||||
bggId = 0
|
bggId = 0
|
||||||
|
|
||||||
exemplaires = 1
|
copies = 1
|
||||||
|
|
||||||
dispoPret = 0
|
lendAvailability = 0
|
||||||
|
|
||||||
nonRangee = 0
|
notStored = 0
|
||||||
|
|
||||||
ean = ""
|
ean = ""
|
||||||
|
|
||||||
bggPhoto = ""
|
bggPhoto = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const translationJeuJav: { [k in keyof JeuJav]: string } = {
|
||||||
|
id: "id",
|
||||||
|
title: "titre",
|
||||||
|
author: "auteur",
|
||||||
|
editor: "editeur",
|
||||||
|
playersMin: "minJoueurs",
|
||||||
|
playersMax: "maxJoueurs",
|
||||||
|
duration: "duree",
|
||||||
|
type: "type",
|
||||||
|
poufpaf: "poufpaf",
|
||||||
|
bggId: "bggId",
|
||||||
|
copies: "exemplaires",
|
||||||
|
lendAvailability: "dispoPret",
|
||||||
|
notStored: "nonRangee",
|
||||||
|
ean: "ean",
|
||||||
|
bggPhoto: "bggPhoto",
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementName = "JeuJav"
|
||||||
|
|
||||||
export type JeuJavWithoutId = Omit<JeuJav, "id">
|
export type JeuJavWithoutId = Omit<JeuJav, "id">
|
||||||
|
|
||||||
export const jeuJavGet = get<JeuJav>("JeuJav")
|
export const jeuJavGet = get<JeuJav>(elementName, translationJeuJav)
|
||||||
|
|
||||||
export const jeuJavListGet = listGet<JeuJav>("JeuJav")
|
export const jeuJavListGet = listGet<JeuJav>(elementName, translationJeuJav)
|
||||||
|
|
||||||
export const jeuJavAdd = add<JeuJavWithoutId, JeuJav>("JeuJav")
|
export const jeuJavAdd = add<JeuJavWithoutId, JeuJav>(elementName, translationJeuJav)
|
||||||
|
|
||||||
export const jeuJavSet = set<JeuJav>("JeuJav")
|
export const jeuJavSet = set<JeuJav>(elementName, translationJeuJav)
|
||||||
|
@ -3,38 +3,56 @@ import { get, listGet, add, set } from "./accessors"
|
|||||||
export class Membre {
|
export class Membre {
|
||||||
id = 0
|
id = 0
|
||||||
|
|
||||||
nom = ""
|
lastname = ""
|
||||||
|
|
||||||
prenom = ""
|
firstname = ""
|
||||||
|
|
||||||
mail = ""
|
email = ""
|
||||||
|
|
||||||
telephone = ""
|
mobile = ""
|
||||||
|
|
||||||
photo = ""
|
photo = ""
|
||||||
|
|
||||||
alimentation = ""
|
food = ""
|
||||||
|
|
||||||
majeur = 1
|
adult = 1
|
||||||
|
|
||||||
privilege = 0
|
privileges = 0
|
||||||
|
|
||||||
actif = 0
|
active = 0
|
||||||
|
|
||||||
commentaire = ""
|
comment = ""
|
||||||
|
|
||||||
horodatage = ""
|
timestamp = ""
|
||||||
|
|
||||||
passe = ""
|
password = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const translationMember: { [k in keyof Membre]: string } = {
|
||||||
|
id: "id",
|
||||||
|
lastname: "nom",
|
||||||
|
firstname: "prenom",
|
||||||
|
email: "mail",
|
||||||
|
mobile: "telephone",
|
||||||
|
photo: "photo",
|
||||||
|
food: "alimentation",
|
||||||
|
adult: "majeur",
|
||||||
|
privileges: "privilege",
|
||||||
|
active: "actif",
|
||||||
|
comment: "commentaire",
|
||||||
|
timestamp: "horodatage",
|
||||||
|
password: "passe",
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementName = "Membre"
|
||||||
|
|
||||||
export const emailRegexp =
|
export const emailRegexp =
|
||||||
/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i
|
/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i
|
||||||
export const passwordMinLength = 4
|
export const passwordMinLength = 4
|
||||||
|
|
||||||
export interface MemberLogin {
|
export interface MemberLogin {
|
||||||
membre?: {
|
membre?: {
|
||||||
prenom: string
|
firstname: string
|
||||||
}
|
}
|
||||||
jwt?: string
|
jwt?: string
|
||||||
error?: string
|
error?: string
|
||||||
@ -42,10 +60,10 @@ export interface MemberLogin {
|
|||||||
|
|
||||||
export type MembreWithoutId = Omit<Membre, "id">
|
export type MembreWithoutId = Omit<Membre, "id">
|
||||||
|
|
||||||
export const membreGet = get<Membre>("Membre")
|
export const membreGet = get<Membre>(elementName, translationMember)
|
||||||
|
|
||||||
export const membreListGet = listGet<Membre>("Membre")
|
export const membreListGet = listGet<Membre>(elementName, translationMember)
|
||||||
|
|
||||||
export const membreAdd = add<MembreWithoutId, Membre>("Membre")
|
export const membreAdd = add<MembreWithoutId, Membre>(elementName, translationMember)
|
||||||
|
|
||||||
export const membreSet = set<Membre>("Membre")
|
export const membreSet = set<Membre>(elementName, translationMember)
|
||||||
|
39
src/services/preMembers.ts
Normal file
39
src/services/preMembers.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { get, listGet, add, set } from "./accessors"
|
||||||
|
|
||||||
|
export class PreMember {
|
||||||
|
id = 0
|
||||||
|
|
||||||
|
firstname = ""
|
||||||
|
|
||||||
|
lastname = ""
|
||||||
|
|
||||||
|
email = ""
|
||||||
|
|
||||||
|
mobile = ""
|
||||||
|
|
||||||
|
alreadyVolunteer = false
|
||||||
|
|
||||||
|
comment = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
export const translationPreMember: { [k in keyof PreMember]: string } = {
|
||||||
|
id: "id",
|
||||||
|
firstname: "prenom",
|
||||||
|
lastname: "nom",
|
||||||
|
email: "email",
|
||||||
|
mobile: "telephone",
|
||||||
|
alreadyVolunteer: "dejaBenevole",
|
||||||
|
comment: "commentaire",
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementName = "PreMember"
|
||||||
|
|
||||||
|
export type PreMemberWithoutId = Omit<PreMember, "id">
|
||||||
|
|
||||||
|
export const preMemberGet = get<PreMember>(elementName, translationPreMember)
|
||||||
|
|
||||||
|
export const preMemberListGet = listGet<PreMember>(elementName, translationPreMember)
|
||||||
|
|
||||||
|
export const preMemberAdd = add<PreMemberWithoutId, PreMember>(elementName, translationPreMember)
|
||||||
|
|
||||||
|
export const preMemberSet = set<PreMember>(elementName, translationPreMember)
|
@ -1,4 +1,5 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
import _ from "lodash"
|
||||||
|
|
||||||
import mockStore from "../../utils/mockStore"
|
import mockStore from "../../utils/mockStore"
|
||||||
import JeuJavList, {
|
import JeuJavList, {
|
||||||
@ -8,11 +9,12 @@ import JeuJavList, {
|
|||||||
getFailure,
|
getFailure,
|
||||||
fetchJeuJavList,
|
fetchJeuJavList,
|
||||||
} from "../jeuJavList"
|
} from "../jeuJavList"
|
||||||
|
import { JeuJav } from "../../services/jeuxJav"
|
||||||
|
|
||||||
jest.mock("axios")
|
jest.mock("axios")
|
||||||
|
|
||||||
const mockData = {
|
const mockFrenchData: any[] = [
|
||||||
"5": {
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
titre: "6 qui prend!",
|
titre: "6 qui prend!",
|
||||||
auteur: "Wolfgang Kramer",
|
auteur: "Wolfgang Kramer",
|
||||||
@ -22,16 +24,35 @@ const mockData = {
|
|||||||
duree: 45,
|
duree: 45,
|
||||||
type: "Ambiance",
|
type: "Ambiance",
|
||||||
poufpaf: "0-9-2/6-qui-prend-6-nimmt",
|
poufpaf: "0-9-2/6-qui-prend-6-nimmt",
|
||||||
photo: "https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
|
bggPhoto:
|
||||||
bggPhoto: "",
|
"https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
|
||||||
bggId: 432,
|
bggId: 432,
|
||||||
exemplaires: 1,
|
exemplaires: 1,
|
||||||
dispoPret: 1,
|
dispoPret: 1,
|
||||||
nonRangee: 0,
|
nonRangee: 0,
|
||||||
horodatage: "0000-00-00",
|
|
||||||
ean: "3421272101313",
|
ean: "3421272101313",
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
|
const mockEnglishData: JeuJav[] = [
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
title: "6 qui prend!",
|
||||||
|
author: "Wolfgang Kramer",
|
||||||
|
editor: "(uncredited) , Design Edge , B",
|
||||||
|
playersMin: 2,
|
||||||
|
playersMax: 10,
|
||||||
|
duration: 45,
|
||||||
|
type: "Ambiance",
|
||||||
|
poufpaf: "0-9-2/6-qui-prend-6-nimmt",
|
||||||
|
bggPhoto:
|
||||||
|
"https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
|
||||||
|
bggId: 432,
|
||||||
|
copies: 1,
|
||||||
|
lendAvailability: 1,
|
||||||
|
notStored: 0,
|
||||||
|
ean: "3421272101313",
|
||||||
|
},
|
||||||
|
]
|
||||||
const mockError = "Oops! Something went wrong."
|
const mockError = "Oops! Something went wrong."
|
||||||
|
|
||||||
describe("JeuJavList reducer", () => {
|
describe("JeuJavList reducer", () => {
|
||||||
@ -49,11 +70,11 @@ describe("JeuJavList reducer", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should handle success correctly", () => {
|
it("should handle success correctly", () => {
|
||||||
expect(JeuJavList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
|
expect(JeuJavList(undefined, { type: getSuccess.type, payload: mockEnglishData })).toEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
readyStatus: "success",
|
readyStatus: "success",
|
||||||
ids: [5],
|
ids: _.map(mockEnglishData, "id"),
|
||||||
entities: mockData,
|
entities: _.keyBy(mockEnglishData, "id"),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -70,12 +91,12 @@ describe("JeuJavList action", () => {
|
|||||||
it("fetches JeuJav list successful", async () => {
|
it("fetches JeuJav list successful", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type, payload: undefined },
|
||||||
{ type: getSuccess.type, payload: mockData },
|
{ type: getSuccess.type, payload: mockEnglishData },
|
||||||
]
|
]
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockResolvedValue({ data: mockData })
|
axios.get.mockResolvedValue({ data: mockFrenchData })
|
||||||
|
|
||||||
await dispatch(fetchJeuJavList())
|
await dispatch(fetchJeuJavList())
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
|
@ -2,10 +2,11 @@ import axios from "axios"
|
|||||||
|
|
||||||
import mockStore from "../../utils/mockStore"
|
import mockStore from "../../utils/mockStore"
|
||||||
import membre, { getRequesting, getSuccess, getFailure, fetchMembre, initialState } from "../membre"
|
import membre, { getRequesting, getSuccess, getFailure, fetchMembre, initialState } from "../membre"
|
||||||
|
import { Membre } from "../../services/membres"
|
||||||
|
|
||||||
jest.mock("axios")
|
jest.mock("axios")
|
||||||
|
|
||||||
const mockData = {
|
const mockFrenchData: any = {
|
||||||
id: 1,
|
id: 1,
|
||||||
nom: "Aupeix",
|
nom: "Aupeix",
|
||||||
prenom: "Amélie",
|
prenom: "Amélie",
|
||||||
@ -20,7 +21,23 @@ const mockData = {
|
|||||||
horodatage: "0000-00-00",
|
horodatage: "0000-00-00",
|
||||||
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
||||||
}
|
}
|
||||||
const { id } = mockData
|
|
||||||
|
const mockEnglishData: Membre = {
|
||||||
|
id: 1,
|
||||||
|
lastname: "Aupeix",
|
||||||
|
firstname: "Amélie",
|
||||||
|
email: "pakouille.lakouille@yahoo.fr",
|
||||||
|
mobile: "0675650392",
|
||||||
|
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
||||||
|
food: "Végétarien",
|
||||||
|
adult: 1,
|
||||||
|
privileges: 0,
|
||||||
|
active: 0,
|
||||||
|
comment: "",
|
||||||
|
timestamp: "0000-00-00",
|
||||||
|
password: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
||||||
|
}
|
||||||
|
const { id } = mockEnglishData
|
||||||
const mockError = "Oops! Something went wrong."
|
const mockError = "Oops! Something went wrong."
|
||||||
|
|
||||||
describe("membre reducer", () => {
|
describe("membre reducer", () => {
|
||||||
@ -39,9 +56,9 @@ describe("membre reducer", () => {
|
|||||||
expect(
|
expect(
|
||||||
membre(undefined, {
|
membre(undefined, {
|
||||||
type: getSuccess.type,
|
type: getSuccess.type,
|
||||||
payload: mockData,
|
payload: mockEnglishData,
|
||||||
})
|
})
|
||||||
).toEqual({ readyStatus: "success", entity: mockData })
|
).toEqual({ readyStatus: "success", entity: mockEnglishData })
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle failure correctly", () => {
|
it("should handle failure correctly", () => {
|
||||||
@ -58,12 +75,12 @@ describe("membre action", () => {
|
|||||||
it("fetches membre data successful", async () => {
|
it("fetches membre data successful", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type, payload: undefined },
|
||||||
{ type: getSuccess.type, payload: mockData },
|
{ type: getSuccess.type, payload: mockEnglishData },
|
||||||
]
|
]
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockResolvedValue({ data: mockData })
|
axios.get.mockResolvedValue({ data: mockFrenchData })
|
||||||
|
|
||||||
await dispatch(fetchMembre(id))
|
await dispatch(fetchMembre(id))
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
import _ from "lodash"
|
||||||
|
|
||||||
import mockStore from "../../utils/mockStore"
|
import mockStore from "../../utils/mockStore"
|
||||||
import membreList, {
|
import membreList, {
|
||||||
@ -8,11 +9,12 @@ import membreList, {
|
|||||||
getFailure,
|
getFailure,
|
||||||
fetchMembreList,
|
fetchMembreList,
|
||||||
} from "../membreList"
|
} from "../membreList"
|
||||||
|
import { Membre } from "../../services/membres"
|
||||||
|
|
||||||
jest.mock("axios")
|
jest.mock("axios")
|
||||||
|
|
||||||
const mockData = {
|
const mockFrenchData: any[] = [
|
||||||
"1": {
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
nom: "Aupeix",
|
nom: "Aupeix",
|
||||||
prenom: "Amélie",
|
prenom: "Amélie",
|
||||||
@ -27,7 +29,25 @@ const mockData = {
|
|||||||
horodatage: "0000-00-00",
|
horodatage: "0000-00-00",
|
||||||
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
|
|
||||||
|
const mockEnglishData: Membre[] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
lastname: "Aupeix",
|
||||||
|
firstname: "Amélie",
|
||||||
|
email: "pakouille.lakouille@yahoo.fr",
|
||||||
|
mobile: "0675650392",
|
||||||
|
photo: "images/membres/$taille/amélie_aupeix.jpg",
|
||||||
|
food: "Végétarien",
|
||||||
|
adult: 1,
|
||||||
|
privileges: 0,
|
||||||
|
active: 0,
|
||||||
|
comment: "",
|
||||||
|
timestamp: "0000-00-00",
|
||||||
|
password: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
|
||||||
|
},
|
||||||
|
]
|
||||||
const mockError = "Oops! Something went wrong."
|
const mockError = "Oops! Something went wrong."
|
||||||
|
|
||||||
describe("membreList reducer", () => {
|
describe("membreList reducer", () => {
|
||||||
@ -45,11 +65,11 @@ describe("membreList reducer", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should handle success correctly", () => {
|
it("should handle success correctly", () => {
|
||||||
expect(membreList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
|
expect(membreList(undefined, { type: getSuccess.type, payload: mockEnglishData })).toEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
readyStatus: "success",
|
readyStatus: "success",
|
||||||
ids: [1],
|
ids: _.map(mockEnglishData, "id"),
|
||||||
entities: mockData,
|
entities: _.keyBy(mockEnglishData, "id"),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -66,12 +86,12 @@ describe("membreList action", () => {
|
|||||||
it("fetches membre list successful", async () => {
|
it("fetches membre list successful", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type, payload: undefined },
|
||||||
{ type: getSuccess.type, payload: mockData },
|
{ type: getSuccess.type, payload: mockEnglishData },
|
||||||
]
|
]
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockResolvedValue({ data: mockData })
|
axios.get.mockResolvedValue({ data: mockFrenchData })
|
||||||
|
|
||||||
await dispatch(fetchMembreList())
|
await dispatch(fetchMembreList())
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
|
38
src/store/preMemberAdd.ts
Normal file
38
src/store/preMemberAdd.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
|
||||||
|
|
||||||
|
import { StateRequest, elementAddFetch } from "./utils"
|
||||||
|
import { PreMember, preMemberAdd } from "../services/preMembers"
|
||||||
|
|
||||||
|
const preMemberAdapter = createEntityAdapter<PreMember>()
|
||||||
|
|
||||||
|
const preMemberAddSlice = createSlice({
|
||||||
|
name: "addPreMember",
|
||||||
|
initialState: preMemberAdapter.getInitialState({
|
||||||
|
readyStatus: "idle",
|
||||||
|
} as StateRequest),
|
||||||
|
reducers: {
|
||||||
|
getRequesting: (state) => {
|
||||||
|
state.readyStatus = "request"
|
||||||
|
},
|
||||||
|
getSuccess: (state, { payload }: PayloadAction<PreMember>) => {
|
||||||
|
state.readyStatus = "success"
|
||||||
|
preMemberAdapter.addOne(state, payload)
|
||||||
|
},
|
||||||
|
getFailure: (state, { payload }: PayloadAction<string>) => {
|
||||||
|
state.readyStatus = "failure"
|
||||||
|
state.error = payload
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default preMemberAddSlice.reducer
|
||||||
|
export const { getRequesting, getSuccess, getFailure } = preMemberAddSlice.actions
|
||||||
|
|
||||||
|
export const fetchPreMemberAdd = elementAddFetch(
|
||||||
|
preMemberAdd,
|
||||||
|
getRequesting,
|
||||||
|
getSuccess,
|
||||||
|
getFailure,
|
||||||
|
() => null,
|
||||||
|
() => null
|
||||||
|
)
|
@ -8,6 +8,7 @@ import membre from "./membre"
|
|||||||
import membreAdd from "./membreAdd"
|
import membreAdd from "./membreAdd"
|
||||||
import membreList from "./membreList"
|
import membreList from "./membreList"
|
||||||
import membreSet from "./membreSet"
|
import membreSet from "./membreSet"
|
||||||
|
import preMemberAdd from "./preMemberAdd"
|
||||||
|
|
||||||
// Use inferred return type for making correctly Redux types
|
// Use inferred return type for making correctly Redux types
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
@ -19,6 +20,7 @@ export default (history: History) => ({
|
|||||||
membreAdd,
|
membreAdd,
|
||||||
membreList,
|
membreList,
|
||||||
membreSet,
|
membreSet,
|
||||||
|
preMemberAdd,
|
||||||
router: connectRouter(history) as any,
|
router: connectRouter(history) as any,
|
||||||
// Register more reducers...
|
// Register more reducers...
|
||||||
})
|
})
|
||||||
|
@ -23,7 +23,7 @@ export function toastError(message: string): void {
|
|||||||
export function toastSuccess(message: string): void {
|
export function toastSuccess(message: string): void {
|
||||||
toast.success(message, {
|
toast.success(message, {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
autoClose: 3000,
|
autoClose: 5000,
|
||||||
hideProgressBar: true,
|
hideProgressBar: true,
|
||||||
closeOnClick: true,
|
closeOnClick: true,
|
||||||
pauseOnHover: true,
|
pauseOnHover: true,
|
||||||
|
@ -31,6 +31,7 @@ const config: Configuration = {
|
|||||||
}),
|
}),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
localStorage: { getItem: () => null, setItem: () => null, removeItem: () => null },
|
localStorage: { getItem: () => null, setItem: () => null, removeItem: () => null },
|
||||||
|
"location.protocol": "http:",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user