mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-08 08:34:20 +02:00
Add hosting form
This commit is contained in:
parent
f9a68d7cfe
commit
032e15d985
39
src/components/Asks/AskHosting.tsx
Normal file
39
src/components/Asks/AskHosting.tsx
Normal 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 ParticipationDetailsForm, {
|
||||
fetchFor as fetchForParticipationDetailsForm,
|
||||
} from "../VolunteerBoard/ParticipationDetailsForm/ParticipationDetailsForm"
|
||||
import { useUserParticipationDetails } from "../VolunteerBoard/participationDetails.utils"
|
||||
|
||||
export function AskParticipationDetails(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 [participationDetails] = useUserParticipationDetails()
|
||||
const tshirtSize = get(participationDetails, "tshirtSize", "")
|
||||
const food = get(participationDetails, "food", "")
|
||||
const needToShow = !tshirtSize || !food
|
||||
|
||||
addAsk(
|
||||
asks,
|
||||
id,
|
||||
volunteerAsks,
|
||||
false,
|
||||
needToShow,
|
||||
<ParticipationDetailsForm afterSubmit={onSubmit}>
|
||||
{answerLaterOnProfile}
|
||||
</ParticipationDetailsForm>
|
||||
)
|
||||
}
|
||||
|
||||
// Fetch server-side data here
|
||||
export const fetchFor = [...fetchForParticipationDetailsForm]
|
@ -1,6 +1,8 @@
|
||||
import { FC, memo } from "react"
|
||||
import DayWishes from "./DayWishes/DayWishes"
|
||||
import DayWishesFormModal from "./DayWishesForm/DayWishesFormModal"
|
||||
import Hosting from "./Hosting/Hosting"
|
||||
import HostingFormModal from "./HostingForm/HostingFormModal"
|
||||
import ParticipationDetails from "./ParticipationDetails/ParticipationDetails"
|
||||
import ParticipationDetailsFormModal from "./ParticipationDetailsForm/ParticipationDetailsFormModal"
|
||||
import TeamWishes from "./TeamWishes/TeamWishes"
|
||||
@ -8,6 +10,7 @@ import TeamWishesFormModal from "./TeamWishesForm/TeamWishesFormModal"
|
||||
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 fetchForParticipationDetailsForm } from "./ParticipationDetailsForm/ParticipationDetailsForm"
|
||||
import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm"
|
||||
import VolunteerTeam from "./VolunteerTeam/VolunteerTeam"
|
||||
@ -22,6 +25,8 @@ const Board: FC = (): JSX.Element => (
|
||||
<TeamWishes />
|
||||
<TeamWishesFormModal />
|
||||
<VolunteerTeam />
|
||||
<Hosting />
|
||||
<HostingFormModal />
|
||||
</>
|
||||
)
|
||||
|
||||
@ -29,6 +34,7 @@ export default memo(withUserConnected(Board))
|
||||
|
||||
export const fetchFor = [
|
||||
...fetchForDayWishesForm,
|
||||
...fetchForHostingForm,
|
||||
...fetchForParticipationDetailsForm,
|
||||
...fetchForTeamWishesForm,
|
||||
]
|
||||
|
61
src/components/VolunteerBoard/Hosting/Hosting.tsx
Normal file
61
src/components/VolunteerBoard/Hosting/Hosting.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { FC, memo, useCallback } from "react"
|
||||
import get from "lodash/get"
|
||||
import styles from "./styles.module.scss"
|
||||
import { useUserHosting } from "../hosting.utils"
|
||||
import useAction from "../../../utils/useAction"
|
||||
import { displayModal, MODAL_IDS } from "../../../store/ui"
|
||||
|
||||
const Hosting: FC = (): JSX.Element | null => {
|
||||
const [userWishes] = useUserHosting()
|
||||
const needsHosting = get(userWishes, "needsHosting", false)
|
||||
const canHostCount = get(userWishes, "canHostCount", 0)
|
||||
const distanceToFestival = get(userWishes, "distanceToFestival", 0)
|
||||
const comment = get(userWishes, "hostingComment", "")
|
||||
const execDisplayModal = useAction(displayModal)
|
||||
const onEdit = useCallback(() => execDisplayModal(MODAL_IDS.HOSTING), [execDisplayModal])
|
||||
|
||||
return (
|
||||
<div className={styles.hosting}>
|
||||
<div className={styles.title}>Mon hébergement</div>
|
||||
{!needsHosting && (
|
||||
<div className={styles.hostingLabel}>
|
||||
Je n'ai pas besoin d'un hébergement proche du festival
|
||||
</div>
|
||||
)}
|
||||
{needsHosting && (
|
||||
<div className={styles.hostingLabel}>
|
||||
J'ai <b>besoin</b> d'un hébergement proche du festival
|
||||
</div>
|
||||
)}
|
||||
{canHostCount === 0 && distanceToFestival === 0 && (
|
||||
<div className={styles.hostingLabel}>
|
||||
Je ne peux héberger personnes de manière utile.
|
||||
</div>
|
||||
)}
|
||||
{canHostCount > 0 && (
|
||||
<div className={styles.hostingLabel}>
|
||||
Je peux héberger <b>{canHostCount} personnes</b> !
|
||||
</div>
|
||||
)}
|
||||
{distanceToFestival > 0 && (
|
||||
<div className={styles.hostingLabel}>
|
||||
Je suis à <b>{distanceToFestival} minutes</b> du festival
|
||||
</div>
|
||||
)}
|
||||
|
||||
{comment && (
|
||||
<div className={styles.commentLine}>
|
||||
<span className={styles.commentLineTitle}>Mon commentaire :</span>
|
||||
<span className={styles.commentLineText}>{comment}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.editButton}>
|
||||
<button type="button" onClick={onEdit}>
|
||||
Modifier
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(Hosting)
|
53
src/components/VolunteerBoard/Hosting/styles.module.scss
Executable file
53
src/components/VolunteerBoard/Hosting/styles.module.scss
Executable file
@ -0,0 +1,53 @@
|
||||
@import "../../../theme/variables";
|
||||
@import "../../../theme/mixins";
|
||||
|
||||
.title {
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hostingLabel {
|
||||
margin-right: 5px;
|
||||
font-style: bold;
|
||||
}
|
||||
|
||||
.hosting {
|
||||
@include inner-content-wrapper();
|
||||
|
||||
position: relative;
|
||||
padding-right: 90px;
|
||||
}
|
||||
|
||||
.hostingLabel,
|
||||
.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;
|
||||
}
|
||||
}
|
133
src/components/VolunteerBoard/HostingForm/HostingForm.tsx
Normal file
133
src/components/VolunteerBoard/HostingForm/HostingForm.tsx
Normal file
@ -0,0 +1,133 @@
|
||||
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 { useUserHosting } from "../hosting.utils"
|
||||
import FormButton from "../../Form/FormButton/FormButton"
|
||||
import { fetchVolunteerHostingSetIfNeed } from "../../../store/volunteerHostingSet"
|
||||
import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton"
|
||||
|
||||
type Props = {
|
||||
children?: ReactNode | undefined
|
||||
afterSubmit?: () => void | undefined
|
||||
}
|
||||
|
||||
const HostingForm: FC<Props> = ({ children, afterSubmit }): JSX.Element => {
|
||||
const [needsHosting, setNeedsHosting] = useState(false)
|
||||
const canHostCountRef = useRef<HTMLInputElement | null>(null)
|
||||
const distanceRef = useRef<HTMLInputElement | null>(null)
|
||||
const commentRef = useRef<HTMLTextAreaElement | null>(null)
|
||||
const [userWishes, saveWishes] = useUserHosting()
|
||||
|
||||
const onNeedsHostingChange = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setNeedsHosting(e.target.checked)
|
||||
|
||||
useEffect(() => {
|
||||
if (!userWishes) return
|
||||
setNeedsHosting(get(userWishes, "needsHosting", false))
|
||||
set(canHostCountRef, "current.value", `${get(userWishes, "canHostCount", 0)}`)
|
||||
set(distanceRef, "current.value", `${get(userWishes, "distanceToFestival", 0)}`)
|
||||
set(commentRef, "current.value", get(userWishes, "hostingComment", ""))
|
||||
}, [commentRef, userWishes])
|
||||
|
||||
const onChoiceSubmit = useCallback(() => {
|
||||
const canHostCount = +get(canHostCountRef, "current.value", "0")
|
||||
const distanceToFestival = +get(distanceRef, "current.value", "0")
|
||||
const hostingComment = get(commentRef, "current.value", "")
|
||||
saveWishes(needsHosting, canHostCount, distanceToFestival, hostingComment)
|
||||
if (afterSubmit) afterSubmit()
|
||||
}, [needsHosting, commentRef, saveWishes, afterSubmit])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.title}>Mes jours de présence</div>
|
||||
<div className={classnames(styles.inputWrapper, styles.noBottomMargin)}>
|
||||
<div className={styles.leftCol}>
|
||||
<div className={styles.needsHostingTitle}>
|
||||
Cela t'arrangerait-il d'avoir un hébergement proche du festival ?
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.rightCol}>
|
||||
<label className={styles.needsHostingLabel}>
|
||||
<input
|
||||
type="checkbox"
|
||||
value="oui"
|
||||
name="needsHosting"
|
||||
onChange={onNeedsHostingChange}
|
||||
checked={needsHosting}
|
||||
/>{" "}
|
||||
Oui
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{needsHosting && (
|
||||
<div className={classnames(styles.inputWrapper, styles.noBottomMargin)}>
|
||||
<div>
|
||||
Il nous serait utile de savoir à quelle temps de transport tu te trouves
|
||||
pour privilégier les bénévoles qui viennent de province à ceux qui viennent
|
||||
de l'autre bout de Paris.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.inputWrapper}>
|
||||
<div className={styles.leftCol}>
|
||||
<div className={styles.canHostCountTitle}>
|
||||
Combien de bénévoles peux-tu héberger confortablement ?
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.rightCol}>
|
||||
<input className={styles.canHostCountLabel} type="text" ref={canHostCountRef} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.inputWrapper}>
|
||||
<div className={styles.leftCol}>
|
||||
<div className={styles.distanceToFestivalTitle}>
|
||||
À combien de minutes de transport es-tu du festival ? (En voiture si tu es
|
||||
en voiture, à vélo si tu as des vélos, sinon en transport en commun.)
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.rightCol}>
|
||||
<input
|
||||
className={styles.distanceToFestivalLabel}
|
||||
type="text"
|
||||
ref={distanceRef}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.hostingCommentWrapper}>
|
||||
<label htmlFor="hosting-comment">Un commentaire, une précision ?</label>
|
||||
<textarea id="hosting-comment" ref={commentRef} />
|
||||
</div>
|
||||
<div className={styles.buttonWrapper}>
|
||||
<FormButton onClick={onChoiceSubmit}>Enregistrer</FormButton>
|
||||
{children === undefined && (
|
||||
<>
|
||||
{" "}
|
||||
<FormButton onClick={afterSubmit} type="grey">
|
||||
Annuler
|
||||
</FormButton>{" "}
|
||||
</>
|
||||
)}
|
||||
{children !== undefined && (
|
||||
<>
|
||||
{" "}
|
||||
<IgnoreButton onClick={afterSubmit} text="Ignorer">
|
||||
{children}
|
||||
</IgnoreButton>{" "}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
HostingForm.defaultProps = {
|
||||
children: undefined,
|
||||
afterSubmit: undefined,
|
||||
}
|
||||
|
||||
export default memo(HostingForm)
|
||||
|
||||
// Fetch server-side data here
|
||||
export const fetchFor = [fetchVolunteerHostingSetIfNeed]
|
@ -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 HostingForm from "./HostingForm"
|
||||
|
||||
const HostingFormModal: FC = (): JSX.Element => {
|
||||
const execHideModal = useAction(hideModal)
|
||||
const afterFormSubmit = useCallback(() => execHideModal(), [execHideModal])
|
||||
|
||||
return (
|
||||
<Modal modalId={MODAL_IDS.HOSTING}>
|
||||
<HostingForm afterSubmit={afterFormSubmit} />
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(HostingFormModal)
|
126
src/components/VolunteerBoard/HostingForm/styles.module.scss
Executable file
126
src/components/VolunteerBoard/HostingForm/styles.module.scss
Executable file
@ -0,0 +1,126 @@
|
||||
@import "../../../theme/variables";
|
||||
@import "../../../theme/mixins";
|
||||
|
||||
.title {
|
||||
padding: 15px 0;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inputWrapper {
|
||||
margin: 25px 0;
|
||||
|
||||
@include desktop {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.noBottomMargin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.leftCol {
|
||||
flex: 0 0 320px;
|
||||
}
|
||||
|
||||
.rightCol {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.needsHostingTitle {
|
||||
display: inline-block;
|
||||
width: 320px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.needsHostingLabel {
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.hostingTitle {
|
||||
display: inline-block;
|
||||
width: 320px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.hostingList {
|
||||
@include clear-ul-style;
|
||||
|
||||
display: inline-block;
|
||||
width: 204px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hostingItem {
|
||||
display: inline-block;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.hostingButton {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
.hostingCommentWrapper {
|
||||
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;
|
||||
}
|
31
src/components/VolunteerBoard/hosting.utils.ts
Normal file
31
src/components/VolunteerBoard/hosting.utils.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { shallowEqual, useSelector } from "react-redux"
|
||||
import { useCallback } from "react"
|
||||
import { selectUserJwtToken } from "../../store/auth"
|
||||
import { AppState } from "../../store"
|
||||
import { fetchVolunteerHostingSet } from "../../store/volunteerHostingSet"
|
||||
import useAction from "../../utils/useAction"
|
||||
|
||||
export const useUserHosting = (): [any, any] => {
|
||||
const save = useAction(fetchVolunteerHostingSet)
|
||||
const jwtToken = useSelector(selectUserJwtToken)
|
||||
const userWishes = useSelector(
|
||||
(state: AppState) => state.volunteerHostingSet?.entity,
|
||||
shallowEqual
|
||||
)
|
||||
|
||||
const saveWishes = useCallback(
|
||||
(needsHosting, canHostCount, distanceToFestival, hostingComment) => {
|
||||
if (!userWishes) return
|
||||
save(jwtToken, 0, {
|
||||
id: userWishes.id,
|
||||
needsHosting,
|
||||
canHostCount,
|
||||
distanceToFestival,
|
||||
hostingComment,
|
||||
})
|
||||
},
|
||||
[userWishes, save, jwtToken]
|
||||
)
|
||||
|
||||
return [userWishes, saveWishes]
|
||||
}
|
@ -11,6 +11,7 @@ import {
|
||||
VolunteerTeamWishes,
|
||||
translationVolunteer,
|
||||
VolunteerDayWishes,
|
||||
VolunteerHosting,
|
||||
VolunteerParticipationDetails,
|
||||
VolunteerTeamAssign,
|
||||
VolunteerKnowledge,
|
||||
@ -324,6 +325,43 @@ export const volunteerDayWishesSet = expressAccessor.set(async (list, body, id)
|
||||
}
|
||||
})
|
||||
|
||||
export const volunteerHostingSet = 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 infos d'hébergement`)
|
||||
}
|
||||
const wishes = body[1] as VolunteerHosting
|
||||
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.needsHosting !== undefined) {
|
||||
newVolunteer.needsHosting = wishes.needsHosting
|
||||
}
|
||||
if (wishes.canHostCount !== undefined) {
|
||||
newVolunteer.canHostCount = wishes.canHostCount
|
||||
}
|
||||
if (wishes.distanceToFestival !== undefined) {
|
||||
newVolunteer.distanceToFestival = wishes.distanceToFestival
|
||||
}
|
||||
if (wishes.hostingComment !== undefined) {
|
||||
newVolunteer.hostingComment = wishes.hostingComment
|
||||
}
|
||||
|
||||
return {
|
||||
toDatabase: newVolunteer,
|
||||
toCaller: {
|
||||
id: newVolunteer.id,
|
||||
needsHosting: newVolunteer.needsHosting,
|
||||
canHostCount: newVolunteer.canHostCount,
|
||||
distanceToFestival: newVolunteer.distanceToFestival,
|
||||
hostingComment: newVolunteer.hostingComment,
|
||||
} as VolunteerHosting,
|
||||
}
|
||||
})
|
||||
|
||||
export const volunteerParticipationDetailsSet = expressAccessor.set(async (list, body, id) => {
|
||||
const requestedId = +body[0] || id
|
||||
if (requestedId !== id && requestedId !== 0) {
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
volunteerAsksSet,
|
||||
volunteerDayWishesSet,
|
||||
volunteerForgot,
|
||||
volunteerHostingSet,
|
||||
volunteerDiscordId,
|
||||
volunteerLogin,
|
||||
volunteerPartialAdd,
|
||||
@ -111,6 +112,7 @@ app.post(
|
||||
volunteerParticipationDetailsSet
|
||||
)
|
||||
app.post("/VolunteerDayWishesSet", secure as RequestHandler, volunteerDayWishesSet)
|
||||
app.post("/VolunteerHostingSet", secure as RequestHandler, volunteerHostingSet)
|
||||
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
|
||||
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
||||
|
||||
|
@ -59,6 +59,14 @@ export class Volunteer implements VolunteerPartial {
|
||||
bof: number[] = []
|
||||
|
||||
niet: number[] = []
|
||||
|
||||
needsHosting = false
|
||||
|
||||
canHostCount = 0
|
||||
|
||||
distanceToFestival = 0
|
||||
|
||||
hostingComment = ""
|
||||
}
|
||||
|
||||
export const translationVolunteer: { [k in keyof Volunteer]: string } = {
|
||||
@ -92,6 +100,10 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
|
||||
ok: "OK",
|
||||
bof: "Bof",
|
||||
niet: "Niet",
|
||||
needsHosting: "besoinHébergement",
|
||||
canHostCount: "nombreHébergés",
|
||||
distanceToFestival: "distanceAuFestival",
|
||||
hostingComment: "commentaireHébergement",
|
||||
}
|
||||
|
||||
export class VolunteerPartial {
|
||||
@ -137,6 +149,10 @@ export const volunteerExample: Volunteer = {
|
||||
ok: [5, 7, 24, 26, 31, 38, 50, 52, 54, 58],
|
||||
bof: [9, 12, 16, 27, 34, 35, 36],
|
||||
niet: [13, 18, 19, 23, 47, 53, 59, 67],
|
||||
needsHosting: false,
|
||||
canHostCount: 0,
|
||||
distanceToFestival: 0,
|
||||
hostingComment: "",
|
||||
}
|
||||
|
||||
export const emailRegexp =
|
||||
@ -181,6 +197,14 @@ export interface VolunteerDayWishes {
|
||||
dayWishesComment: Volunteer["dayWishesComment"]
|
||||
}
|
||||
|
||||
export interface VolunteerHosting {
|
||||
id: Volunteer["id"]
|
||||
needsHosting: Volunteer["needsHosting"]
|
||||
canHostCount: Volunteer["canHostCount"]
|
||||
distanceToFestival: Volunteer["distanceToFestival"]
|
||||
hostingComment: Volunteer["hostingComment"]
|
||||
}
|
||||
|
||||
export interface VolunteerParticipationDetails {
|
||||
id: Volunteer["id"]
|
||||
tshirtSize: Volunteer["tshirtSize"]
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
elementName,
|
||||
Volunteer,
|
||||
VolunteerDayWishes,
|
||||
VolunteerHosting,
|
||||
VolunteerAsks,
|
||||
VolunteerParticipationDetails,
|
||||
VolunteerTeamWishes,
|
||||
@ -38,6 +39,9 @@ export const volunteerTeamWishesSet =
|
||||
export const volunteerDayWishesSet =
|
||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerDayWishes>]>("DayWishesSet")
|
||||
|
||||
export const volunteerHostingSet =
|
||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerHosting>]>("HostingSet")
|
||||
|
||||
export const volunteerParticipationDetailsSet =
|
||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerParticipationDetails>]>(
|
||||
"ParticipationDetailsSet"
|
||||
|
@ -16,6 +16,7 @@ import volunteerAsksSet from "./volunteerAsksSet"
|
||||
import volunteerDayWishesSet from "./volunteerDayWishesSet"
|
||||
import volunteerDiscordId from "./volunteerDiscordId"
|
||||
import volunteerForgot from "./volunteerForgot"
|
||||
import volunteerHostingSet from "./volunteerHostingSet"
|
||||
import volunteerList from "./volunteerList"
|
||||
import volunteerLogin from "./volunteerLogin"
|
||||
import volunteerKnowledgeSet from "./volunteerKnowledgeSet"
|
||||
@ -44,6 +45,7 @@ export default (history: History) => ({
|
||||
volunteerDayWishesSet,
|
||||
volunteerDiscordId,
|
||||
volunteerForgot,
|
||||
volunteerHostingSet,
|
||||
volunteerList,
|
||||
volunteerLogin,
|
||||
volunteerKnowledgeSet,
|
||||
|
@ -28,6 +28,7 @@ export const selectActiveModalId = createSelector(selectUiData, (ui) => ui.modal
|
||||
|
||||
export const MODAL_IDS = {
|
||||
DAYWISHES: "DAYWISHES",
|
||||
HOSTING: "HOSTING",
|
||||
PARTICIPATIONDETAILS: "PARTICIPATIONDETAILS",
|
||||
TEAMWISHES: "TEAMWISHES",
|
||||
}
|
||||
|
60
src/store/volunteerHostingSet.ts
Normal file
60
src/store/volunteerHostingSet.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
||||
|
||||
import { StateRequest, toastError, elementFetch } from "./utils"
|
||||
import { VolunteerHosting } from "../services/volunteers"
|
||||
import { AppThunk, AppState } from "."
|
||||
import { volunteerHostingSet } from "../services/volunteersAccessors"
|
||||
|
||||
type StateVolunteerHostingSet = { entity?: VolunteerHosting } & StateRequest
|
||||
|
||||
export const initialState: StateVolunteerHostingSet = {
|
||||
readyStatus: "idle",
|
||||
}
|
||||
|
||||
const volunteerHostingSetSlice = createSlice({
|
||||
name: "volunteerHostingSet",
|
||||
initialState,
|
||||
reducers: {
|
||||
getRequesting: (_) => ({
|
||||
readyStatus: "request",
|
||||
}),
|
||||
getSuccess: (_, { payload }: PayloadAction<VolunteerHosting>) => ({
|
||||
readyStatus: "success",
|
||||
entity: payload,
|
||||
}),
|
||||
getFailure: (_, { payload }: PayloadAction<string>) => ({
|
||||
readyStatus: "failure",
|
||||
error: payload,
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
export default volunteerHostingSetSlice.reducer
|
||||
export const { getRequesting, getSuccess, getFailure } = volunteerHostingSetSlice.actions
|
||||
|
||||
export const fetchVolunteerHostingSet = elementFetch(
|
||||
volunteerHostingSet,
|
||||
getRequesting,
|
||||
getSuccess,
|
||||
getFailure,
|
||||
(error: Error) =>
|
||||
toastError(`Erreur lors du chargement des choix de jours de présence: ${error.message}`)
|
||||
)
|
||||
|
||||
const shouldFetchVolunteerHostingSet = (state: AppState, id: number) =>
|
||||
state.volunteerHostingSet?.readyStatus !== "success" ||
|
||||
(state.volunteerHostingSet?.entity && state.volunteerHostingSet?.entity?.id !== id)
|
||||
|
||||
export const fetchVolunteerHostingSetIfNeed =
|
||||
(id = 0, wishes: Partial<VolunteerHosting> = {}): AppThunk =>
|
||||
(dispatch, getState) => {
|
||||
let jwt = ""
|
||||
|
||||
if (!id) {
|
||||
;({ jwt, id } = getState().auth)
|
||||
}
|
||||
if (shouldFetchVolunteerHostingSet(getState(), id))
|
||||
return dispatch(fetchVolunteerHostingSet(jwt, id, wishes))
|
||||
|
||||
return null
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user