Improve registration form

This commit is contained in:
pikiou 2022-04-08 16:17:35 +02:00
parent 7fc3ec08ba
commit 1936cd34a3
11 changed files with 780 additions and 238 deletions

BIN
src/app/img/bene2019.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
src/app/img/pel2016.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
src/app/img/pel2017.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
src/app/img/plan2019.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

View File

@ -1,24 +1,31 @@
import { FC, ReactNode } from "react" import { FC, ReactNode } from "react"
import { toastError } from "../../../store/utils"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
type Props = { type Props = {
type?: "grey" type?: "grey"
disabled?: boolean
children: ReactNode children: ReactNode
onClick?: () => void onClick?: () => void
} }
const FormButton: FC<Props> = ({ type, children, onClick }): JSX.Element => ( const FormButton: FC<Props> = ({ type, disabled, children, onClick }): JSX.Element => {
<button const onDisabledClick = () => toastError("Bouton désactivé")
type="button"
className={type === "grey" ? styles.greyButton : styles.button} return (
onClick={onClick} <button
> type="button"
{children} className={type === "grey" || disabled ? styles.greyButton : styles.button}
</button> onClick={disabled ? onDisabledClick : onClick}
) >
{children}
</button>
)
}
FormButton.defaultProps = { FormButton.defaultProps = {
type: undefined, type: undefined,
disabled: false,
onClick: undefined, onClick: undefined,
} }

View File

