Add Brunch and Retex forms ans asks

This commit is contained in:
pikiou 2022-09-13 02:53:30 +02:00
parent bd7dc7578e
commit 72a633ae4f
35 changed files with 1381 additions and 86 deletions

View File

@ -18,7 +18,7 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [17.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View File

@ -0,0 +1,39 @@
import { get } from "lodash"
import { useCallback } from "react"
import { fetchVolunteerAsksSet } from "../../store/volunteerAsksSet"
import { useAskTools, addAsk, answerLaterOnProfile } from "./utils"
import BrunchForm, { fetchFor as fetchForBrunchForm } from "../VolunteerBoard/BrunchForm/BrunchForm"
import { useBrunch } from "../VolunteerBoard/brunch.utils"
export function AskBrunch(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 [retex] = useBrunch()
const question1Default = "-1"
const question1 = +get(retex, "question1", question1Default)
const needToShow = !!retex && question1 === -1
addAsk(
asks,
id,
volunteerAsks,
false,
needToShow,
<>
<BrunchForm afterSubmit={onSubmit}>{answerLaterOnProfile}</BrunchForm>
Nous avons besoin d'une réponse avant le jeudi 15 soir minuit pour commander les repas !
^^
</>
)
}
// Fetch server-side data here
export const fetchFor = [...fetchForBrunchForm]

View File

@ -0,0 +1,59 @@
import { get } from "lodash"
import { useCallback } from "react"
import { fetchVolunteerAsksSet } from "../../store/volunteerAsksSet"
import { useAskTools, addAsk, answerLaterOnProfile } from "./utils"
import RetexForm, { fetchFor as fetchForRetexForm } from "../VolunteerBoard/RetexForm/RetexForm"
import { useRetex } from "../VolunteerBoard/retex.utils"
export function AskRetex(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 [retex] = useRetex()
const question1Default = "-1"
const dayWishes = get(retex, "dayWishes", "")
const question1 = +get(retex, "question1", question1Default)
const question2 = get(retex, "question2", "")
const question3 = get(retex, "question3", "")
const question4 = get(retex, "question4", "")
const question5 = get(retex, "question5", "")
const question6 = get(retex, "question6", "")
const question7 = get(retex, "question7", "")
const question8 = get(retex, "question8", "")
const question9 = get(retex, "question9", "")
const wasHereBeforeAfter = dayWishes.match(/M|J|V|L/)
const needToShow =
!!retex &&
(question1 === -1 ||
!question2 ||
!question3 ||
!question4 ||
(wasHereBeforeAfter && !question5) ||
!question6 ||
!question7 ||
!question8 ||
!question9)
addAsk(
asks,
id,
volunteerAsks,
false,
needToShow,
<>
<RetexForm afterSubmit={onSubmit}>{answerLaterOnProfile}</RetexForm>
Tes réponses sont modifiable sur la page <a href="/profil">Mon profil</a> jusqu'au 23
septembre.
</>
)
}
// Fetch server-side data here
export const fetchFor = [...fetchForRetexForm]

View File

@ -3,16 +3,18 @@ import React, { memo } from "react"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
import { useAskTools } from "./utils" import { useAskTools } from "./utils"
import { AskWelcome } from "./AskWelcome" import { AskWelcome } from "./AskWelcome"
import { AskBrunch, fetchFor as fetchForBrunch } from "./AskBrunch"
import { AskRetex, fetchFor as fetchForRetex } from "./AskRetex"
import { AskDiscord, fetchFor as fetchForDiscord } from "./AskDiscord" import { AskDiscord, fetchFor as fetchForDiscord } from "./AskDiscord"
import { AskDayWishes, fetchFor as fetchForDayWishes } from "./AskDayWishes" // import { AskDayWishes, fetchFor as fetchForDayWishes } from "./AskDayWishes"
import { AskHosting, fetchFor as fetchForHosting } from "./AskHosting" // import { AskHosting, fetchFor as fetchForHosting } from "./AskHosting"
// import { AskMeals, fetchFor as fetchForMeals } from "./AskMeals" // import { AskMeals, fetchFor as fetchForMeals } from "./AskMeals"
import { AskPersonalInfo, fetchFor as fetchForPersonalInfo } from "./AskPersonalInfo" // import { AskPersonalInfo, fetchFor as fetchForPersonalInfo } from "./AskPersonalInfo"
import { AskTeamWishes, fetchFor as fetchForTeamWishes } from "./AskTeamWishes" // import { AskTeamWishes, fetchFor as fetchForTeamWishes } from "./AskTeamWishes"
import { // import {
AskParticipationDetails, // AskParticipationDetails,
fetchFor as fetchForParticipationDetails, // fetchFor as fetchForParticipationDetails,
} from "./AskParticipationDetails" // } from "./AskParticipationDetails"
import { AskPushNotif } from "./AskPushNotif" import { AskPushNotif } from "./AskPushNotif"
const Asks = (): JSX.Element | null => { const Asks = (): JSX.Element | null => {
@ -20,13 +22,15 @@ const Asks = (): JSX.Element | null => {
const asks: JSX.Element[] = [] const asks: JSX.Element[] = []
AskWelcome(asks, 1) AskWelcome(asks, 1)
AskDiscord(asks, 3) AskBrunch(asks, 2)
AskRetex(asks, 3)
AskDiscord(asks, 5)
AskDayWishes(asks, 10) // AskDayWishes(asks, 10)
AskTeamWishes(asks, 11) // AskTeamWishes(asks, 11)
AskParticipationDetails(asks, 12) // AskParticipationDetails(asks, 12)
AskPersonalInfo(asks, 15) // AskPersonalInfo(asks, 15)
AskHosting(asks, 20) // AskHosting(asks, 20)
// AskMeals(asks, 22) // AskMeals(asks, 22)
AskPushNotif(asks, 99) AskPushNotif(asks, 99)
@ -62,11 +66,13 @@ export default memo(Asks)
// Fetch server-side data here // Fetch server-side data here
export const fetchFor = [ export const fetchFor = [
...fetchForBrunch,
...fetchForRetex,
...fetchForDiscord, ...fetchForDiscord,
...fetchForDayWishes, // ...fetchForDayWishes,
...fetchForHosting, // ...fetchForHosting,
// ...fetchForMeals, // ...fetchForMeals,
...fetchForTeamWishes, // ...fetchForTeamWishes,
...fetchForParticipationDetails, // ...fetchForParticipationDetails,
...fetchForPersonalInfo, // ...fetchForPersonalInfo,
] ]

View File

@ -37,7 +37,7 @@ const FormButton: FC<Props> = ({ children, text, onClick }): JSX.Element => {
</button> </button>
<div>{children}</div> <div>{children}</div>
<button type="button" className={styles.greyButton} onClick={onIgnore}> <button type="button" className={styles.greyButton} onClick={onIgnore}>
Ok, ignorer Vraiment passer au questionnaire suivant
</button> </button>
</div> </div>
)} )}

View File

@ -52,7 +52,7 @@ const MainMenu: FC = (): JSX.Element => {
<MenuItem name="Questions" pathname="/" /> <MenuItem name="Questions" pathname="/" />
<MenuItem name="Annonces" pathname="/annonces" /> <MenuItem name="Annonces" pathname="/annonces" />
<MenuItem name="Mon profil" pathname="/profil" /> <MenuItem name="Mon profil" pathname="/profil" />
<MenuItem name="Mes connaissances" pathname="/connaissances" /> {/* <MenuItem name="Mes connaissances" pathname="/connaissances" /> */}
<RestrictMenuItem <RestrictMenuItem
role={ROLES.ASSIGNER} role={ROLES.ASSIGNER}
name="Gestion équipes" name="Gestion équipes"

View File

@ -709,7 +709,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => {
</div> </div>
<div className={styles.rightCol}> <div className={styles.rightCol}>
<div className={styles.rightColContainer}> <div className={styles.rightColContainer}>
{["WhatsApp", "Signal", "SMS", "Email", "Appel", "Aucun"].map((option) => ( {["WhatsApp", "Signal", "SMS", "Email", "Aucun"].map((option) => (
<label className={styles.shortAnswerLabel} key={option}> <label className={styles.shortAnswerLabel} key={option}>
<input <input
type="radio" type="radio"

View File

@ -1,32 +1,45 @@
import { FC, memo } from "react" import { FC, memo } from "react"
import DayWishes from "./DayWishes/DayWishes" // import DayWishes from "./DayWishes/DayWishes"
import DayWishesFormModal from "./DayWishesForm/DayWishesFormModal" // import DayWishesFormModal from "./DayWishesForm/DayWishesFormModal"
import Hosting from "./Hosting/Hosting" // import Hosting from "./Hosting/Hosting"
import HostingFormModal from "./HostingForm/HostingFormModal" // import HostingFormModal from "./HostingForm/HostingFormModal"
import Meals from "./Meals/Meals" // import Meals from "./Meals/Meals"
import MealsFormModal from "./MealsForm/MealsFormModal" // import MealsFormModal from "./MealsForm/MealsFormModal"
import ParticipationDetails from "./ParticipationDetails/ParticipationDetails" // import ParticipationDetails from "./ParticipationDetails/ParticipationDetails"
import ParticipationDetailsFormModal from "./ParticipationDetailsForm/ParticipationDetailsFormModal" // import ParticipationDetailsFormModal from "./ParticipationDetailsForm/ParticipationDetailsFormModal"
import TeamWishes from "./TeamWishes/TeamWishes" // import TeamWishes from "./TeamWishes/TeamWishes"
import TeamWishesFormModal from "./TeamWishesForm/TeamWishesFormModal" // import TeamWishesFormModal from "./TeamWishesForm/TeamWishesFormModal"
// import VolunteerTeam from "./VolunteerTeam/VolunteerTeam"
import withUserConnected from "../../utils/withUserConnected" import withUserConnected from "../../utils/withUserConnected"
import ContentTitle from "../ui/Content/ContentTitle" import ContentTitle from "../ui/Content/ContentTitle"
import { fetchFor as fetchForDayWishesForm } from "./DayWishesForm/DayWishesForm" // import { fetchFor as fetchForDayWishesForm } from "./DayWishesForm/DayWishesForm"
import { fetchFor as fetchForHostingForm } from "./HostingForm/HostingForm" // import { fetchFor as fetchForHostingForm } from "./HostingForm/HostingForm"
import { fetchFor as fetchForMealsForm } from "./MealsForm/MealsForm" // import { fetchFor as fetchForMealsForm } from "./MealsForm/MealsForm"
import { fetchFor as fetchForParticipationDetailsForm } from "./ParticipationDetailsForm/ParticipationDetailsForm" // import { fetchFor as fetchForParticipationDetailsForm } from "./ParticipationDetailsForm/ParticipationDetailsForm"
// import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm"
import { fetchFor as fetchForPersonalInfoForm } from "./PersonalInfoForm/PersonalInfoForm" import { fetchFor as fetchForPersonalInfoForm } from "./PersonalInfoForm/PersonalInfoForm"
import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm"
import VolunteerTeam from "./VolunteerTeam/VolunteerTeam"
import PersonalInfo from "./PersonalInfo/PersonalInfo" import PersonalInfo from "./PersonalInfo/PersonalInfo"
import PersonalInfoFormModal from "./PersonalInfoForm/PersonalInfoFormModal" import PersonalInfoFormModal from "./PersonalInfoForm/PersonalInfoFormModal"
import Brunch from "./Brunch/Brunch"
import BrunchFormModal from "./BrunchForm/BrunchFormModal"
import { fetchFor as fetchForBrunchForm } from "./BrunchForm/BrunchForm"
import Retex from "./Retex/Retex"
import RetexFormModal from "./RetexForm/RetexFormModal"
import { fetchFor as fetchForRetexForm } from "./RetexForm/RetexForm"
import { useRetex } from "./retex.utils"
const Board: FC = (): JSX.Element => ( const Board: FC = (): JSX.Element => {
<> const [retex] = useRetex()
<ContentTitle title="Profil spécifique au festival" /> return (
<PersonalInfo /> <>
<PersonalInfoFormModal /> <ContentTitle title="Profil spécifique au festival" />
<DayWishes /> <PersonalInfo />
<PersonalInfoFormModal />
{retex && <Brunch />}
{retex && <BrunchFormModal />}
{retex && <Retex />}
{retex && <RetexFormModal />}
{/* <DayWishes />
<DayWishesFormModal /> <DayWishesFormModal />
<ParticipationDetails /> <ParticipationDetails />
<ParticipationDetailsFormModal /> <ParticipationDetailsFormModal />
@ -36,17 +49,20 @@ const Board: FC = (): JSX.Element => (
<Hosting /> <Hosting />
<HostingFormModal /> <HostingFormModal />
<Meals /> <Meals />
<MealsFormModal /> <MealsFormModal /> */}
</> </>
) )
}
export default memo(withUserConnected(Board)) export default memo(withUserConnected(Board))
export const fetchFor = [ export const fetchFor = [
...fetchForDayWishesForm,
...fetchForHostingForm,
...fetchForMealsForm,
...fetchForParticipationDetailsForm,
...fetchForPersonalInfoForm, ...fetchForPersonalInfoForm,
...fetchForTeamWishesForm, ...fetchForRetexForm,
...fetchForBrunchForm,
// ...fetchForDayWishesForm,
// ...fetchForHostingForm,
// ...fetchForMealsForm,
// ...fetchForParticipationDetailsForm,
// ...fetchForTeamWishesForm,
] ]

View File

@ -0,0 +1,42 @@
import { FC, memo, useCallback } from "react"
import get from "lodash/get"
import styles from "./styles.module.scss"
import { useBrunch } from "../brunch.utils"
import { displayModal, MODAL_IDS } from "../../../store/ui"
import useAction from "../../../utils/useAction"
type Props = {
afterSubmit?: () => void | undefined
}
const Brunch: FC<Props> = (): JSX.Element | null => {
const [retex] = useBrunch()
const question1 = get(retex, "question1", -1)
const execDisplayModal = useAction(displayModal)
const onEdit = useCallback(() => execDisplayModal(MODAL_IDS.BRUNCH), [execDisplayModal])
return (
<div className={styles.root}>
<div className={styles.title}>Inscription au brunch</div>
<div className={styles.line}>
{question1 === -1 && (
<>
Ma présence au brunch est{" "}
<span className={styles.lineEmpty}>non renseignée</span>
</>
)}
{question1 === 0 && <>Je ne viendrai pas au brunch </>}
{question1 > 0 && (
<>Je viendrai au brunch{question1 > 1 && <> avec {question1} personne(s)</>}</>
)}
</div>
<div className={styles.editButton}>
<button type="button" onClick={onEdit}>
Modifier
</button>
</div>
</div>
)
}
export default memo(Brunch)

View File

@ -0,0 +1,36 @@
@import "../../../theme/variables";
@import "../../../theme/mixins";
.root {
@include inner-content-wrapper();
position: relative;
padding-right: 90px;
}
.title {
padding-bottom: 10px;
font-weight: bold;
}
.line {
margin-bottom: 5px;
}
.lineEmpty {
color: $color-red;
font-style: italic;
}
.editButton {
@include vertical-center();
position: absolute;
right: 20px;
button {
color: $color-green;
font-weight: bold;
cursor: pointer;
}
}

View File

@ -0,0 +1,142 @@
import { FC, memo, ReactNode, useCallback, useEffect, useRef, useState } from "react"
import classnames from "classnames"
import get from "lodash/get"
import set from "lodash/set"
import styles from "./styles.module.scss"
import { useBrunch } from "../brunch.utils"
import FormButton from "../../Form/FormButton/FormButton"
import { fetchRetexSetIfNeed } from "../../../store/retexSet"
import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton"
type Props = {
children?: ReactNode | undefined
afterSubmit?: () => void | undefined
}
const BrunchForm: FC<Props> = ({ children, afterSubmit }): JSX.Element | null => {
const [brunchPresence, setBrunchPresence] = useState<string>("inconnue")
const question1Ref = useRef<HTMLInputElement | null>(null)
const question1Default = "-1"
const [retex, saveBrunch] = useBrunch()
const onSubmit = useCallback(() => {
if (!retex) {
return
}
const question1 = +get(question1Ref, "current.value", question1Default)
saveBrunch(retex.id, question1)
if (afterSubmit) afterSubmit()
}, [afterSubmit, retex, saveBrunch])
const onBrunchPresenceChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const presence = e.target.value
setBrunchPresence(presence)
const guestCountDefault = { oui: 1, non: 0, "peut-etre": -1 }[presence]
set(question1Ref, "current.value", `${guestCountDefault}`)
}, [])
useEffect(() => {
const question1 = +get(retex, "question1", question1Default)
set(question1Ref, "current.value", `${question1}`)
if (question1 >= 1) setBrunchPresence("oui")
else if (question1 === 0) setBrunchPresence("non")
else setBrunchPresence("peut-etre")
}, [setBrunchPresence, retex])
return (
<div>
<div className={styles.title}>Inscription au brunch</div>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.brunchTitle}>
Viendras-tu au brunch samedi 1er octobre ? Le boulodrome (19 route des
fortifications) nous sera réservé de 10h à 18h.
</div>
</div>
<div className={styles.rightCol}>
<label className={styles.brunchLabel}>
<input
type="radio"
value="oui"
name="brunchPresence"
onChange={onBrunchPresenceChange}
checked={brunchPresence === "oui"}
/>{" "}
Oui
</label>
<label className={styles.brunchLabel}>
<input
type="radio"
value="non"
name="brunchPresence"
onChange={onBrunchPresenceChange}
checked={brunchPresence === "non"}
/>{" "}
Non
</label>
<label className={styles.brunchLabel}>
<input
type="radio"
value="peut-etre"
name="brunchPresence"
onChange={onBrunchPresenceChange}
checked={brunchPresence === "peut-etre"}
/>{" "}
Je ne sais pas encore
</label>
</div>
</div>
<div
className={classnames(
styles.inputWrapper,
brunchPresence === "oui" ? null : styles.invisible
)}
>
<div className={styles.leftCol}>
<div className={styles.guestCountTitle}>
À combien viendras-tu ? Le brunch est pour les bénévoles ayant participé à
la dernière édition (y compris ceux empêchés à la dernière minute), ainsi
qu'aux éventuels +1 conjoints et enfants. Mais pas les amis, pour lesquels
d'autres rdv seront proposés au cours de l'année.
</div>
</div>
<div className={styles.rightCol}>
<input className={styles.guestCountLabel} type="text" ref={question1Ref} />
</div>
</div>
<div className={styles.buttonWrapper}>
<FormButton onClick={onSubmit}>Enregistrer</FormButton>
{children === undefined && (
<>
{" "}
<FormButton onClick={afterSubmit} type="grey">
Annuler
</FormButton>{" "}
</>
)}
{children !== undefined && (
<>
{" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children}
</IgnoreButton>{" "}
</>
)}
</div>
</div>
)
}
BrunchForm.defaultProps = {
children: undefined,
afterSubmit: undefined,
}
export default memo(BrunchForm)
// Fetch server-side data here
export const fetchFor = [fetchRetexSetIfNeed]

View File

@ -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 BrunchForm from "./BrunchForm"
const BrunchFormModal: FC = (): JSX.Element => {
const execHideModal = useAction(hideModal)
const afterFormSubmit = useCallback(() => execHideModal(), [execHideModal])
return (
<Modal modalId={MODAL_IDS.BRUNCH}>
<BrunchForm afterSubmit={afterFormSubmit} />
</Modal>
)
}
export default memo(BrunchFormModal)

View File

@ -0,0 +1,109 @@
@import "../../../theme/variables";
@import "../../../theme/mixins";
.title {
padding: 4px;
margin: 15px 0;
font-weight: bold;
text-align: center;
}
.inputWrapper {
margin: 25px 0;
@include desktop {
display: flex;
}
input[type="text"] {
min-width: 175px;
border: 1px solid $color-grey-medium;
outline: 0;
}
}
.leftCol {
flex: 0 0 240px;
}
.rightCol {
width: 100%;
text-align: center;
}
.brunchTitle {
display: inline-block;
width: 320px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.brunchLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 280px;
}
.brunchPresenceTitle {
display: inline-block;
width: 320px;
margin-bottom: 10px;
}
.brunchPresenceLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 80px;
}
.guestCountTitle {
display: inline-block;
width: 320px;
margin-bottom: 10px;
}
.guestCountLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 80px;
}
.questionWrapper {
margin: 6px 0 14px;
label {
display: block;
padding: 6px 0 2px 4px;
}
textarea {
width: 100%;
height: 75px;
padding: 5px;
border: 1px solid $color-grey-light;
background-color: $color-grey-lighter;
outline: 0;
}
}
.buttonWrapper {
margin-bottom: 10px;
text-align: center;
}
.preAnswerWrapper {
margin-bottom: 3px;
text-align: left;
}
.preAnswerButton {
@include form-button;
margin-left: 2px;
margin-top: 2px;
}

View File

@ -164,7 +164,7 @@ const DayWishesForm: FC<Props> = ({ children, afterSubmit }): JSX.Element => {
{children !== undefined && ( {children !== undefined && (
<> <>
{" "} {" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer"> <IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children} {children}
</IgnoreButton>{" "} </IgnoreButton>{" "}
</> </>

View File

@ -112,7 +112,7 @@ const HostingForm: FC<Props> = ({ children, afterSubmit }): JSX.Element => {
{children !== undefined && ( {children !== undefined && (
<> <>
{" "} {" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer"> <IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children} {children}
</IgnoreButton>{" "} </IgnoreButton>{" "}
</> </>

View File

@ -135,7 +135,7 @@ const MealsForm: FC<Props> = ({ children, afterSubmit }): JSX.Element => {
{children !== undefined && ( {children !== undefined && (
<> <>
{" "} {" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer"> <IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children} {children}
</IgnoreButton>{" "} </IgnoreButton>{" "}
</> </>

View File

@ -37,32 +37,6 @@
width: 220px; 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 { .mealsTitle {
display: inline-block; display: inline-block;
width: 320px; width: 320px;

View File

@ -151,7 +151,7 @@ const ParticipationDetailsForm: FC<Props> = ({ children, afterSubmit }): JSX.Ele
{children !== undefined && ( {children !== undefined && (
<> <>
{" "} {" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer"> <IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children} {children}
</IgnoreButton>{" "} </IgnoreButton>{" "}
</> </>

View File

@ -96,7 +96,6 @@ const PersonalInfoForm: FC<Props> = ({ children, afterSubmit }): JSX.Element =>
type="file" type="file"
name="myImage" name="myImage"
onChange={(event) => { onChange={(event) => {
console.log(event?.target?.files?.[0])
setSelectedImage(event?.target?.files?.[0] || null) setSelectedImage(event?.target?.files?.[0] || null)
}} }}
/> />
@ -134,7 +133,7 @@ const PersonalInfoForm: FC<Props> = ({ children, afterSubmit }): JSX.Element =>
{children !== undefined && ( {children !== undefined && (
<> <>
{" "} {" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer"> <IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children} {children}
</IgnoreButton>{" "} </IgnoreButton>{" "}
</> </>

View File

@ -0,0 +1,56 @@
import { FC, memo, useCallback } from "react"
import get from "lodash/get"
import styles from "./styles.module.scss"
import { useRetex } from "../retex.utils"
import { displayModal, MODAL_IDS } from "../../../store/ui"
import useAction from "../../../utils/useAction"
type Props = {
afterSubmit?: () => void | undefined
}
const Retex: FC<Props> = (): JSX.Element | null => {
const [retex] = useRetex()
const dayWishes = get(retex, "dayWishes", "")
const question2 = get(retex, "question2", "")
const question3 = get(retex, "question3", "")
const question4 = get(retex, "question4", "")
const question5 = get(retex, "question5", "")
const question6 = get(retex, "question6", "")
const question7 = get(retex, "question7", "")
const question8 = get(retex, "question8", "")
const execDisplayModal = useAction(displayModal)
const onEdit = useCallback(() => execDisplayModal(MODAL_IDS.RETEX), [execDisplayModal])
const weekDays = `,${dayWishes}`.replace(/,S|,D/g, "").replace(/^,/, "")
const answeredQuestionCount =
(question2 ? 1 : 0) +
(question3 ? 1 : 0) +
(question4 ? 1 : 0) +
(question5 ? 1 : 0) +
(question6 ? 1 : 0) +
(question7 ? 1 : 0) +
(question8 ? 1 : 0)
const expectedAnswerCount = weekDays ? 7 : 6
return (
<div className={styles.root}>
<div className={styles.title}>Retour sur PeL 2022</div>
<div className={styles.line}>
<span
className={answeredQuestionCount < expectedAnswerCount ? styles.lineEmpty : ""}
>
{answeredQuestionCount} réponses{" "}
</span>
sur {expectedAnswerCount}
{answeredQuestionCount >= expectedAnswerCount && <> !</>}
</div>
<div className={styles.editButton}>
<button type="button" onClick={onEdit}>
Modifier
</button>
</div>
</div>
)
}
export default memo(Retex)

View File

@ -0,0 +1,36 @@
@import "../../../theme/variables";
@import "../../../theme/mixins";
.root {
@include inner-content-wrapper();
position: relative;
padding-right: 90px;
}
.title {
padding-bottom: 10px;
font-weight: bold;
}
.line {
margin-bottom: 5px;
}
.lineEmpty {
color: $color-red;
font-style: italic;
}
.editButton {
@include vertical-center();
position: absolute;
right: 20px;
button {
color: $color-green;
font-weight: bold;
cursor: pointer;
}
}

View File

@ -0,0 +1,374 @@
import { FC, memo, ReactNode, useCallback, useEffect, useRef } from "react"
import get from "lodash/get"
import set from "lodash/set"
import styles from "./styles.module.scss"
import { useRetex } from "../retex.utils"
import FormButton from "../../Form/FormButton/FormButton"
import { fetchRetexSetIfNeed } from "../../../store/retexSet"
import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton"
type Props = {
children?: ReactNode | undefined
afterSubmit?: () => void | undefined
}
const RetexForm: FC<Props> = ({ children, afterSubmit }): JSX.Element | null => {
const question2Ref = useRef<HTMLTextAreaElement | null>(null)
const question3Ref = useRef<HTMLTextAreaElement | null>(null)
const question4Ref = useRef<HTMLTextAreaElement | null>(null)
const question5Ref = useRef<HTMLTextAreaElement | null>(null)
const question6Ref = useRef<HTMLTextAreaElement | null>(null)
const question7Ref = useRef<HTMLTextAreaElement | null>(null)
const question8Ref = useRef<HTMLTextAreaElement | null>(null)
const question9Ref = useRef<HTMLTextAreaElement | null>(null)
const [retex, saveRetex] = useRetex()
const dayWishes = get(retex, "dayWishes", "")
const weekDaysText = `,${dayWishes}`
.replace(/,S|,D/g, "")
.replace("M", "mercredi")
.replace("J", "jeudi")
.replace("V", "vendredi")
.replace("L", "lundi")
.replace(/^,/, "")
const weekDays = weekDaysText ? weekDaysText.split(",") : []
const onSubmit = useCallback(() => {
if (!retex) {
return
}
const question2 = get(question2Ref, "current.value", "")
const question3 = get(question3Ref, "current.value", "")
const question4 = get(question4Ref, "current.value", "")
const question5 = get(question5Ref, "current.value", "")
const question6 = get(question6Ref, "current.value", "")
const question7 = get(question7Ref, "current.value", "")
const question8 = get(question8Ref, "current.value", "")
const question9 = get(question9Ref, "current.value", "")
saveRetex(
retex.id,
question2,
question3,
question4,
question5,
question6,
question7,
question8,
question9
)
if (afterSubmit) afterSubmit()
}, [afterSubmit, retex, saveRetex])
const preAnswer = useCallback(
(ref: React.MutableRefObject<HTMLTextAreaElement | null>) =>
(e: React.MouseEvent<HTMLButtonElement>) => {
const answer = e.currentTarget.innerText
const currentAnswer = get(ref, "current.value", "")
const newAnswer = `${currentAnswer}${currentAnswer ? "\n" : ""}${answer.replace(
/_+$/,
""
)}`
set(ref, "current.value", newAnswer)
ref?.current?.focus()
},
[]
)
useEffect(() => {
const question2 = get(retex, "question2", "")
const question3 = get(retex, "question3", "")
const question4 = get(retex, "question4", "")
const question5 = get(retex, "question5", "")
const question6 = get(retex, "question6", "")
const question7 = get(retex, "question7", "")
const question8 = get(retex, "question8", "")
const question9 = get(retex, "question9", "")
if (question2) set(question2Ref, "current.value", question2)
if (question3) set(question3Ref, "current.value", question3)
if (question4) set(question4Ref, "current.value", question4)
if (question5) set(question5Ref, "current.value", question5)
if (question6) set(question6Ref, "current.value", question6)
if (question7) set(question7Ref, "current.value", question7)
if (question8) set(question8Ref, "current.value", question8)
if (question9) set(question9Ref, "current.value", question9)
}, [retex])
return (
<div>
<div className={styles.title}>Retour sur PeL 2022</div>
<div className={styles.questionWrapper}>
On aimerait savoir comment s'est passé ton festival !<br />
L'orga lira tes réponses et répondra à son tour à tes questions soit
individuellement, soit dans la prochaine gazette. Puis toutes les réponses seront
anonymisées et une synthèse sera diffusée dans la gazette.
<br />
Tu peux répondre par 3 mots ou 3 pages, on a tous vécu le festival différemment !
</div>
<div className={styles.questionWrapper}>
<label htmlFor="question2">
As-tu un avis positif/négatif ou une recommandation au sujet des repas, des WC,
de tes besoins en tee-shirt, chapeau, eau, bière, crème solaire ?
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question2Ref)}
>
Tout était top.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question2Ref)}
>
On ma rapporté que __
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question2Ref)}
>
Jai eu un problème concernant __
</button>
</div>
<textarea id="question2" ref={question2Ref} placeholder="..." />
</div>
<div className={styles.questionWrapper}>
<label htmlFor="question3">
As-tu, comme prévu et en accord avec ton équipe, pris du temps pour profiter des
espaces visiteurs du festival, des badges inter-équipes, des crêpes/glaces à
lespace bénévole ?
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question3Ref)}
>
Jai joué X temps sur des stands éditeurs.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question3Ref)}
>
Je me suis baladé sans jouer.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question3Ref)}
>
Il y avait des crêpes ?
</button>
</div>
<textarea id="question3" ref={question3Ref} placeholder="..." />
</div>
<div className={styles.questionWrapper}>
<label htmlFor="question4">
Gestion du stress, de la fatigue : as-tu fait des pauses (à notre espace sieste,
à lespace Shiatsu) ? Tes-tu senti épuisé lors du festival, après, et sais-tu
pourquoi ?
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question4Ref)}
>
Jétais en forme tout du long.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question4Ref)}
>
Les jours de préparatifs mont fatigués.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question4Ref)}
>
Il y avait des massages gratuits ?
</button>
</div>
<textarea id="question4" ref={question4Ref} placeholder="..." />
</div>
{weekDays.length > 0 && (
<div className={styles.questionWrapper}>
<label htmlFor="question5">
{weekDays.length > 1
? `Comment se sont passés les ${weekDays.join(", ")} ?`
: `Comment s'est passé le ${weekDays.join(", ")} ?`}{" "}
As-tu eu assez dinfos, te sentais-tu utile ? Y compris au sein de ton
équipe ?
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question5Ref)}
>
Je nai pas pu venir.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question5Ref)}
>
Je nai pas arrêté.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question5Ref)}
>
Je manquais dinfos.
</button>
</div>
<textarea id="question5" ref={question5Ref} placeholder="..." />
</div>
)}
<div className={styles.questionWrapper}>
<label htmlFor="question6">
As-tu trouvé ton compte vis-à-vis des raisons qui t'ont poussées à être bénévole
(faire découvrir sa passion, se rendre utile, découvrir lenvers du décor,
sympathiser, apprendre, simplement kiffer, etc) ?
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question6Ref)}
>
Oui, objectifs atteints.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question6Ref)}
>
Je navais pas dattente.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question6Ref)}
>
Il ma manqué __
</button>
</div>
<textarea id="question6" ref={question6Ref} placeholder="..." />
</div>
<div className={styles.questionWrapper}>
<label htmlFor="question7">
Si dautres bénévoles sont partants pour te soutenir, que mettrais-tu en œuvre
autrement ou mieux pour la prochaine édition du festival ?
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question7Ref)}
>
Dans léquipe __ jaimerais __
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question7Ref)}
>
B. La réponse B.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question7Ref)}
>
Je manque de temps.
</button>
</div>
<textarea id="question7" ref={question7Ref} placeholder="..." />
</div>
<div className={styles.questionWrapper}>
<label htmlFor="question8">
Envisages-tu dêtre bénévole pour PeL 2023 ? Dans la même équipe, ou tu aurais
envie den changer ? Libre à toi dexpliquer ou non pourquoi.
</label>
<div className={styles.preAnswerWrapper}>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question8Ref)}
>
Oui, si je suis dispo.
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question8Ref)}
>
Oui, mais dans léquipe __
</button>
<button
type="button"
className={styles.preAnswerButton}
onClick={preAnswer(question8Ref)}
>
Hélas non.
</button>
</div>
<textarea id="question8" ref={question8Ref} placeholder="..." />
</div>
<div className={styles.questionWrapper}>
<label htmlFor="question9">
As-tu un conseil, une remarque, une idée non couverte par les précédentes
questions ? Laisse ton imagination déborder ^^
</label>
<textarea id="question9" ref={question9Ref} placeholder="..." />
</div>
<div className={styles.buttonWrapper}>
<FormButton onClick={onSubmit}>Enregistrer</FormButton>
{children === undefined && (
<>
{" "}
<FormButton onClick={afterSubmit} type="grey">
Annuler
</FormButton>{" "}
</>
)}
{children !== undefined && (
<>
{" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children}
</IgnoreButton>{" "}
</>
)}
</div>
</div>
)
}
RetexForm.defaultProps = {
children: undefined,
afterSubmit: undefined,
}
export default memo(RetexForm)
// Fetch server-side data here
export const fetchFor = [fetchRetexSetIfNeed]

