diff --git a/src/components/Asks/AskMeals.tsx b/src/components/Asks/AskMeals.tsx new file mode 100644 index 0000000..65ba699 --- /dev/null +++ b/src/components/Asks/AskMeals.tsx @@ -0,0 +1,38 @@ +import { get } from "lodash" +import { useCallback } from "react" +import { fetchVolunteerAsksSet } from "../../store/volunteerAsksSet" +import { useAskTools, addAsk, answerLaterOnProfile } from "./utils" +import MealsForm, { fetchFor as fetchForMealsForm } from "../VolunteerBoard/MealsForm/MealsForm" +import { useUserMeals } from "../VolunteerBoard/meals.utils" + +export function AskMeals(asks: JSX.Element[], id: number): void { + const { dispatch, jwtToken, volunteerAsks } = useAskTools() + + const onSubmit = useCallback((): void => { + dispatch( + fetchVolunteerAsksSet(jwtToken, 0, { + hiddenAsks: [...(volunteerAsks?.hiddenAsks || []), id], + }) + ) + }, [dispatch, id, jwtToken, volunteerAsks?.hiddenAsks]) + + const [meals] = useUserMeals() + const needsMeals = get(meals, "needsMeals", false) + const canHostCount = get(meals, "canHostCount", 0) + const distanceToFestival = get(meals, "distanceToFestival", 0) + const mealsComment = get(meals, "mealsComment", "") + const needToShow = + !needsMeals && canHostCount === 0 && distanceToFestival === 0 && mealsComment === "" + + addAsk( + asks, + id, + volunteerAsks, + false, + needToShow, + {answerLaterOnProfile} + ) +} + +// Fetch server-side data here +export const fetchFor = [...fetchForMealsForm] diff --git a/src/components/Asks/index.tsx b/src/components/Asks/index.tsx index 028a02c..7aad7b0 100644 --- a/src/components/Asks/index.tsx +++ b/src/components/Asks/index.tsx @@ -6,6 +6,7 @@ import { AskWelcome } from "./AskWelcome" import { AskDiscord, fetchFor as fetchForDiscord } from "./AskDiscord" import { AskDayWishes, fetchFor as fetchForDayWishes } from "./AskDayWishes" import { AskHosting, fetchFor as fetchForHosting } from "./AskHosting" +import { AskMeals, fetchFor as fetchForMeals } from "./AskMeals" import { AskTeamWishes, fetchFor as fetchForTeamWishes } from "./AskTeamWishes" import { AskParticipationDetails, @@ -24,6 +25,7 @@ const Asks = (): JSX.Element | null => { AskTeamWishes(asks, 11) AskParticipationDetails(asks, 12) AskHosting(asks, 20) + AskMeals(asks, 22) AskPushNotif(asks, 99) @@ -61,6 +63,7 @@ export const fetchFor = [ ...fetchForDiscord, ...fetchForDayWishes, ...fetchForHosting, + ...fetchForMeals, ...fetchForTeamWishes, ...fetchForParticipationDetails, ] diff --git a/src/components/RegisterForm/index.tsx b/src/components/RegisterForm/index.tsx index 260f49d..5bcb36a 100644 --- a/src/components/RegisterForm/index.tsx +++ b/src/components/RegisterForm/index.tsx @@ -55,6 +55,8 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => { const meetingDateList = useSelector(selectMiscMeetingDateList) + const enableRegistering = false + useEffect(() => { const timer = setInterval(() => { setChangingBackground((changingBackground + 1) % animations.length) @@ -234,20 +236,33 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => {

-
- Si l'expérience vous tente, remplissez le formulaire suivant pour devenir - bénévole !
- Vous pouvez aussi juste nous rencontrer avant de vous décider à devenir bénévole, on - comprend qu'un saut pareil dans l'inconnu soit difficile. -
- Dans les deux cas, venez rencontrer une poignée d'entre nous dans un bar/resto près - de Châtelet ! :) Sur inscription uniquement... -
-
+ + {!enableRegistering && ( +
+ L'inscription est clôturée pour l'édition 2022, mais si l'expérience vous tente, + remplissez le formulaire suivant pour devenir bénévole à PeL 2023 !
+ Dès septembre on se rencontrera sur Paris en petits groupes pour discuter du + festival, du bénévolat et surtout faire connaissance :) +
+
+ )} + + {enableRegistering && ( +
+ Si l'expérience vous tente, remplissez le formulaire suivant pour devenir + bénévole !
+ Vous pouvez aussi juste nous rencontrer avant de vous décider à devenir + bénévole, on comprend qu'un saut pareil dans l'inconnu soit difficile. +
+ Dans les deux cas, venez rencontrer une poignée d'entre nous dans un bar/resto + près de Châtelet ! :) Sur inscription uniquement... +
+
+ )} ) - const potentialVolunteerQuestion = ( + const potentialVolunteerQuestion = enableRegistering && (
Je veux devenir bénévole :
@@ -431,7 +446,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => { ) - const meeting = ( + const meeting = enableRegistering && ( <>
{!potentialVolunteer &&
Faisons connaissance !
} @@ -535,7 +550,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => { ) - const helpBefore = !potentialVolunteer && ( + const helpBefore = enableRegistering && !potentialVolunteer && ( <>
Bénévolat en amont du festival
@@ -608,7 +623,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => { ) - const pelMemberQuestion = !potentialVolunteer && ( + const pelMemberQuestion = enableRegistering && !potentialVolunteer && ( <>
Association Paris est Ludique
@@ -784,7 +799,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => { {(potentialVolunteer || !alreadyVolunteer) && ( <> - {commentQuestion} + {enableRegistering && commentQuestion} {cameAsVisitor} {meeting} {helpBefore} @@ -792,6 +807,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => { {(potentialVolunteer || pelMember) && ( <> {nameMobileEmail} + {!enableRegistering && commentQuestion} {howToContact !== "Aucun" && submitButton} )} diff --git a/src/components/VolunteerBoard/Board.tsx b/src/components/VolunteerBoard/Board.tsx index 79ba71f..678c246 100644 --- a/src/components/VolunteerBoard/Board.tsx +++ b/src/components/VolunteerBoard/Board.tsx @@ -3,6 +3,8 @@ import DayWishes from "./DayWishes/DayWishes" import DayWishesFormModal from "./DayWishesForm/DayWishesFormModal" import Hosting from "./Hosting/Hosting" import HostingFormModal from "./HostingForm/HostingFormModal" +import Meals from "./Meals/Meals" +import MealsFormModal from "./MealsForm/MealsFormModal" import ParticipationDetails from "./ParticipationDetails/ParticipationDetails" import ParticipationDetailsFormModal from "./ParticipationDetailsForm/ParticipationDetailsFormModal" import TeamWishes from "./TeamWishes/TeamWishes" @@ -11,6 +13,7 @@ import withUserConnected from "../../utils/withUserConnected" import ContentTitle from "../ui/Content/ContentTitle" import { fetchFor as fetchForDayWishesForm } from "./DayWishesForm/DayWishesForm" import { fetchFor as fetchForHostingForm } from "./HostingForm/HostingForm" +import { fetchFor as fetchForMealsForm } from "./MealsForm/MealsForm" import { fetchFor as fetchForParticipationDetailsForm } from "./ParticipationDetailsForm/ParticipationDetailsForm" import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm" import VolunteerTeam from "./VolunteerTeam/VolunteerTeam" @@ -27,6 +30,8 @@ const Board: FC = (): JSX.Element => ( + + ) @@ -35,6 +40,7 @@ export default memo(withUserConnected(Board)) export const fetchFor = [ ...fetchForDayWishesForm, ...fetchForHostingForm, + ...fetchForMealsForm, ...fetchForParticipationDetailsForm, ...fetchForTeamWishesForm, ] diff --git a/src/components/VolunteerBoard/Meals/Meals.tsx b/src/components/VolunteerBoard/Meals/Meals.tsx new file mode 100644 index 0000000..fd6e155 --- /dev/null +++ b/src/components/VolunteerBoard/Meals/Meals.tsx @@ -0,0 +1,65 @@ +import { FC, memo, useCallback } from "react" +import { find, get } from "lodash" +import styles from "./styles.module.scss" +import { useUserMeals, mealDays, MealOption } from "../meals.utils" +import useAction from "../../../utils/useAction" +import { displayModal, MODAL_IDS } from "../../../store/ui" +import { useUserDayWishes } from "../daysWishes.utils" + +const Meals: FC = (): JSX.Element | null => { + const [userMeals] = useUserMeals() + const [userWishes] = useUserDayWishes() + const meals = get(userMeals, "meals", []) + const dayWishesString = get(userWishes, "dayWishes", []) + const execDisplayModal = useAction(displayModal) + const onEdit = useCallback(() => execDisplayModal(MODAL_IDS.MEALS), [execDisplayModal]) + const mealChoices = mealDays.map((meal, i: number) => + find(meal.options, { abbr: meals[i] || "" }) + ) as MealOption[] + + function getMealElement(i: number): JSX.Element { + const mealChoice = mealChoices[i] + return ( +
+ {mealDays[i].name}, {mealChoice.title} +
+ ) + } + + return ( +
+
Mes repas
+ {dayWishesString.includes("S") ? ( + <> + {getMealElement(0)} +
+ Samedi soir, apéro dînatoire +
+ + ) : ( +
+ Non bénévole le samedi +
+ )} + + {dayWishesString.includes("D") ? ( + <> + {getMealElement(1)} + {getMealElement(2)} + + ) : ( +
+ Non bénévole le dimanche +
+ )} + +
+ +
+
+ ) +} + +export default memo(Meals) diff --git a/src/components/VolunteerBoard/Meals/styles.module.scss b/src/components/VolunteerBoard/Meals/styles.module.scss new file mode 100755 index 0000000..a81d4f0 --- /dev/null +++ b/src/components/VolunteerBoard/Meals/styles.module.scss @@ -0,0 +1,53 @@ +@import "../../../theme/variables"; +@import "../../../theme/mixins"; + +.title { + padding-bottom: 10px; + font-weight: bold; +} + +.mealsLabel { + margin-right: 5px; + font-style: bold; +} + +.meals { + @include inner-content-wrapper(); + + position: relative; + padding-right: 90px; +} + +.mealsLabel, +.commentLine { + margin-bottom: 5px; + span { + display: inline-block; + } +} + +.lineEmpty { + color: $color-red; + font-style: italic; +} + +.commentLineTitle { + padding-right: 5px; +} + +.commentLineText { + font-style: italic; +} + +.editButton { + @include vertical-center(); + + position: absolute; + right: 20px; + + button { + color: $color-green; + font-weight: bold; + cursor: pointer; + } +} diff --git a/src/components/VolunteerBoard/MealsForm/MealsForm.tsx b/src/components/VolunteerBoard/MealsForm/MealsForm.tsx new file mode 100644 index 0000000..122d941 --- /dev/null +++ b/src/components/VolunteerBoard/MealsForm/MealsForm.tsx @@ -0,0 +1,152 @@ +import { get } from "lodash" +import { FC, memo, ReactNode, useCallback, useEffect, useState } from "react" +import classnames from "classnames" +import styles from "./styles.module.scss" +import { mealDays, MealOption, useUserMeals } from "../meals.utils" +import FormButton from "../../Form/FormButton/FormButton" +import { fetchVolunteerMealsSetIfNeed } from "../../../store/volunteerMealsSet" +import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton" +import { useUserDayWishes } from "../daysWishes.utils" +import { fetchVolunteerDayWishesSetIfNeed } from "../../../store/volunteerDayWishesSet" + +type Props = { + children?: ReactNode | undefined + afterSubmit?: () => void | undefined +} + +const MealsForm: FC = ({ children, afterSubmit }): JSX.Element => { + const [saturdayLunchMeal, setSaturdayLunchMeal] = useState("") + const [sundayLunchMeal, setSundayLunchMeal] = useState("") + const [sundayDinnerMeal, setSundayDinnerMeal] = useState("") + const [userMeals, saveMeals] = useUserMeals() + const [userWishes] = useUserDayWishes() + const meals = get(userMeals, "meals", []) + const dayWishesString = get(userWishes, "dayWishes", []) + + useEffect(() => { + setSaturdayLunchMeal(meals[0] || "") + setSundayLunchMeal(meals[1] || "") + setSundayDinnerMeal(meals[2] || "") + }, [meals]) + + const onChoiceSubmit = useCallback(() => { + saveMeals([saturdayLunchMeal, sundayLunchMeal, sundayDinnerMeal]) + if (afterSubmit) afterSubmit() + }, [saveMeals, saturdayLunchMeal, sundayLunchMeal, sundayDinnerMeal, afterSubmit]) + + const getBreakfeastElement = (dayName: string): JSX.Element => ( +
+ {dayName} matin, petit dej à 8h avec jus de pomme, multifruit, café, brioches et + quatre-quarts, crêpes si bénévoles motivés. +
+ ) + + const getMealElement = (i: number, meal: string, setMeal: (m: string) => void): JSX.Element => ( +
+
+
+ {mealDays[i].name} + {i === 0 && <>, accompagné d'un délicieux brownie tout chocolat} + {i === 1 && ( + <>, accompagné du même brownie. Enfin, un autre que celui de la veille + )}{" "} + : +
+
+
+ {mealDays[i].options.map((option: MealOption) => ( + + ))} +
+
+ ) + + const getNotVolunteerElement = (dayName: string): JSX.Element => ( +
+ {dayName} matin/midi/soir, comme tu n'es pas bénévole ce jour-là, on a rien + prévu. Mais{" "} + + contacte-nous + {" "} + si tu veux qu'on te prévoie un dîner.{" "} + {dayName === "Dimanche" && ( + <> + Surtout dimanche soir si tu redeviens bénévole pour nous aider à ranger un peu + le festival ! + + )} +
+ ) + + return ( +
+
Mes repas
+ {dayWishesString.includes("S") ? ( + <> + {getBreakfeastElement("Samedi")} + {getMealElement(0, saturdayLunchMeal, setSaturdayLunchMeal)} +
+ Samedi soir, apéro dînatoire +
+ + ) : ( + getNotVolunteerElement("Samedi") + )} +
+
+
+ {dayWishesString.includes("D") ? ( + <> + {getBreakfeastElement("Dimanche")} + {getMealElement(1, sundayLunchMeal, setSundayLunchMeal)} + {getMealElement(2, sundayDinnerMeal, setSundayDinnerMeal)} + + ) : ( + getNotVolunteerElement("Dimanche") + )} + +
+
+ Jeudi, vendredi et lundi, chacun improvise. Peut-être resto à proximité. +
+
+
+ Enregistrer + {children === undefined && ( + <> + {" "} + + Annuler + {" "} + + )} + {children !== undefined && ( + <> + {" "} + + {children} + {" "} + + )} +
+
+ ) +} + +MealsForm.defaultProps = { + children: undefined, + afterSubmit: undefined, +} + +export default memo(MealsForm) + +// Fetch server-side data here +export const fetchFor = [fetchVolunteerMealsSetIfNeed, fetchVolunteerDayWishesSetIfNeed] diff --git a/src/components/VolunteerBoard/MealsForm/MealsFormModal.tsx b/src/components/VolunteerBoard/MealsForm/MealsFormModal.tsx new file mode 100644 index 0000000..12bc91f --- /dev/null +++ b/src/components/VolunteerBoard/MealsForm/MealsFormModal.tsx @@ -0,0 +1,18 @@ +import { FC, memo, useCallback } from "react" +import { hideModal, MODAL_IDS } from "../../../store/ui" +import Modal from "../../Modal/Modal" +import useAction from "../../../utils/useAction" +import MealsForm from "./MealsForm" + +const MealsFormModal: FC = (): JSX.Element => { + const execHideModal = useAction(hideModal) + const afterFormSubmit = useCallback(() => execHideModal(), [execHideModal]) + + return ( + + + + ) +} + +export default memo(MealsFormModal) diff --git a/src/components/VolunteerBoard/MealsForm/styles.module.scss b/src/components/VolunteerBoard/MealsForm/styles.module.scss new file mode 100755 index 0000000..7b76bbe --- /dev/null +++ b/src/components/VolunteerBoard/MealsForm/styles.module.scss @@ -0,0 +1,122 @@ +@import "../../../theme/variables"; +@import "../../../theme/mixins"; + +.title { + padding: 15px 0; + font-weight: bold; + text-align: center; +} + +.inputWrapper { + margin: 25px 0; + + @include desktop { + display: flex; + } +} + +.leftCol { + flex: 0 0 320px; +} + +.rightCol { + width: 100%; + text-align: center; +} + +.needsMealsTitle { + display: inline-block; + width: 320px; + margin-bottom: 10px; +} + +.mealsLabel { + text-align: left; + display: inline-block; + margin-bottom: 10px; + width: 220px; +} + +.canHostCountTitle { + display: inline-block; + width: 320px; + margin-bottom: 10px; +} + +.canHostCountLabel { + text-align: left; + display: inline-block; + margin-bottom: 10px; + width: 80px; +} + +.distanceToFestivalTitle { + display: inline-block; + width: 320px; + margin-bottom: 10px; +} + +.distanceToFestivalLabel { + text-align: left; + display: inline-block; + margin-bottom: 10px; + width: 80px; +} + +.mealsTitle { + display: inline-block; + width: 320px; + margin-bottom: 10px; +} + +.mealsList { + @include clear-ul-style; + + display: inline-block; + width: 204px; + text-align: center; +} + +.mealsItem { + display: inline-block; + margin: 3px; +} + +.mealsButton { + margin: 0; + padding: 7px 2px 6px; + border: 0; + border-radius: 0; + width: 90px; + text-align: center; + color: $color-grey-dark; + background-color: $color-grey-light; + cursor: pointer; + + &.active { + color: $color-yellow; + background-color: $color-black; + } +} + +.mealsCommentWrapper { + margin: 6px 0 14px; + + label { + display: block; + padding: 6px 0 2px 4px; + } + textarea { + width: 100%; + height: 50px; + padding: 5px; + border: 1px solid $color-grey-light; + background-color: $color-grey-lighter; + outline: 0; + } +} + +.buttonWrapper { + margin-bottom: 10px; + text-align: center; +} diff --git a/src/components/VolunteerBoard/hosting.utils.ts b/src/components/VolunteerBoard/hosting.utils.ts index aea33ad..dd0179e 100644 --- a/src/components/VolunteerBoard/hosting.utils.ts +++ b/src/components/VolunteerBoard/hosting.utils.ts @@ -4,8 +4,16 @@ import { selectUserJwtToken } from "../../store/auth" import { AppState } from "../../store" import { fetchVolunteerHostingSet } from "../../store/volunteerHostingSet" import useAction from "../../utils/useAction" +import { VolunteerHosting } from "../../services/volunteers" -export const useUserHosting = (): [any, any] => { +type SetFunction = ( + needsHosting: VolunteerHosting["needsHosting"], + canHostCount: VolunteerHosting["canHostCount"], + distanceToFestival: VolunteerHosting["distanceToFestival"], + hostingComment: VolunteerHosting["hostingComment"] +) => void + +export const useUserHosting = (): [VolunteerHosting | undefined, SetFunction] => { const save = useAction(fetchVolunteerHostingSet) const jwtToken = useSelector(selectUserJwtToken) const userWishes = useSelector( diff --git a/src/components/VolunteerBoard/meals.utils.ts b/src/components/VolunteerBoard/meals.utils.ts new file mode 100644 index 0000000..9c8b978 --- /dev/null +++ b/src/components/VolunteerBoard/meals.utils.ts @@ -0,0 +1,69 @@ +import { shallowEqual, useSelector } from "react-redux" +import { useCallback } from "react" +import { selectUserJwtToken } from "../../store/auth" +import { AppState } from "../../store" +import { fetchVolunteerMealsSet } from "../../store/volunteerMealsSet" +import useAction from "../../utils/useAction" +import { VolunteerMeals } from "../../services/volunteers" + +export type MealOption = { abbr: string; title: string } +export type MealDay = { + name: string + options: MealOption[] +} + +export const mealDays: MealDay[] = [ + { + name: "Samedi midi", + options: [ + { abbr: "V", title: "Sandwich végétarien" }, + { abbr: "F", title: "Sandwich fromage" }, + { abbr: "P", title: "Sandwich poulet" }, + { abbr: "", title: "Pas de repas" }, + ], + }, + { + name: "Dimanche midi", + options: [ + { abbr: "V", title: "Sandwich végétarien" }, + { abbr: "F", title: "Sandwich fromage" }, + { abbr: "P", title: "Sandwich poulet" }, + { abbr: "", title: "Pas de repas" }, + ], + }, + { + name: "Dimanche soir", + options: [ + { + abbr: "V", + title: "Lasagnes végétariennes accompagnées de ratatouille et haricots verts", + }, + { abbr: "P", title: "Aiguillettes de poulet accompagnées de riz thaï" }, + { abbr: "", title: "Pas de repas" }, + ], + }, +] + +type SetFunction = (meals: VolunteerMeals["meals"]) => void + +export const useUserMeals = (): [VolunteerMeals | undefined, SetFunction] => { + const save = useAction(fetchVolunteerMealsSet) + const jwtToken = useSelector(selectUserJwtToken) + const userWishes = useSelector( + (state: AppState) => state.volunteerMealsSet?.entity, + shallowEqual + ) + + const saveWishes = useCallback( + (meals) => { + if (!userWishes) return + save(jwtToken, 0, { + id: userWishes.id, + meals, + }) + }, + [userWishes, save, jwtToken] + ) + + return [userWishes, saveWishes] +} diff --git a/src/server/gsheets/postulants.ts b/src/server/gsheets/postulants.ts index e7b1322..2bf8782 100644 --- a/src/server/gsheets/postulants.ts +++ b/src/server/gsheets/postulants.ts @@ -71,8 +71,8 @@ async function sendMeetingEmail( to: email, from: "contact@parisestludique.fr", subject: "Première rencontre Paris est Ludique", - text: `Salut ${firstname},\n\nNous allons te contacter prochainement pour trouver ensemble un moyen de se rencontrer.\n\nÀ bientôt :)\nPierre`, - html: `Salut ${firstname},

Nous allons te contacter prochainement pour trouver ensemble un moyen de se rencontrer.

À bientôt :)
Pierre`, + text: `Salut ${firstname},\n\nTon inscription est bien prise en compte !\n\nNous te contacterons pour trouver un moyen de se rencontrer.\n\nÀ bientôt :)\nPierre`, + html: `Salut ${firstname},

Ton inscription est bien prise en compte !

Nous te contacterons pour trouver un moyen de se rencontrer.

À bientôt :)
Pierre`, } await sgMail.send(msg) } diff --git a/src/server/gsheets/volunteers.ts b/src/server/gsheets/volunteers.ts index 1822a59..1ca81da 100644 --- a/src/server/gsheets/volunteers.ts +++ b/src/server/gsheets/volunteers.ts @@ -12,6 +12,7 @@ import { translationVolunteer, VolunteerDayWishes, VolunteerHosting, + VolunteerMeals, VolunteerParticipationDetails, VolunteerTeamAssign, VolunteerKnowledge, @@ -362,6 +363,30 @@ export const volunteerHostingSet = expressAccessor.set(async (list, body, id) => } }) +export const volunteerMealsSet = expressAccessor.set(async (list, body, id) => { + const requestedId = +body[0] || id + if (requestedId !== id && requestedId !== 0) { + throw Error(`On ne peut acceder qu'à ses propres repas`) + } + const wishes = body[1] as VolunteerMeals + const volunteer: Volunteer | undefined = list.find((v) => v.id === requestedId) + if (!volunteer) { + throw Error(`Il n'y a aucun bénévole avec cet identifiant ${requestedId}`) + } + const newVolunteer = cloneDeep(volunteer) + + if (wishes.meals !== undefined) { + newVolunteer.meals = wishes.meals + } + + return { + toDatabase: newVolunteer, + toCaller: { + id: newVolunteer.id, + meals: newVolunteer.meals, + } as VolunteerMeals, + } +}) export const volunteerParticipationDetailsSet = expressAccessor.set(async (list, body, id) => { const requestedId = +body[0] || id if (requestedId !== id && requestedId !== 0) { diff --git a/src/server/index.ts b/src/server/index.ts index b7e050f..32c1274 100755 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -27,9 +27,9 @@ import { volunteerDayWishesSet, volunteerForgot, volunteerHostingSet, + volunteerMealsSet, volunteerDiscordId, volunteerLogin, - volunteerPartialAdd, volunteerParticipationDetailsSet, volunteerSet, volunteerTeamWishesSet, @@ -94,7 +94,7 @@ app.get("/MiscMeetingDateListGet", miscMeetingDateListGet) app.get("/WishListGet", wishListGet) app.post("/WishAdd", wishAdd) app.post("/PostulantAdd", postulantAdd) -app.post("/VolunteerPartialAdd", volunteerPartialAdd) +// Disabling registration app.post("/VolunteerPartialAdd", volunteerPartialAdd) app.post("/VolunteerLogin", volunteerLogin) app.post("/VolunteerForgot", volunteerForgot) app.get("/VolunteerListGet", secure as RequestHandler, volunteerListGet) @@ -113,6 +113,7 @@ app.post( ) app.post("/VolunteerDayWishesSet", secure as RequestHandler, volunteerDayWishesSet) app.post("/VolunteerHostingSet", secure as RequestHandler, volunteerHostingSet) +app.post("/VolunteerMealsSet", secure as RequestHandler, volunteerMealsSet) app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet) app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet) diff --git a/src/services/volunteers.ts b/src/services/volunteers.ts index 6715c5b..b6f7511 100644 --- a/src/services/volunteers.ts +++ b/src/services/volunteers.ts @@ -67,6 +67,8 @@ export class Volunteer implements VolunteerPartial { distanceToFestival = 0 hostingComment = "" + + meals: string[] = [] } export const translationVolunteer: { [k in keyof Volunteer]: string } = { @@ -104,6 +106,7 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = { canHostCount: "nombreHébergés", distanceToFestival: "distanceAuFestival", hostingComment: "commentaireHébergement", + meals: "repas", } export class VolunteerPartial { @@ -153,6 +156,7 @@ export const volunteerExample: Volunteer = { canHostCount: 0, distanceToFestival: 0, hostingComment: "", + meals: [], } export const emailRegexp = @@ -205,6 +209,11 @@ export interface VolunteerHosting { hostingComment: Volunteer["hostingComment"] } +export interface VolunteerMeals { + id: Volunteer["id"] + meals: Volunteer["meals"] +} + export interface VolunteerParticipationDetails { id: Volunteer["id"] tshirtSize: Volunteer["tshirtSize"] diff --git a/src/services/volunteersAccessors.ts b/src/services/volunteersAccessors.ts index dbb1efe..40a963e 100644 --- a/src/services/volunteersAccessors.ts +++ b/src/services/volunteersAccessors.ts @@ -11,6 +11,7 @@ import { VolunteerWithoutId, VolunteerDiscordId, VolunteerKnowledge, + VolunteerMeals, } from "./volunteers" const serviceAccessors = new ServiceAccessors(elementName) @@ -42,6 +43,9 @@ export const volunteerDayWishesSet = export const volunteerHostingSet = serviceAccessors.securedCustomPost<[number, Partial]>("HostingSet") +export const volunteerMealsSet = + serviceAccessors.securedCustomPost<[number, Partial]>("MealsSet") + export const volunteerParticipationDetailsSet = serviceAccessors.securedCustomPost<[number, Partial]>( "ParticipationDetailsSet" diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts index 0bc15d4..7642271 100644 --- a/src/store/rootReducer.ts +++ b/src/store/rootReducer.ts @@ -17,6 +17,7 @@ import volunteerDayWishesSet from "./volunteerDayWishesSet" import volunteerDiscordId from "./volunteerDiscordId" import volunteerForgot from "./volunteerForgot" import volunteerHostingSet from "./volunteerHostingSet" +import volunteerMealsSet from "./volunteerMealsSet" import volunteerList from "./volunteerList" import volunteerLogin from "./volunteerLogin" import volunteerKnowledgeSet from "./volunteerKnowledgeSet" @@ -46,6 +47,7 @@ export default (history: History) => ({ volunteerDiscordId, volunteerForgot, volunteerHostingSet, + volunteerMealsSet, volunteerList, volunteerLogin, volunteerKnowledgeSet, diff --git a/src/store/ui.ts b/src/store/ui.ts index f97b6fa..2de7700 100644 --- a/src/store/ui.ts +++ b/src/store/ui.ts @@ -29,6 +29,7 @@ export const selectActiveModalId = createSelector(selectUiData, (ui) => ui.modal export const MODAL_IDS = { DAYWISHES: "DAYWISHES", HOSTING: "HOSTING", + MEALS: "MEALS", PARTICIPATIONDETAILS: "PARTICIPATIONDETAILS", TEAMWISHES: "TEAMWISHES", } diff --git a/src/store/volunteerMealsSet.ts b/src/store/volunteerMealsSet.ts new file mode 100644 index 0000000..59a8246 --- /dev/null +++ b/src/store/volunteerMealsSet.ts @@ -0,0 +1,60 @@ +import { PayloadAction, createSlice } from "@reduxjs/toolkit" + +import { StateRequest, toastError, elementFetch } from "./utils" +import { VolunteerMeals } from "../services/volunteers" +import { AppThunk, AppState } from "." +import { volunteerMealsSet } from "../services/volunteersAccessors" + +type StateVolunteerMealsSet = { entity?: VolunteerMeals } & StateRequest + +export const initialState: StateVolunteerMealsSet = { + readyStatus: "idle", +} + +const volunteerMealsSetSlice = createSlice({ + name: "volunteerMealsSet", + initialState, + reducers: { + getRequesting: (_) => ({ + readyStatus: "request", + }), + getSuccess: (_, { payload }: PayloadAction) => ({ + readyStatus: "success", + entity: payload, + }), + getFailure: (_, { payload }: PayloadAction) => ({ + readyStatus: "failure", + error: payload, + }), + }, +}) + +export default volunteerMealsSetSlice.reducer +export const { getRequesting, getSuccess, getFailure } = volunteerMealsSetSlice.actions + +export const fetchVolunteerMealsSet = elementFetch( + volunteerMealsSet, + getRequesting, + getSuccess, + getFailure, + (error: Error) => + toastError(`Erreur lors du chargement des choix de jours de présence: ${error.message}`) +) + +const shouldFetchVolunteerMealsSet = (state: AppState, id: number) => + state.volunteerMealsSet?.readyStatus !== "success" || + (state.volunteerMealsSet?.entity && state.volunteerMealsSet?.entity?.id !== id) + +export const fetchVolunteerMealsSetIfNeed = + (id = 0, wishes: Partial = {}): AppThunk => + (dispatch, getState) => { + let jwt = "" + + if (!id) { + ;({ jwt, id } = getState().auth) + } + if (shouldFetchVolunteerMealsSet(getState(), id)) + return dispatch(fetchVolunteerMealsSet(jwt, id, wishes)) + + return null + }