@ -1,4 +1,4 @@
import React, { memo, useState } from "react" import React, { memo, useEffect, useState } from "react"
import { useSelector, shallowEqual } from "react-redux" import { useSelector, shallowEqual } from "react-redux"
import { toast } from "react-toastify" import { toast } from "react-toastify"
import _ from "lodash" import _ from "lodash"
@ -7,11 +7,13 @@ import styles from "./styles.module.scss"
import { fetchPostulantAdd } from "../../store/postulantAdd" import { fetchPostulantAdd } from "../../store/postulantAdd"
import { AppDispatch, AppState } from "../../store" import { AppDispatch, AppState } from "../../store"
import { fetchVolunteerPartialAdd } from "../../store/volunteerPartialAdd" import { fetchVolunteerPartialAdd } from "../../store/volunteerPartialAdd"
import FormButton from "../Form/FormButton/FormButton"
interface Props { interface Props {
dispatch: AppDispatch dispatch: AppDispatch
} }
let backgroundId = 1
const RegisterForm = ({ dispatch }: Props): JSX.Element => { const RegisterForm = ({ dispatch }: Props): JSX.Element => {
const [potentialVolunteer, setPotentialVolunteer] = useState(true) const [potentialVolunteer, setPotentialVolunteer] = useState(true)
const [firstname, setFirstname] = useState("") const [firstname, setFirstname] = useState("")
@ -20,66 +22,102 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => {
const [mobile, setMobile] = useState("") const [mobile, setMobile] = useState("")
const [alreadyVolunteer, setAlreadyVolunteer] = useState(false) const [alreadyVolunteer, setAlreadyVolunteer] = useState(false)
const [comment, setComment] = useState("") const [comment, setComment] = useState("")
const [alreadyCame, setAlreadyCame] = useState(true)
const [firstMeeting, setFirstMeeting] = useState("")
const [commentFirstMeeting, setCommentFirstMeeting] = useState("")
const [canHelpBefore, setCanHelpBefore] = useState("")
const [howToContact, setHowToContact] = useState("Email")
const [sending, setSending] = useState(false) const [sending, setSending] = useState(false)
const [changingBackground, setChangingBackground] = useState(styles.pelImg1)
const onNewVolunteer = (e: React.ChangeEvent<HTMLInputElement>) => useEffect(() => {
setPotentialVolunteer(!e.target.value) setInterval(() => {
const onPotentialVolunteer = (e: React.ChangeEvent<HTMLInputElement>) => backgroundId = backgroundId === 1 ? 2 : 1
setPotentialVolunteer(!!e.target.value) setChangingBackground(backgroundId === 1 ? styles.pelImg1 : styles.pelImg2)
}, 20000)
}, [setChangingBackground])
const onFirstnameChanged = (e: React.ChangeEvent<HTMLInputElement>) => const sendTextDispatch =
setFirstname(e.target.value) (dispatchSetter: React.Dispatch<React.SetStateAction<string>>) =>
const onLastnameChanged = (e: React.ChangeEvent<HTMLInputElement>) => (e: React.ChangeEvent<HTMLInputElement>) =>
setLastname(e.target.value) dispatchSetter(e.target.value)
const onEmailChanged = (e: React.ChangeEvent<HTMLInputElement>) => setEmail(e.target.value) const sendTextareaDispatch =
const onMobileChanged = (e: React.ChangeEvent<HTMLInputElement>) => setMobile(e.target.value) (dispatchSetter: React.Dispatch<React.SetStateAction<string>>) =>
(e: React.ChangeEvent<HTMLTextAreaElement>) =>
dispatchSetter(e.target.value)
const onAlreadyVolunteer = (e: React.ChangeEvent<HTMLInputElement>) => const sendBooleanRadioboxDispatch =
setAlreadyVolunteer(!!e.target.value) (dispatchSetter: React.Dispatch<React.SetStateAction<boolean>>, isYes: boolean) =>
const onNotYesVolunteer = (e: React.ChangeEvent<HTMLInputElement>) => (e: React.ChangeEvent<HTMLInputElement>) =>
setAlreadyVolunteer(!e.target.value) dispatchSetter(isYes ? !!e.target.value : !e.target.value)
const onCommentChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => const sendRadioboxDispatch =
setComment(e.target.value) (dispatchSetter: React.Dispatch<React.SetStateAction<string>>) =>
(e: React.ChangeEvent<HTMLInputElement>) =>
dispatchSetter(e.target.value)
const onSubmit = () => { const onSubmit = () => {
if (firstname && lastname && email && mobile && !sending) { if (firstname && lastname && email && mobile && !sending) {
if (potentialVolunteer) { if (potentialVolunteer) {
/*
potentialVolunteer,
firstname,
lastname,
email,
mobile,
comment,
alreadyCame,
firstMeeting,
commentFirstMeeting,
canHelpBefore,
howToContact,
*/
dispatch( dispatch(
fetchPostulantAdd({ fetchPostulantAdd({
potential: true,
firstname, firstname,
lastname, lastname,
email, email,
mobile, mobile,
potential: true, howToContact,
alreadyCame,
firstMeeting,
commentFirstMeeting: firstMeeting ? "" : commentFirstMeeting,
comment, comment,
}) })
) )
} else { } else {
dispatch(
fetchPostulantAdd({
firstname,
lastname,
email,
mobile,
potential: false,
comment,
})
)
dispatch( dispatch(
fetchVolunteerPartialAdd({ fetchVolunteerPartialAdd({
firstname, firstname,
lastname, lastname,
email, email,
mobile, mobile,
howToContact,
canHelpBefore,
})
)
dispatch(
fetchPostulantAdd({
potential: false,
firstname,
lastname,
email,
mobile,
howToContact,
alreadyCame,
firstMeeting,
commentFirstMeeting: firstMeeting ? "" : commentFirstMeeting,
comment,
}) })
) )
} }
setSending(true) setSending(true)
} else { } else {
toast.warning("Il faut remplir tous les champs (sauf le dernier)", { toast.warning("Il faut remplir les queques infos sur toi ><", {
position: "top-center", position: "top-center",
autoClose: 6000, autoClose: 6000,
hideProgressBar: true, hideProgressBar: true,
@ -116,191 +154,560 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => {
if (sending) { if (sending) {
sendingElement = <span className={styles.sending}>Envoi en cours...</span> sendingElement = <span className={styles.sending}>Envoi en cours...</span>
} }
/*
firstname
lastname
mail
tel
j'ai déjà é bénévole pour PEL
un petit mot...
*/
return ( const intro = (
<form onSubmit={onSubmit}> <dl className={styles.registerIntro}>
<dl className={styles.preRegisterIntro} key="preRegister-intro"> <dt>Qu&apos;est-ce que Paris est Ludique ?</dt>
<dt>Qu&apos;est-ce que Paris est Ludique ?</dt> <dd>
<dd> <p>
<p> Un festival en plein air dédié 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. Les samedi 2 et dimanche 3 juillet 2022 !
toutes leurs formes. </p>
</p> <p>
<p> En 2019 lors de la dernière édition, ce sont <b>16 000</b> joueurs qui se sont
En 2019 lors de la dernière édition, ce sont <b>16 000</b> joueurs qui se réunis sous 300 chapiteaux et 2 000 tables.
sont réunis sous 300 chapiteaux et 2 000 tables. </p>
</p> <p>
<p> Les 2 jours que durent le festival sont entièrement dédiés à ce que le public{" "}
Les 2 jours que durent le festival sont entièrement dédiés à ce que le <b>JOUE</b>, que ce soit sur les stands d&apos;éditeurs, d&apos;associations,
public <b>JOUE</b>, que ce soit sur les stands d&apos;éditeurs, d&apos;animateurs bénévoles, du coin des petits joueurs, de l&apos;espace
d&apos;associations, d&apos;animateurs bénévoles, du coin des petits tournois, ou de l&apos;espace prototypes.
joueurs, de l&apos;espace tournois, ou de l&apos;espace prototypes. </p>
</p> <div id="pelImg" className={changingBackground}>
</dd> {" "}
<dt>Et les bénévoles de PeL ?</dt> </div>
<dd> </dd>
<p> <dt>Et les bénévoles de PeL ?</dt>
L&apos;organisation du festival est <b>entièrement gérée par nous</b>, les <dd>
bénévoles. À aucun moment ça ne ressemble à du travail : nous faisons tout <p>
pour passer <b>un aussi bon moment que les visiteurs</b> :) L&apos;organisation du festival est <b>entièrement gérée par nous</b>, les
</p> bénévoles. À aucun moment ça ne ressemble à du travail : nous faisons tout pour
<p> passer <b>un aussi bon moment que les visiteurs</b> :)
D&apos;ailleurs, un soir par mois nous nous réunissons pour un apéro ludique </p>
discuter de l&apos;organisation ! On joue autant que les visiteurs, mais <p>
sur toute l&apos;année ^^ D&apos;ailleurs, un soir par mois nous nous réunissons pour un apéro ludique
</p> discuter de l&apos;organisation ! On joue autant que les visiteurs, mais sur
<p> toute l&apos;année ^^
Pendant le festival de 2019, nous étions <b>187 bénévoles</b> organisés en </p>
équipes qui chouchoutent les visiteurs en les accueillant, en <p>
s&apos;assurant que tout se passe bien, ou encore en expliquant des règles Pendant le festival de 2019, nous étions <b>187 bénévoles</b> organisés en
de jeux. équipes qui chouchoutent les visiteurs en les accueillant, en s&apos;assurant
</p> que tout se passe bien, ou encore en expliquant des règles de jeux.
<p> </p>
Une équipe est même dédiée au bien être des bénévoles en leur servant à <p>
boire et à manger dans un espace à part faire des pauses régulières. Et Une équipe est même dédiée au bien être des bénévoles en leur servant à boire et
puis nous hébergeons ceux d&apos;entre nous qui habitent loin de Paris. Le à manger dans un espace à part faire des pauses régulières. Et puis nous
confort avant tout ! hébergeons ceux d&apos;entre nous qui habitent loin de Paris. Le confort avant
</p> tout !
<p> </p>
La majorité d&apos;entre nous sommes bénévoles les <b>samedi et dimanche</b> <p>
, mais certains bénévoles ne sont pas disponibles les deux jours. On leur La majorité d&apos;entre nous sommes bénévoles les <b>samedi et dimanche</b>,
demande alors d&apos;aider à la mise en place jeudi ou vendredi, ou au mais certains bénévoles ne sont pas disponibles les deux jours. On leur demande
rangement le lundi. Bref, chacun participe comme il peut mais deux jours alors d&apos;aider à la mise en place jeudi ou vendredi, ou au rangement le
minimum ! lundi, à la place d'un des jours du weekend. Bref, chacun participe comme il
</p> peut mais deux jours minimum !
<p> </p>
Le samedi soir quand les visiteurs sont partis, nous prolongeons la fête en <p>
dînant avec les exposants présents sur le festival. Le samedi soir quand les visiteurs sont partis, nous prolongeons la fête en
</p> dînant avec les exposants présents sur le festival. Le dimanche rebelote juste
</dd> entre bénévoles.
<dt> </p>
Si l&apos;expérience vous tente, remplissez le formulaire suivant pour devenir <div className={styles.beneImg}> </div>
bénévoles !<br /> </dd>
Vous pouvez aussi juste nous rencontrer avant de vous décider à devenir <dt>
bénévole, on comprend qu&apos;un saut dans l&apos;inconnu soit difficile. Si l&apos;expérience vous tente, remplissez le formulaire suivant pour devenir
<br /> bénévole !<br />
Dans les deux cas, venez nous rencontrer mardi 22 mars près de Châtelet, détails Vous pouvez aussi juste nous rencontrer avant de vous décider à devenir bénévole, on
après l&apos;inscription :) comprend qu&apos;un saut pareil dans l&apos;inconnu soit difficile.
<br /> <br />
</dt> Dans les deux cas, venez rencontrer une poignée d'entre nous dans un bar/resto près
<dd> de Châtelet ! :) Sur inscription uniquement...
<div className={styles.formLine} key="line-potential-volunteer"> <br />
<div> </dt>
Je veux devenir bénévole </dl>
)
const potentialVolunteerQuestion = (
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.multipleChoiceTitle}>Je veux devenir bénévole :</div>
</div>
<div className={styles.rightCol}>
{["Tout de suite !", "Peut-être après une rencontre avec des bénévoles"].map(
(option) => (
<label className={styles.longAnswerLabel} key={option}>
<input <input
type="radio" type="radio"
name="potentialVolunteer" name="potentialVolunteer"
id="potentialVolunteer-yes" onChange={sendBooleanRadioboxDispatch(
className={styles.inputRadio} setPotentialVolunteer,
checked={!potentialVolunteer} option !== "Tout de suite !"
onChange={onNewVolunteer} )}
/> checked={potentialVolunteer === (option !== "Tout de suite !")}
<label htmlFor="potentialVolunteer-yes">Tout de suite !</label> />{" "}
<input {option}
type="radio" </label>
name="potentialVolunteer" )
id="potentialVolunteer-no" )}
className={styles.inputRadio} </div>
checked={potentialVolunteer} </div>
onChange={onPotentialVolunteer} )
/>
<label htmlFor="potentialVolunteer-no"> const alreadyVolunteerQuestion = !potentialVolunteer && (
Peut-être après une rencontre avec des bénévoles <>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.multipleChoiceTitle}>J'ai déjà é bénévole à PeL</div>
</div>
<div className={styles.rightCol}>
<div className={styles.rightColContainer}>
{["Oui", "Non"].map((option) => (
<label className={styles.shortAnswerLabel} key={option}>
<input
type="radio"
name="alreadyVolunteer"
onChange={sendBooleanRadioboxDispatch(
setAlreadyVolunteer,
option === "Oui"
)}
checked={alreadyVolunteer === (option === "Oui")}
/>{" "}
{option}
</label> </label>
</div> ))}
</div> </div>
<div className={styles.formLine} key="line-firstname"> </div>
<label htmlFor="firstname">Prénom</label> </div>
<input
type="text" {alreadyVolunteer && (
id="firstname" <dl className={styles.registerIntro}>
required <dd>
value={firstname} <p>Dans ce cas pourquoi t'inscris-tu ici ? ^^</p>
onChange={onFirstnameChanged} <p>
/> Si tu te rappelles de l'email que tu avais utilisé à ta dernière
inscription sur le site Force Orange des bénévoles (même sur l'ancienne
version) tu peux{" "}
<a href="/sidentifier" target="_blank" rel="noreferrer">
t'identifier ici
</a>{" "}
avec ton ancien mot de passe, ou en{" "}
<a href="/sinscrire" target="_blank" rel="noreferrer">
demander un nouveau ici
</a>
.
</p>
<p>
Autrement, si tu as changé d'email, mieux vaut nous le communiquer à
benevoles@parisestludique.fr en précisant bien tes nom et prénom :)
</p>
</dd>
</dl>
)}
</>
)
const commentQuestion = (
<dl className={styles.inputWrapper}>
<dd className={styles.commentWrapper}>
<textarea
name="message"
id="message"
className={styles.inputWrapper}
placeholder="Peux-tu nous dire ici comment tu as connu le festival, ce qui te motive à nous rejoindre, quelles compétences tu aimerais éventuellement développer ou utiliser... ou tu n'y as pas trop réfléchi et tu trouveras en discutant avec nous :)"
value={comment}
onChange={sendTextareaDispatch(setComment)}
/>
</dd>
</dl>
)
const cameAsVisitor = (
<>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.multipleChoiceTitle}>
Es-tu déjà venu à PeL en tant que visiteur ?
</div> </div>
<div className={styles.formLine} key="line-lastname"> </div>
<label htmlFor="lastname">Nom</label> <div className={styles.rightCol}>
<input <div className={styles.rightColContainer}>
type="text" {["Oui", "Non"].map((option) => (
id="lastname" <label className={styles.shortAnswerLabel} key={option}>
required <input
value={lastname} type="radio"
onChange={onLastnameChanged} name="alreadyCame"
/> onChange={sendBooleanRadioboxDispatch(
</div> setAlreadyCame,
<div className={styles.formLine} key="line-email"> option === "Oui"
<label htmlFor="email">Email</label> )}
<input checked={alreadyCame === (option === "Oui")}
type="email" />{" "}
id="email" {option}
required </label>
value={email} ))}
onChange={onEmailChanged}
/>
</div>
<div className={styles.formLine} key="line-mobile">
<label htmlFor="mobile">Téléphone</label>
<input
type="text"
id="mobile"
required
value={mobile}
onChange={onMobileChanged}
/>
</div>
<div className={styles.formLine} key="line-already-volunteer">
<div>
J&apos;ai déjà é bénévole à PeL
<input
type="radio"
name="alreadyVolunteer"
id="alreadyVolunteer-yes"
className={styles.inputRadio}
checked={alreadyVolunteer}
onChange={onAlreadyVolunteer}
/>
<label htmlFor="alreadyVolunteer-yes">Oui</label>
<input
type="radio"
name="alreadyVolunteer"
id="alreadyVolunteer-no"
className={styles.inputRadio}
checked={!alreadyVolunteer}
onChange={onNotYesVolunteer}
/>
<label htmlFor="alreadyVolunteer-no">Non</label>
</div>
</div>
<div className={styles.formLine} key="line-message">
<textarea
name="message"
id="message"
placeholder="Dis-nous ici comment tu as connu le festival, ce qui te motive à nous rejoindre, quelles compétences tu aimerais développer ou utiliser... ou tu n'y as pas trop réfléchi et tu trouveras en discutant avec nous :)"
value={comment}
onChange={onCommentChanged}
/>
</div>
<div className={styles.formButtons}>
<button type="button" onClick={onSubmit} disabled={sending}>
Envoyer
</button>
</div>
<div className={styles.formReactions}>
{sendingElement}
{sendSuccess}
{sendError}
</div> </div>
</div>
</div>
{!alreadyCame && (
<dl className={styles.registerIntro}>
<dt>Dans ce cas laisse-moi t'en dire un peu plus sur le festival !</dt>
<dd>
<p>
Il a lieu peu après la Foire du Trône et au même emplacement, sur la{" "}
<a
href="https://www.google.com/maps/place/Pelouse+de+Reuilly,+75012+Paris/@48.8301639,2.4043365,17z/data=!3m1!4b1!4m5!3m4!1s0x47e67258d44aa311:0x2c6a08bb6aa88f4d!8m2!3d48.8301604!4d2.4065252?hl=en"
target="_blank"
rel="noreferrer"
>
"pelouse" de Reuilly
</a>
. En voici le plan de 2019, quand il s'étendait sur 2 hectares pour
accueillir 16 000 visiteurs. La plupart des rectangles colorés que tu
vois dessus sont d'énormes barnums, ou agglomérats de tonnelles.
</p>
<div className={styles.planImg}> </div>
<p>
Les espaces jeux bleu, violet, gris, ou marron sont installés et animés
par des éditeurs professionnels. Des pros gèrent les zones de
restauration rouges. Tout le reste est tenu par des associations ou des
bénévoles du festival.
</p>
<p>
Après l'édition de 2019, on a fait cette petite vidéo qui donne une
bonne impression de l'ambiance :{" "}
<a
href="https://www.youtube.com/watch?v=eVuQaERb7EU"
target="_blank"
rel="noreferrer"
>
https://www.youtube.com/watch?v=eVuQaERb7EU
</a>
</p>
<p>
Et des visiteurs passionnés (
<a
href="https://www.youtube.com/c/RoadNTroll"
target="_blank"
rel="noreferrer"
>
Road N Troll
</a>
) ont fait cette présentation plus en détail des différentes zones en
2018. J'ai coupé les présentations de jeux mais tout le reste est encore
d'actualité :{" "}
<a
href="https://www.youtube.com/watch?v=jSCHWqjHJIQ"
target="_blank"
rel="noreferrer"
>
https://www.youtube.com/watch?v=jSCHWqjHJIQ
</a>
</p>
</dd>
</dl>
)}
</>
)
const meeting = (
<>
<dl className={styles.registerIntro}>
{!potentialVolunteer && <dt>Faisons connaissance !</dt>}
{potentialVolunteer && (
<dt>Se rencontrer avant de se décider à devenir bénévole ?</dt>
)}
<dd>
<p>
On organise des rencontres entre de nouvelles personnes comme toi, et des
bénévoles suffisamment expérimentés pour te parler en détail du festival et
répondre à toutes tes questions liées au bénévolat ou au festival.
</p>
<p>
Ces rencontres ont lieu dans un bar/resto calme à Châtelet, le{" "}
<a
href="https://goo.gl/maps/N5NYWDF66vNQDFMh8"
target="_blank"
rel="noreferrer"
>
Street Food Market
</a>
.
</p>
</dd> </dd>
</dl> </dl>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.multipleChoiceTitle}>
À quelle date pourrais-tu venir ?
</div>
</div>
<div className={styles.rightCol}>
<div className={styles.rightColContainer}>
{[
{ value: "20avril", desc: "Mercredi 20 avril à 19h" },
{ value: "13mai", desc: "Vendredi 13 mai à 19h30" },
{ value: "", desc: "Aucune date possible" },
].map((option) => (
<label className={styles.longAnswerLabel} key={option.value}>
<input
type="radio"
name="firstMeeting"
value={option.value}
onChange={sendRadioboxDispatch(setFirstMeeting)}
checked={firstMeeting === option.value}
/>{" "}
{option.desc}
</label>
))}
</div>
</div>
</div>
{firstMeeting !== "" && (
<dl className={styles.registerIntro}>
<dd>
<p>
Top ! On fait en sorte qu'il y ait assez de bénévole expérimentés pour
les nombreux curieux comme toi, donc pour ne pas gâcher leur temps on
compte sur ta présence :)
</p>
<p>Si tu as un contre-temps, écris-nous à benevoles@parisestludique.fr</p>
<p>À très bientôt !</p>
</dd>
</dl>
)}
{firstMeeting === "" && (
<div className={styles.inputWrapper}>
<div className={styles.commentWrapper}>
<textarea
name="commentFirstMeeting"
id="commentFirstMeeting"
className={styles.inputWrapper}
placeholder={
potentialVolunteer
? "Mince. Quelles dates t'arrangeraient ? Ou si c'est plus simple, quels jours sont à éviter ? Est-ce trop loin de chez toi ? Préfères-tu nous rencontrer en visio ?"
: "Ce n'est pas obligé mais ça aurait été top ! Manques-tu de temps ? Préfères-tu une autre date ? Est-ce trop loin de chez toi ? Préfères-tu nous rencontrer en visio ?"
}
value={commentFirstMeeting}
onChange={sendTextareaDispatch(setCommentFirstMeeting)}
/>
</div>
</div>
)}
</>
)
const helpBefore = !potentialVolunteer && (
<>
<dl className={styles.registerIntro}>
<dt>Bénévolat en amont du festival</dt>
<dd>
<p>
En tant que bénévole, tu fais selon tes envies, tes disponibilités, ton
énergie. Si personne ne veut faire quelque chose de primordial pour le
festival, on paye quelqu'un de l'extérieur. Par exemple le transport+montage
des tentes+tables, ou la sécurité de nuit. Et si ce quelque chose n'est pas
primordiale et que personne ne veut s'en occuper, bah tant pis on le fait
pas ^^
</p>
<p>
Après on essaye de faire plein de choses sans aide extérieure. Pour le
plaisir de collaborer à un projet entre bénévoles parfois devenus amis, pour
aquérir de nouvelles compétences, parce que chaque économie d'argent fait
baisser le prix d'entrée au festival et contribue à le rendre plus
accessible.
</p>
</dd>
</dl>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.multipleChoiceTitle}>
Bref, as-tu le temps et l'envie de voir si tu peux aider en amont du
festival ?
</div>
</div>
<div className={styles.rightCol}>
<div className={styles.rightColContainer}>
{[
{ value: "oui", desc: "Oui" },
{ value: "non", desc: "Non" },
{ value: "", desc: "Ne sais pas" },
].map((option) => (
<label className={styles.shortAnswerLabel} key={option.value}>
<input
type="radio"
name="canHelpBefore"
value={option.value}
onChange={sendRadioboxDispatch(setCanHelpBefore)}
checked={canHelpBefore === option.value}
/>{" "}
{option.desc}
</label>
))}
</div>
</div>
</div>
<dl className={styles.registerIntro}>
<dd>
{canHelpBefore === "oui" && (
<p>
Génial ! Quand tu auras fini de t'inscrire et que tu seras identifié sur
le site, nous t'en parlerons plus en détail.
</p>
)}
{canHelpBefore === "non" && (
<p>
Aucun soucis tu nous seras d'une aide précieuse le jour J c'est déjà
énorme !
</p>
)}
<p>
Si tu changes d'avis, il sera possible de revenir sur cette décision dans
ton profil sur le site.
</p>
</dd>
</dl>
</>
)
const nameMobileEmail = (
<>
<dl className={styles.registerIntro}>
<dt>Quelques infos sur toi</dt>
</dl>
<div className={styles.inputWrapper}>
<div className={styles.leftColTiny}>
<label htmlFor="firstname">Prénom</label>
</div>
<div className={styles.rightColLefter}>
<input
type="text"
id="firstname"
required
value={firstname}
onChange={sendTextDispatch(setFirstname)}
/>
</div>
</div>
<div className={styles.inputWrapper}>
<div className={styles.leftColTiny}>
<label htmlFor="lastname">Nom</label>
</div>
<div className={styles.rightColLefter}>
<input
type="text"
id="lastname"
required
value={lastname}
onChange={sendTextDispatch(setLastname)}
/>
</div>
</div>
<div className={styles.inputWrapper}>
<div className={styles.leftColTiny}>
<label htmlFor="email">Email</label>
</div>
<div className={styles.rightColLefter}>
<input
type="email"
id="email"
required
value={email}
onChange={sendTextDispatch(setEmail)}
/>
</div>
</div>
<div className={styles.inputWrapper}>
<div className={styles.leftColTiny}>
<label htmlFor="mobile">Téléphone</label>
</div>
<div className={styles.rightColLefter}>
<input
type="text"
id="mobile"
required
value={mobile}
onChange={sendTextDispatch(setMobile)}
/>
</div>
</div>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.multipleChoiceTitle}>
Par quel moyen fiable et rapide préfères-tu être contacté si on en a besoin
?
</div>
</div>
<div className={styles.rightCol}>
<div className={styles.rightColContainer}>
{["Email", "SMS", "WhatsApp", "Signal", "Appeler", "Aucun"].map(
(option) => (
<label className={styles.shortAnswerLabel} key={option}>
<input
type="radio"
name="howToContact"
value={option}
onChange={sendRadioboxDispatch(setHowToContact)}
checked={howToContact === option}
/>{" "}
{option}
</label>
)
)}
</div>
</div>
</div>
{howToContact === "Aucun" && (
<dl className={styles.registerIntro}>
<dd>
<p>
Aïe ça va poser problème, je suis désolé. Il faut faire un effort en
choisir un moyen de communication proposé.
</p>
<p>
Tu en connais un meilleur que ceux proposés et suffisemment répendu ?
Parle-nous en à benevoles@parisestludique.fr :)
</p>
</dd>
</dl>
)}
</>
)
const submitButton = (
<>
<div className={styles.buttonWrapper}>
<FormButton onClick={onSubmit} disabled={!potentialVolunteer && alreadyVolunteer}>
Envoyer
</FormButton>
</div>
<div className={styles.formReactions}>
{sendingElement}
{sendSuccess}
{sendError}
</div>
</>
)
return (
<form>
{intro}
{potentialVolunteerQuestion}
{alreadyVolunteerQuestion}
{(potentialVolunteer || !alreadyVolunteer) && (
<>
{commentQuestion}
{cameAsVisitor}
{meeting}
{helpBefore}
{nameMobileEmail}
{howToContact !== "Aucun" && submitButton}
</>
)}
</form> </form>
) )
} }