View File

@ -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 RetexForm from "./RetexForm"
const RetexFormModal: FC = (): JSX.Element => {
const execHideModal = useAction(hideModal)
const afterFormSubmit = useCallback(() => execHideModal(), [execHideModal])
return (
<Modal modalId={MODAL_IDS.RETEX}>
<RetexForm afterSubmit={afterFormSubmit} />
</Modal>
)
}
export default memo(RetexFormModal)

View File

@ -0,0 +1,109 @@
@import "../../../theme/variables";
@import "../../../theme/mixins";
.title {
padding: 4px;
margin: 15px 0;
font-weight: bold;
text-align: center;
}
.inputWrapper {
margin: 25px 0;
@include desktop {
display: flex;
}
input[type="text"] {
min-width: 175px;
border: 1px solid $color-grey-medium;
outline: 0;
}
}
.leftCol {
flex: 0 0 240px;
}
.rightCol {
width: 100%;
text-align: center;
}
.brunchTitle {
display: inline-block;
width: 320px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.brunchLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 280px;
}
.brunchPresenceTitle {
display: inline-block;
width: 320px;
margin-bottom: 10px;
}
.brunchPresenceLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 80px;
}
.guestCountTitle {
display: inline-block;
width: 320px;
margin-bottom: 10px;
}
.guestCountLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 80px;
}
.questionWrapper {
margin: 6px 0 14px;
label {
display: block;
padding: 6px 0 2px 4px;
}
textarea {
width: 100%;
height: 75px;
padding: 5px;
border: 1px solid $color-grey-light;
background-color: $color-grey-lighter;
outline: 0;
}
}
.buttonWrapper {
margin-bottom: 10px;
text-align: center;
}
.preAnswerWrapper {
margin-bottom: 3px;
text-align: left;
}
.preAnswerButton {
@include form-button;
margin-left: 2px;
margin-top: 2px;
}

