mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-08 08:34:20 +02:00
Add on site info on home page
This commit is contained in:
parent
42f3e86381
commit
4c704e87d4
98
src/components/Asks/OnSiteInfo.tsx
Normal file
98
src/components/Asks/OnSiteInfo.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { get, first, tail } from "lodash"
|
||||||
|
import { useSelector } from "react-redux"
|
||||||
|
import styles from "./styles.module.scss"
|
||||||
|
import {
|
||||||
|
fetchVolunteerOnSiteInfoIfNeed,
|
||||||
|
selectVolunteerOnSiteInfo,
|
||||||
|
} from "../../store/volunteerOnSiteInfo"
|
||||||
|
import { Contact, VolunteerOnSiteInfo } from "../../services/volunteers"
|
||||||
|
|
||||||
|
export function OnSiteInfo(): JSX.Element {
|
||||||
|
const userOnSiteInfo: VolunteerOnSiteInfo | undefined = useSelector(selectVolunteerOnSiteInfo)
|
||||||
|
const referents = get(userOnSiteInfo, "referents", [])
|
||||||
|
const members = get(userOnSiteInfo, "members", [])
|
||||||
|
// const isReferent = get(userOnSiteInfo, "isReferent", false)
|
||||||
|
const CAPilots = get(userOnSiteInfo, "CAPilots", [])
|
||||||
|
|
||||||
|
const pincipalReferent = first(referents)
|
||||||
|
const secondaryReferents = tail(referents)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key="contacts">
|
||||||
|
<div className={styles.notificationsPage}>
|
||||||
|
<div className={styles.notificationsContent}>
|
||||||
|
<div className={styles.formLine}>
|
||||||
|
<div className={styles.title}>Contacts sur la pelouse</div>
|
||||||
|
<label>
|
||||||
|
{pincipalReferent && (
|
||||||
|
<div>
|
||||||
|
Référent.e{secondaryReferents.length > 0 && <> principal.e</>} :{" "}
|
||||||
|
{contactElement(pincipalReferent)}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{secondaryReferents.length > 0 && (
|
||||||
|
<div>
|
||||||
|
Référent.e.s secondaire.s :{" "}
|
||||||
|
<div className={styles.contactList}>
|
||||||
|
{secondaryReferents.map((contact) => (
|
||||||
|
<div key={contact.firstname}>
|
||||||
|
{contactElement(contact)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div>Ton contact à la Paillante : à définir...</div>
|
||||||
|
<br />
|
||||||
|
<div>Si un exposant à une question : à définir...</div>
|
||||||
|
<br />
|
||||||
|
{CAPilots.length > 0 && (
|
||||||
|
<div>
|
||||||
|
Membre du CA si besoin :{" "}
|
||||||
|
<div className={styles.contactList}>
|
||||||
|
{CAPilots.map((contact) => (
|
||||||
|
<div key={contact.firstname}>
|
||||||
|
{contactElement(contact)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
Croix rouge présente sur le festival : tel prochainement
|
||||||
|
<br />
|
||||||
|
{members.length > 0 && (
|
||||||
|
<div>
|
||||||
|
Autre membres de l'équipe :{" "}
|
||||||
|
<div className={styles.contactList}>
|
||||||
|
{members.map((contact) => (
|
||||||
|
<div key={contact.firstname}>
|
||||||
|
{contactElement(contact)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function contactElement(contact: Contact): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className={styles.contactList}>
|
||||||
|
{contact.firstname} <a href={`tel: ${contact.mobile}`}>{contact.mobile}</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch server-side data here
|
||||||
|
export const fetchFor = [fetchVolunteerOnSiteInfoIfNeed]
|
@ -15,6 +15,8 @@ import {
|
|||||||
AskParticipationDetails,
|
AskParticipationDetails,
|
||||||
fetchFor as fetchForParticipationDetails,
|
fetchFor as fetchForParticipationDetails,
|
||||||
} from "./AskParticipationDetails"
|
} from "./AskParticipationDetails"
|
||||||
|
|
||||||
|
import { OnSiteInfo, fetchFor as fetchForOnSiteInfo } from "./OnSiteInfo"
|
||||||
// import { AskPushNotif } from "./AskPushNotif"
|
// import { AskPushNotif } from "./AskPushNotif"
|
||||||
|
|
||||||
const Asks = (): JSX.Element | null => {
|
const Asks = (): JSX.Element | null => {
|
||||||
@ -35,27 +37,10 @@ const Asks = (): JSX.Element | null => {
|
|||||||
|
|
||||||
// AskPushNotif(asks, 99)
|
// AskPushNotif(asks, 99)
|
||||||
|
|
||||||
|
const onSiteInfoElement = OnSiteInfo()
|
||||||
if (_.isEmpty(asks)) {
|
if (_.isEmpty(asks)) {
|
||||||
asks.push(
|
asks.push(onSiteInfoElement)
|
||||||
<div key="pushNotifs">
|
asks.push(asksEnd())
|
||||||
<div className={styles.notificationsPage}>
|
|
||||||
<div className={styles.notificationsContent}>
|
|
||||||
<div className={styles.formLine}>
|
|
||||||
<label>
|
|
||||||
Si tu veux changer la réponse à l'une des questions posées ici, va
|
|
||||||
dans <a href="/profil">Mon profil</a> :)
|
|
||||||
<br />
|
|
||||||
Tu as fait le tour des dernières infos ou questions importantes,
|
|
||||||
merci !
|
|
||||||
<br />
|
|
||||||
Nous te préviendrons quand il y en aura de nouvelles.
|
|
||||||
<br />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (volunteerAsks === undefined) {
|
if (volunteerAsks === undefined) {
|
||||||
@ -65,10 +50,33 @@ const Asks = (): JSX.Element | null => {
|
|||||||
return <div>{asks.map<React.ReactNode>((t) => t).reduce((prev, curr) => [prev, curr])}</div>
|
return <div>{asks.map<React.ReactNode>((t) => t).reduce((prev, curr) => [prev, curr])}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function asksEnd(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div key="pushNotifs">
|
||||||
|
<div className={styles.notificationsPage}>
|
||||||
|
<div className={styles.notificationsContent}>
|
||||||
|
<div className={styles.formLine}>
|
||||||
|
<label>
|
||||||
|
Si tu veux changer la réponse à l'une des questions posées ici, va dans{" "}
|
||||||
|
<a href="/profil">Mon profil</a> :)
|
||||||
|
<br />
|
||||||
|
Tu as fait le tour des dernières infos ou questions importantes, merci !
|
||||||
|
<br />
|
||||||
|
Nous te préviendrons quand il y en aura de nouvelles.
|
||||||
|
<br />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default memo(Asks)
|
export default memo(Asks)
|
||||||
|
|
||||||
// Fetch server-side data here
|
// Fetch server-side data here
|
||||||
export const fetchFor = [
|
export const fetchFor = [
|
||||||
|
...fetchForOnSiteInfo,
|
||||||
// ...fetchForBrunch,
|
// ...fetchForBrunch,
|
||||||
// ...fetchForRetex,
|
// ...fetchForRetex,
|
||||||
...fetchForDiscord,
|
...fetchForDiscord,
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
@include page-content-wrapper;
|
@include page-content-wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.notifIntro {
|
.notifIntro {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
@ -28,6 +33,15 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contactList {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.contactItem {
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.formLine {
|
.formLine {
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
|
|
||||||
|
@ -22,10 +22,13 @@ import {
|
|||||||
VolunteerDetailedKnowledge,
|
VolunteerDetailedKnowledge,
|
||||||
VolunteerPersonalInfo,
|
VolunteerPersonalInfo,
|
||||||
VolunteerLoan,
|
VolunteerLoan,
|
||||||
|
Contact,
|
||||||
} from "../../services/volunteers"
|
} from "../../services/volunteers"
|
||||||
|
import { Team, TeamWithoutId, translationTeam } from "../../services/teams"
|
||||||
import { canonicalEmail, canonicalMobile, trim, validMobile } from "../../utils/standardization"
|
import { canonicalEmail, canonicalMobile, trim, validMobile } from "../../utils/standardization"
|
||||||
import { getJwt } from "../secure"
|
import { getJwt } from "../secure"
|
||||||
import { getUniqueNickname } from "./tools"
|
import { getUniqueNickname } from "./tools"
|
||||||
|
import { getSheet } from "./accessors"
|
||||||
|
|
||||||
const expressAccessor = new ExpressAccessors<VolunteerWithoutId, Volunteer>(
|
const expressAccessor = new ExpressAccessors<VolunteerWithoutId, Volunteer>(
|
||||||
"Volunteers",
|
"Volunteers",
|
||||||
@ -174,7 +177,9 @@ export const volunteerLogin = expressAccessor.get<VolunteerLogin>(async (list, b
|
|||||||
map(toTry, async ([p, save]) => bcrypt.compare(p, save.replace(/^\$2y/, "$2a")))
|
map(toTry, async ([p, save]) => bcrypt.compare(p, save.replace(/^\$2y/, "$2a")))
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!some(tries)) {
|
const noSuccessfulLogin = !some(tries)
|
||||||
|
const isDevException = __DEV__ && [1, 508].includes(volunteer.id) // Amélie and Tom E
|
||||||
|
if (noSuccessfulLogin && !isDevException) {
|
||||||
throw Error("Mauvais mot de passe pour cet email")
|
throw Error("Mauvais mot de passe pour cet email")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,3 +640,81 @@ export const volunteerLoanSet = expressAccessor.set(async (list, body, id) => {
|
|||||||
} as VolunteerLoan,
|
} as VolunteerLoan,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const volunteerOnSiteInfo = expressAccessor.get(async (list, body, id) => {
|
||||||
|
const requestedId = +body[0] || id
|
||||||
|
if (requestedId !== id && requestedId !== 0) {
|
||||||
|
throw Error(`On ne peut acceder qu'à ses propres infos sur site`)
|
||||||
|
}
|
||||||
|
const volunteer = list.find((v) => v.id === requestedId)
|
||||||
|
if (!volunteer) {
|
||||||
|
throw Error(`Il n'y a aucun bénévole avec cet identifiant ${requestedId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const teamSheet = await getSheet<TeamWithoutId, Team>("Teams", new Team(), translationTeam)
|
||||||
|
const teamList = await teamSheet.getList()
|
||||||
|
if (!teamList) {
|
||||||
|
throw Error("Unable to load teams")
|
||||||
|
}
|
||||||
|
const team = teamList.find((v) => v.id === volunteer.team)
|
||||||
|
const referentVolunteers: Volunteer[] = []
|
||||||
|
const memberVolunteers: Volunteer[] = []
|
||||||
|
const CAVolunteers: Volunteer[] = []
|
||||||
|
let isReferent = false
|
||||||
|
if (team) {
|
||||||
|
const referentFirstnames = team.referentFirstnames.split(/\s*(,|ou|et)\s*/)
|
||||||
|
referentFirstnames.forEach((firstname) => {
|
||||||
|
const referent = list.find(
|
||||||
|
(v) =>
|
||||||
|
v.team === volunteer.team &&
|
||||||
|
v.firstname === firstname &&
|
||||||
|
v.roles.includes("référent")
|
||||||
|
)
|
||||||
|
if (referent) {
|
||||||
|
referentVolunteers.push(referent)
|
||||||
|
isReferent ||= referent.id === requestedId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
memberVolunteers.push(
|
||||||
|
...list.filter(
|
||||||
|
(v) =>
|
||||||
|
v.team === volunteer.team &&
|
||||||
|
!v.roles.includes("référent") &&
|
||||||
|
v.id !== requestedId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const pilotFirstnames = team.CAPilots.split(/,\s+/)
|
||||||
|
pilotFirstnames.forEach((name) => {
|
||||||
|
addContactFromName(CAVolunteers, list, name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const referents: Contact[] = volunteersToContacts(referentVolunteers)
|
||||||
|
|
||||||
|
const showMembers = isReferent || memberVolunteers.length <= 10
|
||||||
|
const members: Contact[] = showMembers ? volunteersToContacts(memberVolunteers) : []
|
||||||
|
|
||||||
|
const CAPilots: Contact[] = volunteersToContacts(CAVolunteers)
|
||||||
|
|
||||||
|
return { ...pick(volunteer, "id", "team"), referents, isReferent, CAPilots, members }
|
||||||
|
})
|
||||||
|
|
||||||
|
function volunteersToContacts(volunteers: Volunteer[]): Contact[] {
|
||||||
|
return volunteers.map((v) => volunteerToContact(v, volunteers))
|
||||||
|
}
|
||||||
|
|
||||||
|
function addContactFromName(dest: Volunteer[], list: Volunteer[], name: string): void {
|
||||||
|
const firstname = name.split(/\s+/)[0]
|
||||||
|
const lastname = name.split(/\s+/)[1]
|
||||||
|
const volunteer = list.find((v) => v.firstname === firstname && v.lastname === lastname)
|
||||||
|
if (volunteer) {
|
||||||
|
dest.push(volunteer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function volunteerToContact(volunteer: Volunteer, list?: Volunteer[]): Contact {
|
||||||
|
const firstname = list ? getUniqueNickname(list, volunteer) : volunteer.firstname
|
||||||
|
return { ...pick(volunteer, "mobile"), firstname }
|
||||||
|
}
|
||||||
|
@ -46,6 +46,7 @@ import {
|
|||||||
volunteerAddNew,
|
volunteerAddNew,
|
||||||
volunteerDetailedKnowledgeList,
|
volunteerDetailedKnowledgeList,
|
||||||
volunteerLoanSet,
|
volunteerLoanSet,
|
||||||
|
volunteerOnSiteInfo,
|
||||||
} from "./gsheets/volunteers"
|
} from "./gsheets/volunteers"
|
||||||
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
@ -150,6 +151,7 @@ app.post("/VolunteerMealsSet", secure as RequestHandler, volunteerMealsSet)
|
|||||||
app.post("/VolunteerPersonalInfoSet", secure as RequestHandler, volunteerPersonalInfoSet)
|
app.post("/VolunteerPersonalInfoSet", secure as RequestHandler, volunteerPersonalInfoSet)
|
||||||
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
|
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
|
||||||
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
||||||
|
app.get("/VolunteerOnSiteInfo", secure as RequestHandler, volunteerOnSiteInfo)
|
||||||
|
|
||||||
// Admin only
|
// Admin only
|
||||||
app.post("/VolunteerAddNew", secure as RequestHandler, volunteerAddNew)
|
app.post("/VolunteerAddNew", secure as RequestHandler, volunteerAddNew)
|
||||||
|
@ -18,6 +18,10 @@ export class Team {
|
|||||||
status = ""
|
status = ""
|
||||||
|
|
||||||
order = 0
|
order = 0
|
||||||
|
|
||||||
|
referentFirstnames = ""
|
||||||
|
|
||||||
|
CAPilots = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
export const translationTeam: { [k in keyof Team]: string } = {
|
export const translationTeam: { [k in keyof Team]: string } = {
|
||||||
@ -31,6 +35,8 @@ export const translationTeam: { [k in keyof Team]: string } = {
|
|||||||
after: "après",
|
after: "après",
|
||||||
status: "statut",
|
status: "statut",
|
||||||
order: "ordre",
|
order: "ordre",
|
||||||
|
referentFirstnames: "prénomsRéférents",
|
||||||
|
CAPilots: "pilotesAuCA",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const elementName = "Team"
|
export const elementName = "Team"
|
||||||
|
@ -173,8 +173,8 @@ export const volunteerExample: Volunteer = {
|
|||||||
id: 1,
|
id: 1,
|
||||||
firstname: "Aupeix",
|
firstname: "Aupeix",
|
||||||
lastname: "Amélie",
|
lastname: "Amélie",
|
||||||
email: "pakouille.lakouille@yahoo.fr",
|
email: "bidonmail@yahoo.fr",
|
||||||
mobile: "0675650392",
|
mobile: "0606060606",
|
||||||
photo: "images/volunteers/$taille/amélie_aupeix.jpg",
|
photo: "images/volunteers/$taille/amélie_aupeix.jpg",
|
||||||
adult: 1,
|
adult: 1,
|
||||||
roles: [],
|
roles: [],
|
||||||
@ -183,8 +183,8 @@ export const volunteerExample: Volunteer = {
|
|||||||
dayWishes: [],
|
dayWishes: [],
|
||||||
dayWishesComment: "",
|
dayWishesComment: "",
|
||||||
tshirtCount: 1,
|
tshirtCount: 1,
|
||||||
tshirtSize: "Femme M",
|
tshirtSize: "Femme S",
|
||||||
food: "Végétarien",
|
food: "Crudivore",
|
||||||
team: 2,
|
team: 2,
|
||||||
teamWishes: [],
|
teamWishes: [],
|
||||||
teamWishesComment: "",
|
teamWishesComment: "",
|
||||||
@ -335,3 +335,16 @@ export interface VolunteerLoan {
|
|||||||
giftable: Volunteer["giftable"]
|
giftable: Volunteer["giftable"]
|
||||||
noOpinion: Volunteer["noOpinion"]
|
noOpinion: Volunteer["noOpinion"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Contact = { firstname: string; mobile: string }
|
||||||
|
export type VolunteerOnSiteInfoWithoutId = Omit<VolunteerOnSiteInfo, "id">
|
||||||
|
export interface VolunteerOnSiteInfo {
|
||||||
|
id: Volunteer["id"]
|
||||||
|
team: Volunteer["team"]
|
||||||
|
isReferent: boolean
|
||||||
|
referentFirstnames: string
|
||||||
|
referents: Contact[]
|
||||||
|
CAPilots: Contact[]
|
||||||
|
members: Contact[]
|
||||||
|
orga: Contact[]
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
VolunteerMeals,
|
VolunteerMeals,
|
||||||
VolunteerPersonalInfo,
|
VolunteerPersonalInfo,
|
||||||
VolunteerLoan,
|
VolunteerLoan,
|
||||||
|
VolunteerOnSiteInfo,
|
||||||
} from "./volunteers"
|
} from "./volunteers"
|
||||||
|
|
||||||
const serviceAccessors = new ServiceAccessors<VolunteerWithoutId, Volunteer>(elementName)
|
const serviceAccessors = new ServiceAccessors<VolunteerWithoutId, Volunteer>(elementName)
|
||||||
@ -68,3 +69,8 @@ export const volunteerDetailedKnowledgeList = serviceAccessors.securedCustomPost
|
|||||||
|
|
||||||
export const volunteerLoanSet =
|
export const volunteerLoanSet =
|
||||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerLoan>]>("LoanSet")
|
serviceAccessors.securedCustomPost<[number, Partial<VolunteerLoan>]>("LoanSet")
|
||||||
|
|
||||||
|
export const volunteerOnSiteInfoGet = serviceAccessors.securedCustomGet<
|
||||||
|
[number],
|
||||||
|
VolunteerOnSiteInfo
|
||||||
|
>("OnSiteInfo")
|
||||||
|
@ -33,6 +33,7 @@ import volunteerTeamAssignSet from "./volunteerTeamAssignSet"
|
|||||||
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
|
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
|
||||||
import wishAdd from "./wishAdd"
|
import wishAdd from "./wishAdd"
|
||||||
import wishList from "./wishList"
|
import wishList from "./wishList"
|
||||||
|
import volunteerOnSiteInfo from "./volunteerOnSiteInfo"
|
||||||
|
|
||||||
// Use inferred return type for making correctly Redux types
|
// Use inferred return type for making correctly Redux types
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
@ -61,6 +62,7 @@ export default (history: History) => ({
|
|||||||
volunteerLoanSet,
|
volunteerLoanSet,
|
||||||
volunteerLogin,
|
volunteerLogin,
|
||||||
volunteerKnowledgeSet,
|
volunteerKnowledgeSet,
|
||||||
|
volunteerOnSiteInfo,
|
||||||
volunteerDetailedKnowledgeList,
|
volunteerDetailedKnowledgeList,
|
||||||
volunteerParticipationDetailsSet,
|
volunteerParticipationDetailsSet,
|
||||||
volunteerPersonalInfoSet,
|
volunteerPersonalInfoSet,
|
||||||
|
65
src/store/volunteerOnSiteInfo.ts
Normal file
65
src/store/volunteerOnSiteInfo.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit"
|
||||||
|
|
||||||
|
import { StateRequest, toastError, elementFetch } from "./utils"
|
||||||
|
import { VolunteerOnSiteInfo } from "../services/volunteers"
|
||||||
|
import { AppThunk, AppState } from "."
|
||||||
|
import { volunteerOnSiteInfoGet } from "../services/volunteersAccessors"
|
||||||
|
|
||||||
|
type StateVolunteerOnSiteInfo = { entity?: VolunteerOnSiteInfo } & StateRequest
|
||||||
|
|
||||||
|
export const initialState: StateVolunteerOnSiteInfo = {
|
||||||
|
readyStatus: "idle",
|
||||||
|
}
|
||||||
|
|
||||||
|
const volunteerOnSiteInfo = createSlice({
|
||||||
|
name: "volunteerOnSiteInfo",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
getRequesting: (_) => ({
|
||||||
|
readyStatus: "request",
|
||||||
|
}),
|
||||||
|
getSuccess: (_, { payload }: PayloadAction<VolunteerOnSiteInfo>) => ({
|
||||||
|
readyStatus: "success",
|
||||||
|
entity: payload,
|
||||||
|
}),
|
||||||
|
getFailure: (_, { payload }: PayloadAction<string>) => ({
|
||||||
|
readyStatus: "failure",
|
||||||
|
error: payload,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default volunteerOnSiteInfo.reducer
|
||||||
|
export const { getRequesting, getSuccess, getFailure } = volunteerOnSiteInfo.actions
|
||||||
|
|
||||||
|
export const fetchVolunteerOnSiteInfo = elementFetch(
|
||||||
|
volunteerOnSiteInfoGet,
|
||||||
|
getRequesting,
|
||||||
|
getSuccess,
|
||||||
|
getFailure,
|
||||||
|
(error: Error) =>
|
||||||
|
toastError(`Erreur lors du chargement des infos sur site d'un bénévole: ${error.message}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
const shouldFetchVolunteerOnSiteInfo = (state: AppState, id: number) =>
|
||||||
|
state.volunteerOnSiteInfo.readyStatus !== "success" ||
|
||||||
|
(state.volunteerOnSiteInfo.entity && state.volunteerOnSiteInfo.entity.id !== id)
|
||||||
|
|
||||||
|
export const fetchVolunteerOnSiteInfoIfNeed =
|
||||||
|
(id = 0): AppThunk =>
|
||||||
|
(dispatch, getState) => {
|
||||||
|
let jwt = ""
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
;({ jwt, id } = getState().auth)
|
||||||
|
}
|
||||||
|
if (shouldFetchVolunteerOnSiteInfo(getState(), id))
|
||||||
|
return dispatch(fetchVolunteerOnSiteInfo(jwt, id))
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const selectVolunteerOnSiteInfo = createSelector(
|
||||||
|
(state: AppState) => state,
|
||||||
|
(state): VolunteerOnSiteInfo | undefined => state.volunteerOnSiteInfo?.entity
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user