View File

@ -1,7 +1,7 @@
@import "../../theme/variables"; @import "../../theme/variables";
@import "../../theme/mixins"; @import "../../theme/mixins";
.preRegisterIntro { .registerIntro {
dt { dt {
font-weight: bold; font-weight: bold;
margin-top: 10px; margin-top: 10px;
@ -20,37 +20,68 @@
font-weight: normal; font-weight: normal;
} }
.formLine { .inputWrapper {
padding: 5px 0; padding: 5px 0;
margin: 10px 0;
label { @include desktop {
display: block; display: flex;
margin-left: 5px;
} }
input,
textarea { input[type="text"] {
width: 100%; min-width: 175px;
padding: 4px; border: 1px solid $color-grey-medium;
border: 1px solid #333;
border-radius: 4px;
outline: 0; outline: 0;
} }
textarea {
height: 100px;
}
.inputRadio {
margin-left: 12px;
width: inherit;
}
.inputRadio + label {
display: inline;
margin: 0 0 0 5px;
}
} }
.formButtons { .leftCol {
margin-top: 10px; flex: 0 0 240px;
padding: 5px 0; }
.leftColTiny {
flex: 0 0 120px;
}
.rightCol,
.rightColLefter {
width: 100%;
text-align: center;
}
.rightCol {
text-align: center;
}
.rightColLefter {
text-align: left;
}
.rightColContainer {
display: inline-block;
width: 300px;
text-align: left;
}
.multipleChoiceTitle {
display: inline-block;
width: 240px;
margin-bottom: 10px;
}
.longAnswerLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 300px;
}
.shortAnswerLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 100px;
}
.buttonWrapper {
margin-bottom: 10px;
text-align: center; text-align: center;
[disabled="true"] { [disabled="true"] {
@ -59,6 +90,20 @@
} }
} }
.commentWrapper {
width: 100%;
margin: 0 0 14px;
textarea {
width: 100%;
height: 120px;
padding: 5px;
border: 1px solid $color-grey-light;
background-color: $color-grey-lighter;
outline: 0;
}
}
.formReactions { .formReactions {
margin-top: 3px; margin-top: 3px;
padding: 5px 0; padding: 5px 0;
@ -74,3 +119,58 @@
color: rgb(255, 0, 0); color: rgb(255, 0, 0);
} }
} }
.pelImg1 {
background: url("../../app/img/pel2016.jpg") no-repeat center center;
}
.pelImg2 {
background: url("../../app/img/pel2017.jpg") no-repeat center center;
}
.pelImg1,
.pelImg2 {
position: relative;
width: calc(90vw);
height: calc(60vw);
background-size: cover;
background-size: cover;
background-size: cover;
background-size: cover;
transition: background 2000ms ease-in-out 3000ms;
@include desktop {
width: 552px;
height: 368px;
}
}
.beneImg {
position: relative;
width: calc(90vw);
height: calc(40vw);
background: url("../../app/img/bene2019.jpg") no-repeat center center;
background-size: cover;
background-size: cover;
background-size: cover;
background-size: cover;
@include desktop {
width: 552px;
height: 249px;
}
}
.planImg {
position: relative;
width: calc(90vw);
height: calc(168vw);
background: url("../../app/img/plan2019.jpg") no-repeat center center;
background-size: cover;
background-size: cover;
background-size: cover;
background-size: cover;
@include desktop {
width: 552px;
height: 1028px;
}
}