View File

@ -110,7 +110,7 @@ const TeamWishesForm: FC<Props> = ({ children, afterSubmit }): JSX.Element | nul
{children !== undefined && ( {children !== undefined && (
<> <>
{" "} {" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer"> <IgnoreButton onClick={afterSubmit} text="Ignorer pour l'instant">
{children} {children}
</IgnoreButton>{" "} </IgnoreButton>{" "}
</> </>

View File

@ -0,0 +1,25 @@
import { useCallback } from "react"
import { shallowEqual, useSelector } from "react-redux"
import useAction from "../../utils/useAction"
import { selectUserJwtToken } from "../../store/auth"
import { AppState } from "../../store"
import { fetchRetexSet } from "../../store/retexSet"
import { Retex } from "../../services/retex"
type SetFunction = (id: Retex["id"], question1: Retex["question1"]) => void
export const useBrunch = (): [Retex | undefined, SetFunction] => {
const save = useAction(fetchRetexSet)
const jwtToken = useSelector(selectUserJwtToken)
const retex = useSelector((state: AppState) => state.retexSet?.entity, shallowEqual)
const saveBrunch: SetFunction = useCallback(
(id, question1) => {
if (!retex) return
save(jwtToken, { id, question1 })
},
[retex, save, jwtToken]
)
return [retex, saveBrunch]
}

View File

@ -0,0 +1,55 @@
import { useCallback } from "react"
import { shallowEqual, useSelector } from "react-redux"
import useAction from "../../utils/useAction"
import { selectUserJwtToken } from "../../store/auth"
import { AppState } from "../../store"
import { fetchRetexSet } from "../../store/retexSet"
import { Retex } from "../../services/retex"
type SetFunction = (
id: Retex["id"],
question2: Retex["question2"],
question3: Retex["question3"],
question4: Retex["question4"],
question5: Retex["question5"],
question6: Retex["question6"],
question7: Retex["question7"],
question8: Retex["question8"],
question9: Retex["question9"]
) => void
export const useRetex = (): [Retex | undefined, SetFunction] => {
const save = useAction(fetchRetexSet)
const jwtToken = useSelector(selectUserJwtToken)
const retex = useSelector((state: AppState) => state.retexSet?.entity, shallowEqual)
const saveRetex: SetFunction = useCallback(
(
id,
question2,
question3,
question4,
question5,
question6,
question7,
question8,
question9
) => {
if (!retex) return
save(jwtToken, {
id,
question2,
question3,
question4,
question5,
question6,
question7,
question8,
question9,
})
},
[retex, save, jwtToken]
)
return [retex, saveRetex]
}

View File

@ -20,6 +20,8 @@ export class SheetNames {
Postulants = "Postulants" Postulants = "Postulants"
Retex = "Retex"
Teams = "Equipes" Teams = "Equipes"
Volunteers = "Membres" Volunteers = "Membres"

View File

@ -0,0 +1,59 @@
import { cloneDeep } from "lodash"
import ExpressAccessors from "./expressAccessors"
import { Retex, RetexWithoutId, translationRetex } from "../../services/retex"
const expressAccessor = new ExpressAccessors<RetexWithoutId, Retex>(
"Retex",
new Retex(),
translationRetex
)
export const retexSet = expressAccessor.set(async (list, body, id, _roles) => {
const receivedRetex = body[0] as Record<keyof Retex, string>
if (id !== +receivedRetex.id) {
throw Error(`Retex modifié pour un autre member que soit`)
}
const retex: Retex | undefined = list.find((v) => v.id === +receivedRetex.id)
if (!retex) {
throw Error(`Il n'y a aucun bénévole avec cet identifiant ${receivedRetex.id}`)
}
const newRetex: Retex = cloneDeep(retex)
const parsedPartialRetex = expressAccessor.parseRawPartialElement(receivedRetex)
if (parsedPartialRetex === undefined) {
throw Error(`Erreur au parsing dans retexSet`)
}
if (parsedPartialRetex.question1 !== undefined)
newRetex.question1 = parsedPartialRetex.question1
if (parsedPartialRetex.question2 !== undefined)
newRetex.question2 = parsedPartialRetex.question2
if (parsedPartialRetex.question3 !== undefined)
newRetex.question3 = parsedPartialRetex.question3
if (parsedPartialRetex.question4 !== undefined)
newRetex.question4 = parsedPartialRetex.question4
if (parsedPartialRetex.question5 !== undefined)
newRetex.question5 = parsedPartialRetex.question5
if (parsedPartialRetex.question6 !== undefined)
newRetex.question6 = parsedPartialRetex.question6
if (parsedPartialRetex.question7 !== undefined)
newRetex.question7 = parsedPartialRetex.question7
if (parsedPartialRetex.question8 !== undefined)
newRetex.question8 = parsedPartialRetex.question8
if (parsedPartialRetex.question9 !== undefined)
newRetex.question9 = parsedPartialRetex.question9
return {
toDatabase: newRetex,
toCaller: newRetex,
}
})

View File

@ -47,6 +47,7 @@ import checkAccess from "./checkAccess"
import { hasGSheetsAccess } from "./gsheets/accessors" import { hasGSheetsAccess } from "./gsheets/accessors"
import { addStatus, showStatusAt } from "./status" import { addStatus, showStatusAt } from "./status"
import { miscMeetingDateListGet, miscDiscordInvitation } from "./gsheets/miscs" import { miscMeetingDateListGet, miscDiscordInvitation } from "./gsheets/miscs"
import { retexSet } from "./gsheets/retex"
checkAccess() checkAccess()
@ -108,6 +109,7 @@ app.get("/VolunteerListGet", secure as RequestHandler, volunteerListGet)
// Secured APIs // Secured APIs
app.get("/AnnouncementListGet", secure as RequestHandler, announcementListGet) app.get("/AnnouncementListGet", secure as RequestHandler, announcementListGet)
app.get("/MiscDiscordInvitationGet", secure as RequestHandler, miscDiscordInvitation) app.get("/MiscDiscordInvitationGet", secure as RequestHandler, miscDiscordInvitation)
app.post("/RetexSet", secure as RequestHandler, retexSet)
app.get("/TeamListGet", teamListGet) app.get("/TeamListGet", teamListGet)
app.get("/VolunteerDiscordId", secure as RequestHandler, volunteerDiscordId) app.get("/VolunteerDiscordId", secure as RequestHandler, volunteerDiscordId)
app.post("/VolunteerAsksSet", secure as RequestHandler, volunteerAsksSet) app.post("/VolunteerAsksSet", secure as RequestHandler, volunteerAsksSet)

56
src/services/retex.ts Normal file
View File

@ -0,0 +1,56 @@
/* eslint-disable max-classes-per-file */
export class Retex {
id = 0
dayWishes = ""
question1 = -1
question2 = ""
question3 = ""
question4 = ""
question5 = ""
question6 = ""
question7 = ""
question8 = ""
question9 = ""
}
export const translationRetex: { [k in keyof Retex]: string } = {
id: "id",
dayWishes: "enviesJours",
question1: "question1",
question2: "question2",
question3: "question3",
question4: "question4",
question5: "question5",
question6: "question6",
question7: "question7",
question8: "question8",
question9: "question9",
}
export const elementName = "Retex"
export const volunteerExample: Retex = {
id: 1,
dayWishes: "J,S,D",
question1: 1,
question2: "Amélie",
question3: "sadasdsa",
question4: "",
question5: "sadasdsa",
question6: "",
question7: "",
question8: "sadasdsa",
question9: "sadasdsa",
}
export type RetexWithoutId = Omit<Retex, "id">

View File

@ -0,0 +1,6 @@
import ServiceAccessors from "./accessors"
import { elementName, Retex, RetexWithoutId } from "./retex"
const serviceAccessors = new ServiceAccessors<RetexWithoutId, Retex>(elementName)
export const retexSet = serviceAccessors.securedCustomPost<[Partial<Retex>]>("Set")

53
src/store/retexSet.ts Normal file
View File

@ -0,0 +1,53 @@
import { PayloadAction, createSlice, createSelector } from "@reduxjs/toolkit"
import { StateRequest, toastError, elementFetch } from "./utils"
import { Retex } from "../services/retex"
import { retexSet } from "../services/retexAccessors"
import { AppState, AppThunk } from "."
type StateRetex = { entity?: Retex } & StateRequest
export const initialState: StateRetex = {
readyStatus: "idle",
}
const retexSetSlice = createSlice({
name: "retexSet",
initialState,
reducers: {
getRequesting: (_) => ({
readyStatus: "request",
}),
getSuccess: (_, { payload }: PayloadAction<Retex>) => ({
readyStatus: "success",
entity: payload,
}),
getFailure: (_, { payload }: PayloadAction<string>) => ({
readyStatus: "failure",
error: payload,
}),
},
})
export default retexSetSlice.reducer
export const { getRequesting, getSuccess, getFailure } = retexSetSlice.actions
export const fetchRetexSet = elementFetch(
retexSet,
getRequesting,
getSuccess,
getFailure,
(error: Error) => toastError(`Erreur lors de la modification d'un retex: ${error.message}`)
)
export const fetchRetexSetIfNeed =
(newPartialRetex?: Partial<Retex>): AppThunk =>
(dispatch, getState) => {
const { jwt, id } = getState().auth
return dispatch(fetchRetexSet(jwt, newPartialRetex || { id }))
}
export const selectRetexSet = createSelector(
(state: AppState) => state,
(state): Retex | undefined => state.retexSet?.entity
)

View File

@ -9,6 +9,7 @@ import gameDetailsUpdate from "./gameDetailsUpdate"
import miscDiscordInvitation from "./miscDiscordInvitation" import miscDiscordInvitation from "./miscDiscordInvitation"
import miscMeetingDateList from "./miscMeetingDateList" import miscMeetingDateList from "./miscMeetingDateList"
import postulantAdd from "./postulantAdd" import postulantAdd from "./postulantAdd"
import retexSet from "./retexSet"
import teamList from "./teamList" import teamList from "./teamList"
import ui from "./ui" import ui from "./ui"
import volunteerPartialAdd from "./volunteerPartialAdd" import volunteerPartialAdd from "./volunteerPartialAdd"
@ -41,6 +42,7 @@ export default (history: History) => ({
miscDiscordInvitation, miscDiscordInvitation,
miscMeetingDateList, miscMeetingDateList,
postulantAdd, postulantAdd,
retexSet,
teamList, teamList,
ui, ui,
volunteerPartialAdd, volunteerPartialAdd,

View File

@ -27,10 +27,12 @@ const selectUiData = (state: AppState) => state.ui
export const selectActiveModalId = createSelector(selectUiData, (ui) => ui.modalId) export const selectActiveModalId = createSelector(selectUiData, (ui) => ui.modalId)
export const MODAL_IDS = { export const MODAL_IDS = {
BRUNCH: "BRUNCH",
DAYWISHES: "DAYWISHES", DAYWISHES: "DAYWISHES",
HOSTING: "HOSTING", HOSTING: "HOSTING",
MEALS: "MEALS", MEALS: "MEALS",
PARTICIPATIONDETAILS: "PARTICIPATIONDETAILS", PARTICIPATIONDETAILS: "PARTICIPATIONDETAILS",
PERSONALINFO: "PERSONALINFO", PERSONALINFO: "PERSONALINFO",
RETEX: "RETEX",
TEAMWISHES: "TEAMWISHES", TEAMWISHES: "TEAMWISHES",
} }