mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-08 08:34:20 +02:00
assigners can assign volunteer to a team
This commit is contained in:
parent
f0f08a91ed
commit
7c96636477
@ -5,6 +5,7 @@ import classnames from "classnames"
|
||||
import { selectVolunteerList } from "../../store/volunteerList"
|
||||
import { selectTeamList } from "../../store/teamList"
|
||||
import styles from "./styles.module.scss"
|
||||
import { useTeamAssign } from "./teamAssign.utils"
|
||||
|
||||
const selectTeamsWithVolunteersCandidates = createSelector(
|
||||
selectVolunteerList,
|
||||
@ -37,7 +38,13 @@ type PropsDaysDisplay = {
|
||||
|
||||
const DaysDisplay: FC<PropsDaysDisplay> = ({ dayWishes }): JSX.Element => (
|
||||
<span className={styles.daysDisplay}>
|
||||
{dayWishes.map((day) => (day === "S" || day === "D" ? <strong>{day}</strong> : day))}
|
||||
{dayWishes.map((day) =>
|
||||
day === "S" || day === "D" ? (
|
||||
<strong key={day}>{day}</strong>
|
||||
) : (
|
||||
<span key={day}>{day}</span>
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
|
||||
@ -48,10 +55,14 @@ type Props = {
|
||||
const TeamWithCandidates: FC<Props> = ({ teamId }): JSX.Element | null => {
|
||||
const teams = useSelector(selectTeamsWithVolunteersCandidates)
|
||||
const team = teams.find((t) => t.id === teamId)
|
||||
const [, saveTeam] = useTeamAssign()
|
||||
|
||||
const onTeamSelected = useCallback((volunteerId, selectedTeamId) => {
|
||||
console.log("select ", volunteerId, selectedTeamId)
|
||||
}, [])
|
||||
const onTeamSelected = useCallback(
|
||||
(volunteerId, selectedTeamId) => {
|
||||
saveTeam(volunteerId, selectedTeamId)
|
||||
},
|
||||
[saveTeam]
|
||||
)
|
||||
|
||||
if (!team) return null
|
||||
|
||||
|
27
src/components/TeamAssignment/teamAssign.utils.ts
Normal file
27
src/components/TeamAssignment/teamAssign.utils.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { shallowEqual, useSelector } from "react-redux"
|
||||
import { useCallback } from "react"
|
||||
import { selectUserJwtToken } from "../../store/auth"
|
||||
import { AppState } from "../../store"
|
||||
import useAction from "../../utils/useAction"
|
||||
import { fetchVolunteerTeamAssignSet } from "../../store/volunteerTeamAssignSet"
|
||||
|
||||
export const useTeamAssign = (): [any, any] => {
|
||||
const save = useAction(fetchVolunteerTeamAssignSet)
|
||||
const jwtToken = useSelector(selectUserJwtToken)
|
||||
const teamSet = useSelector(
|
||||
(state: AppState) => state.volunteerTeamAssignSet?.entity,
|
||||
shallowEqual
|
||||
)
|
||||
|
||||
const saveWishes = useCallback(
|
||||
(volunteerId, teamId) => {
|
||||
save(jwtToken, 0, {
|
||||
volunteer: volunteerId,
|
||||
team: teamId,
|
||||
})
|
||||
},
|
||||
[save, jwtToken]
|
||||
)
|
||||
|
||||
return [teamSet, saveWishes]
|
||||
}
|
@ -12,6 +12,7 @@ import {
|
||||
translationVolunteer,
|
||||
VolunteerDayWishes,
|
||||
VolunteerParticipationDetails,
|
||||
VolunteerTeamAssign,
|
||||
} from "../../services/volunteers"
|
||||
import { canonicalEmail } from "../../utils/standardization"
|
||||
import { getJwt } from "../secure"
|
||||
@ -246,8 +247,31 @@ export const volunteerParticipationDetailsSet = expressAccessor.set(async (list,
|
||||
}
|
||||
})
|
||||
|
||||
export const volunteerTeamAssignSet = expressAccessor.set(async (list, body, id) => {
|
||||
const requestedId = +body[0] || id
|
||||
const assigner = list.find((v) => v.id === requestedId)
|
||||
if (!assigner || !assigner.roles.includes("répartiteur")) {
|
||||
throw Error(`Vous n'avez pas les droits pas assigner les équipes.`)
|
||||
}
|
||||
|
||||
const teamAssign = body[1] as VolunteerTeamAssign
|
||||
const volunteer = list.find((v) => v.id === teamAssign.volunteer)
|
||||
if (!volunteer) {
|
||||
throw Error(`Il n'y a aucun bénévole avec cet identifiant ${teamAssign.volunteer}`)
|
||||
}
|
||||
const newVolunteer = _.cloneDeep(volunteer)
|
||||
newVolunteer.team = teamAssign.team
|
||||
|
||||
return {
|
||||
toDatabase: newVolunteer,
|
||||
toCaller: {
|
||||
id: newVolunteer.id,
|
||||
team: newVolunteer.team,
|
||||
} as VolunteerTeamAssign,
|
||||
}
|
||||
})
|
||||
|
||||
function getByEmail<T extends { email: string }>(list: T[], rawEmail: string): T | undefined {
|
||||
const email = canonicalEmail(rawEmail || "")
|
||||
const volunteer = list.find((v) => canonicalEmail(v.email) === email)
|
||||
return volunteer
|
||||
return list.find((v) => canonicalEmail(v.email) === email)
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import {
|
||||
volunteerParticipationDetailsSet,
|
||||
volunteerTeamWishesSet,
|
||||
volunteerDayWishesSet,
|
||||
volunteerTeamAssignSet,
|
||||
volunteerListGet,
|
||||
} from "./gsheets/volunteers"
|
||||
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
||||
@ -102,6 +103,7 @@ app.post(
|
||||
)
|
||||
app.post("/VolunteerDayWishesSet", secure as RequestHandler, volunteerDayWishesSet)
|
||||
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
|
||||
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
||||
|
||||
// Push notification subscription
|
||||
app.post("/notifications/subscribe", notificationsSubscribe)
|
||||
|
@ -29,6 +29,8 @@ export class Volunteer {
|
||||
|
||||
food = ""
|
||||
|
||||
team = 0
|
||||
|
||||
teamWishes: number[] = []
|
||||
|
||||
teamWishesComment = ""
|
||||
@ -62,6 +64,7 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
|
||||
tshirtCount: "nbDeTshirts",
|
||||
tshirtSize: "tailleDeTshirts",
|
||||
food: "alimentation",
|
||||
team: "équipe",
|
||||
teamWishes: "enviesEquipe",
|
||||
teamWishesComment: "commentaireEnviesEquipe",
|
||||
hiddenAsks: "questionsCachees",
|
||||
@ -90,6 +93,7 @@ export const volunteerExample: Volunteer = {
|
||||
tshirtCount: "1",
|
||||
tshirtSize: "Femme M",
|
||||
food: "Végétarien",
|
||||
team: 2,
|
||||
teamWishes: [],
|
||||
teamWishesComment: "",
|
||||
hiddenAsks: [],
|
||||
@ -146,3 +150,9 @@ export interface VolunteerParticipationDetails {
|
||||
adult: Volunteer["adult"]
|
||||
food: Volunteer["food"]
|
||||
}
|
||||
|
||||
export interface VolunteerTeamAssign {
|
||||
id: Volunteer["id"]
|
||||
volunteer: number
|
||||
team: Volunteer["team"]
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
VolunteerAsks,
|
||||
VolunteerParticipationDetails,
|
||||
VolunteerTeamWishes,
|
||||
VolunteerTeamAssign,
|
||||
VolunteerWithoutId,
|
||||
} from "./volunteers"
|
||||
|
||||
@ -34,3 +35,6 @@ export const volunteerParticipationDetailsSet =
|
||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerParticipationDetails>]>(
|
||||
"ParticipationDetailsSet"
|
||||
)
|
||||
|
||||
export const volunteerTeamAssignSet =
|
||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerTeamAssign>]>("TeamAssignSet")
|
||||
|
@ -18,6 +18,7 @@ import volunteerAsksSet from "./volunteerAsksSet"
|
||||
import volunteerParticipationDetailsSet from "./volunteerParticipationDetailsSet"
|
||||
import volunteerDayWishesSet from "./volunteerDayWishesSet"
|
||||
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
|
||||
import volunteerTeamAssignSet from "./volunteerTeamAssignSet"
|
||||
import wishAdd from "./wishAdd"
|
||||
import wishList from "./wishList"
|
||||
|
||||
@ -41,6 +42,7 @@ export default (history: History) => ({
|
||||
volunteerParticipationDetailsSet,
|
||||
volunteerDayWishesSet,
|
||||
volunteerTeamWishesSet,
|
||||
volunteerTeamAssignSet,
|
||||
wishAdd,
|
||||
wishList,
|
||||
router: connectRouter(history) as any,
|
||||
|
59
src/store/volunteerTeamAssignSet.ts
Normal file
59
src/store/volunteerTeamAssignSet.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
||||
|
||||
import { StateRequest, toastError, elementFetch } from "./utils"
|
||||
import { VolunteerTeamAssign } from "../services/volunteers"
|
||||
import { AppThunk, AppState } from "."
|
||||
import { volunteerTeamAssignSet } from "../services/volunteersAccessors"
|
||||
|
||||
type StateVolunteerTeamAssignSet = { entity?: VolunteerTeamAssign } & StateRequest
|
||||
|
||||
export const initialState: StateVolunteerTeamAssignSet = {
|
||||
readyStatus: "idle",
|
||||
}
|
||||
|
||||
const volunteerTeamAssignSetSlice = createSlice({
|
||||
name: "volunteerTeamAssignSet",
|
||||
initialState,
|
||||
reducers: {
|
||||
getRequesting: (_) => ({
|
||||
readyStatus: "request",
|
||||
}),
|
||||
getSuccess: (_, { payload }: PayloadAction<VolunteerTeamAssign>) => ({
|
||||
readyStatus: "success",
|
||||
entity: payload,
|
||||
}),
|
||||
getFailure: (_, { payload }: PayloadAction<string>) => ({
|
||||
readyStatus: "failure",
|
||||
error: payload,
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
export default volunteerTeamAssignSetSlice.reducer
|
||||
export const { getRequesting, getSuccess, getFailure } = volunteerTeamAssignSetSlice.actions
|
||||
|
||||
export const fetchVolunteerTeamAssignSet = elementFetch(
|
||||
volunteerTeamAssignSet,
|
||||
getRequesting,
|
||||
getSuccess,
|
||||
getFailure,
|
||||
(error: Error) => toastError(`Erreur lors du chargement des notifications: ${error.message}`)
|
||||
)
|
||||
|
||||
const shouldFetchVolunteerTeamAssignSet = (state: AppState, id: number) =>
|
||||
state.volunteerTeamAssignSet?.readyStatus !== "success" ||
|
||||
(state.volunteerTeamAssignSet?.entity && state.volunteerTeamAssignSet?.entity?.id !== id)
|
||||
|
||||
export const fetchVolunteerTeamAssignSetIfNeed =
|
||||
(id = 0, wishes: Partial<VolunteerTeamAssign> = {}): AppThunk =>
|
||||
(dispatch, getState) => {
|
||||
let jwt = ""
|
||||
|
||||
if (!id) {
|
||||
;({ jwt, id } = getState().auth)
|
||||
}
|
||||
if (shouldFetchVolunteerTeamAssignSet(getState(), id))
|
||||
return dispatch(fetchVolunteerTeamAssignSet(jwt, id, wishes))
|
||||
|
||||
return null
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user