mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-09 17:14:21 +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 { selectVolunteerList } from "../../store/volunteerList"
|
||||||
import { selectTeamList } from "../../store/teamList"
|
import { selectTeamList } from "../../store/teamList"
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
|
import { useTeamAssign } from "./teamAssign.utils"
|
||||||
|
|
||||||
const selectTeamsWithVolunteersCandidates = createSelector(
|
const selectTeamsWithVolunteersCandidates = createSelector(
|
||||||
selectVolunteerList,
|
selectVolunteerList,
|
||||||
@ -37,7 +38,13 @@ type PropsDaysDisplay = {
|
|||||||
|
|
||||||
const DaysDisplay: FC<PropsDaysDisplay> = ({ dayWishes }): JSX.Element => (
|
const DaysDisplay: FC<PropsDaysDisplay> = ({ dayWishes }): JSX.Element => (
|
||||||
<span className={styles.daysDisplay}>
|
<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>
|
</span>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,10 +55,14 @@ type Props = {
|
|||||||
const TeamWithCandidates: FC<Props> = ({ teamId }): JSX.Element | null => {
|
const TeamWithCandidates: FC<Props> = ({ teamId }): JSX.Element | null => {
|
||||||
const teams = useSelector(selectTeamsWithVolunteersCandidates)
|
const teams = useSelector(selectTeamsWithVolunteersCandidates)
|
||||||
const team = teams.find((t) => t.id === teamId)
|
const team = teams.find((t) => t.id === teamId)
|
||||||
|
const [, saveTeam] = useTeamAssign()
|
||||||
|
|
||||||
const onTeamSelected = useCallback((volunteerId, selectedTeamId) => {
|
const onTeamSelected = useCallback(
|
||||||
console.log("select ", volunteerId, selectedTeamId)
|
(volunteerId, selectedTeamId) => {
|
||||||
}, [])
|
saveTeam(volunteerId, selectedTeamId)
|
||||||
|
},
|
||||||
|
[saveTeam]
|
||||||
|
)
|
||||||
|
|
||||||
if (!team) return null
|
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,
|
translationVolunteer,
|
||||||
VolunteerDayWishes,
|
VolunteerDayWishes,
|
||||||
VolunteerParticipationDetails,
|
VolunteerParticipationDetails,
|
||||||
|
VolunteerTeamAssign,
|
||||||
} from "../../services/volunteers"
|
} from "../../services/volunteers"
|
||||||
import { canonicalEmail } from "../../utils/standardization"
|
import { canonicalEmail } from "../../utils/standardization"
|
||||||
import { getJwt } from "../secure"
|
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 {
|
function getByEmail<T extends { email: string }>(list: T[], rawEmail: string): T | undefined {
|
||||||
const email = canonicalEmail(rawEmail || "")
|
const email = canonicalEmail(rawEmail || "")
|
||||||
const volunteer = list.find((v) => canonicalEmail(v.email) === email)
|
return list.find((v) => canonicalEmail(v.email) === email)
|
||||||
return volunteer
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import {
|
|||||||
volunteerParticipationDetailsSet,
|
volunteerParticipationDetailsSet,
|
||||||
volunteerTeamWishesSet,
|
volunteerTeamWishesSet,
|
||||||
volunteerDayWishesSet,
|
volunteerDayWishesSet,
|
||||||
|
volunteerTeamAssignSet,
|
||||||
volunteerListGet,
|
volunteerListGet,
|
||||||
} from "./gsheets/volunteers"
|
} from "./gsheets/volunteers"
|
||||||
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
||||||
@ -102,6 +103,7 @@ app.post(
|
|||||||
)
|
)
|
||||||
app.post("/VolunteerDayWishesSet", secure as RequestHandler, volunteerDayWishesSet)
|
app.post("/VolunteerDayWishesSet", secure as RequestHandler, volunteerDayWishesSet)
|
||||||
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
|
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
|
||||||
|
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
||||||
|
|
||||||
// Push notification subscription
|
// Push notification subscription
|
||||||
app.post("/notifications/subscribe", notificationsSubscribe)
|
app.post("/notifications/subscribe", notificationsSubscribe)
|
||||||
|
@ -29,6 +29,8 @@ export class Volunteer {
|
|||||||
|
|
||||||
food = ""
|
food = ""
|
||||||
|
|
||||||
|
team = 0
|
||||||
|
|
||||||
teamWishes: number[] = []
|
teamWishes: number[] = []
|
||||||
|
|
||||||
teamWishesComment = ""
|
teamWishesComment = ""
|
||||||
@ -62,6 +64,7 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
|
|||||||
tshirtCount: "nbDeTshirts",
|
tshirtCount: "nbDeTshirts",
|
||||||
tshirtSize: "tailleDeTshirts",
|
tshirtSize: "tailleDeTshirts",
|
||||||
food: "alimentation",
|
food: "alimentation",
|
||||||
|
team: "équipe",
|
||||||
teamWishes: "enviesEquipe",
|
teamWishes: "enviesEquipe",
|
||||||
teamWishesComment: "commentaireEnviesEquipe",
|
teamWishesComment: "commentaireEnviesEquipe",
|
||||||
hiddenAsks: "questionsCachees",
|
hiddenAsks: "questionsCachees",
|
||||||
@ -90,6 +93,7 @@ export const volunteerExample: Volunteer = {
|
|||||||
tshirtCount: "1",
|
tshirtCount: "1",
|
||||||
tshirtSize: "Femme M",
|
tshirtSize: "Femme M",
|
||||||
food: "Végétarien",
|
food: "Végétarien",
|
||||||
|
team: 2,
|
||||||
teamWishes: [],
|
teamWishes: [],
|
||||||
teamWishesComment: "",
|
teamWishesComment: "",
|
||||||
hiddenAsks: [],
|
hiddenAsks: [],
|
||||||
@ -146,3 +150,9 @@ export interface VolunteerParticipationDetails {
|
|||||||
adult: Volunteer["adult"]
|
adult: Volunteer["adult"]
|
||||||
food: Volunteer["food"]
|
food: Volunteer["food"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VolunteerTeamAssign {
|
||||||
|
id: Volunteer["id"]
|
||||||
|
volunteer: number
|
||||||
|
team: Volunteer["team"]
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
VolunteerAsks,
|
VolunteerAsks,
|
||||||
VolunteerParticipationDetails,
|
VolunteerParticipationDetails,
|
||||||
VolunteerTeamWishes,
|
VolunteerTeamWishes,
|
||||||
|
VolunteerTeamAssign,
|
||||||
VolunteerWithoutId,
|
VolunteerWithoutId,
|
||||||
} from "./volunteers"
|
} from "./volunteers"
|
||||||
|
|
||||||
@ -34,3 +35,6 @@ export const volunteerParticipationDetailsSet =
|
|||||||
serviceAccessors.securedCustomPost<[number, Partial<VolunteerParticipationDetails>]>(
|
serviceAccessors.securedCustomPost<[number, Partial<VolunteerParticipationDetails>]>(
|
||||||
"ParticipationDetailsSet"
|
"ParticipationDetailsSet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const volunteerTeamAssignSet =
|
||||||
|
serviceAccessors.securedCustomPost<[number, Partial<VolunteerTeamAssign>]>("TeamAssignSet")
|
||||||
|
@ -18,6 +18,7 @@ import volunteerAsksSet from "./volunteerAsksSet"
|
|||||||
import volunteerParticipationDetailsSet from "./volunteerParticipationDetailsSet"
|
import volunteerParticipationDetailsSet from "./volunteerParticipationDetailsSet"
|
||||||
import volunteerDayWishesSet from "./volunteerDayWishesSet"
|
import volunteerDayWishesSet from "./volunteerDayWishesSet"
|
||||||
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
|
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
|
||||||
|
import volunteerTeamAssignSet from "./volunteerTeamAssignSet"
|
||||||
import wishAdd from "./wishAdd"
|
import wishAdd from "./wishAdd"
|
||||||
import wishList from "./wishList"
|
import wishList from "./wishList"
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ export default (history: History) => ({
|
|||||||
volunteerParticipationDetailsSet,
|
volunteerParticipationDetailsSet,
|
||||||
volunteerDayWishesSet,
|
volunteerDayWishesSet,
|
||||||
volunteerTeamWishesSet,
|
volunteerTeamWishesSet,
|
||||||
|
volunteerTeamAssignSet,
|
||||||
wishAdd,
|
wishAdd,
|
||||||
wishList,
|
wishList,
|
||||||
router: connectRouter(history) as any,
|
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