View File

@ -28,6 +28,12 @@ export const postulantAdd = expressAccessor.add(async (list, body) => {
firstname: trim(params.firstname), firstname: trim(params.firstname),
email: trim(params.email), email: trim(params.email),
mobile: canonicalMobile(params.mobile), mobile: canonicalMobile(params.mobile),
howToContact: trim(params.howToContact),
potential: params.potential === true,
alreadyCame: params.alreadyCame === true,
firstMeeting: trim(params.firstMeeting),
commentFirstMeeting: trim(params.commentFirstMeeting),
comment: trim(params.comment),
}) })
return { return {

View File

@ -47,6 +47,8 @@ export const volunteerPartialAdd = expressAccessor.add(async (list, body) => {
firstname: trim(params.firstname), firstname: trim(params.firstname),
email: trim(params.email), email: trim(params.email),
mobile: canonicalMobile(params.mobile), mobile: canonicalMobile(params.mobile),
howToContact: trim(params.howToContact),
canHelpBefore: trim(params.canHelpBefore),
password1: passwordHash, password1: passwordHash,
password2: passwordHash, password2: passwordHash,
}) })

View File

@ -9,8 +9,16 @@ export class Postulant {
mobile = "" mobile = ""
howToContact = ""
potential = false potential = false
alreadyCame = false
firstMeeting = ""
commentFirstMeeting = ""
comment = "" comment = ""
} }
@ -20,7 +28,11 @@ export const translationPostulant: { [k in keyof Postulant]: string } = {
lastname: "nom", lastname: "nom",
email: "email", email: "email",
mobile: "telephone", mobile: "telephone",
howToContact: "commentContacter",
potential: "potentiel", potential: "potentiel",
alreadyCame: "déjàVenu",
firstMeeting: "dateRencontre",
commentFirstMeeting: "commentaireDateRencontre",
comment: "commentaire", comment: "commentaire",
} }

View File

@ -34,6 +34,10 @@ export class Volunteer implements VolunteerPartial {
teamWishesComment = "" teamWishesComment = ""
howToContact = ""
canHelpBefore = ""
hiddenAsks: number[] = [] hiddenAsks: number[] = []
created = new Date() created = new Date()
@ -65,6 +69,8 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
food: "alimentation", food: "alimentation",
teamWishes: "enviesEquipe", teamWishes: "enviesEquipe",
teamWishesComment: "commentaireEnviesEquipe", teamWishesComment: "commentaireEnviesEquipe",
howToContact: "commentContacter",
canHelpBefore: "aideEnAmont",
hiddenAsks: "questionsCachees", hiddenAsks: "questionsCachees",
created: "creation", created: "creation",
password1: "passe1", password1: "passe1",
@ -109,6 +115,8 @@ export const volunteerExample: Volunteer = {
food: "Végétarien", food: "Végétarien",
teamWishes: [], teamWishes: [],
teamWishesComment: "", teamWishesComment: "",
howToContact: "",
canHelpBefore: "",
hiddenAsks: [], hiddenAsks: [],
created: new Date(0), created: new Date(0),
password1: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPkdq9d5fqpbl8ASimSjNj4SR.9O", password1: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPkdq9d5fqpbl8ASimSjNj4SR.9O",