Add volunteerTeamWishesSet in store

This commit is contained in:
pikiou 2022-01-21 01:34:32 +01:00
parent d5eeb44d2f
commit fc65a2d42b
9 changed files with 232 additions and 1 deletions

View File

@ -0,0 +1,93 @@
import { FC, memo, useCallback, useEffect, useState } from "react"
import { RouteComponentProps } from "react-router-dom"
import { useSelector, shallowEqual, useDispatch } from "react-redux"
import { AppState, AppThunk } from "../../store"
import {
fetchVolunteerTeamWishesSet,
fetchVolunteerTeamWishesSetIfNeed,
} from "../../store/volunteerTeamWishesSet"
import { VolunteerTeamWishes } from "../../services/volunteers"
import { selectUserJwtToken } from "../../store/auth"
export type Props = RouteComponentProps
let prevWishes: VolunteerTeamWishes | undefined
const HomePage: FC<Props> = (): JSX.Element => {
const dispatch = useDispatch()
const jwtToken = useSelector(selectUserJwtToken)
const wishesForm = useSelector((state: AppState) => {
const wishes = state.volunteerTeamWishesSet?.entity
if (wishes) {
prevWishes = wishes
return wishes
}
return prevWishes
}, shallowEqual)
const [teamWishes, setTeamWishes] = useState(wishesForm?.teamWishes.join(",") || "")
const [teamWishComment, setTeamWishComment] = useState(wishesForm?.teamWishComment || "")
useEffect(() => {
setTeamWishes(wishesForm?.teamWishes.join(",") || "")
setTeamWishComment(wishesForm?.teamWishComment || "")
}, [wishesForm])
const onTeamWishesChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
setTeamWishes(e.target.value)
const onTeamWishCommentChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
setTeamWishComment(e.target.value)
const onSubmit = useCallback(
(event: React.SyntheticEvent): void => {
event.preventDefault()
if (!wishesForm) {
console.error("NO FORM WISHES RECEIVED")
return // Form should not even appear if this happens
}
dispatch(
fetchVolunteerTeamWishesSet(jwtToken, 0, {
id: wishesForm.id,
teamWishes: (teamWishes || "").split(","),
teamWishComment,
})
)
},
[dispatch, jwtToken, wishesForm, teamWishes, teamWishComment]
)
if (jwtToken === undefined) return <p>Loading...</p>
if (jwtToken) {
return (
<form>
<input
type="text"
id="teamWishes"
required
value={teamWishes}
onChange={onTeamWishesChanged}
/>
<br />
<input
type="text"
id="teamWishComment"
required
value={teamWishComment}
onChange={onTeamWishCommentChanged}
/>
<button type="button" onClick={onSubmit}>
Envoyer
</button>
</form>
)
}
return <div>Besoin d&apos;être identifié</div>
}
// Fetch server-side data here
export const loadData = (): AppThunk[] => [fetchVolunteerTeamWishesSetIfNeed()]
export default memo(HomePage)

16
src/pages/TeamWishes/index.tsx Executable file
View File

@ -0,0 +1,16 @@
import loadable from "@loadable/component"
import { Loading, ErrorBoundary } from "../../components"
import { Props, loadData } from "./TeamWishes"
const HomePage = loadable(() => import("./TeamWishes"), {
fallback: <Loading />,
})
export default (props: Props): JSX.Element => (
<ErrorBoundary>
<HomePage {...props} />
</ErrorBoundary>
)
export { loadData }

View File

@ -0,0 +1 @@
@import "../../theme/mixins";

View File

@ -4,6 +4,7 @@ import App from "../app"
import AsyncHome, { loadData as loadHomeData } from "../pages/Home"
import AsyncPreRegisterPage, { loadData as loadPreRegisterPage } from "../pages/PreRegister"
import AsyncTeams, { loadData as loadTeamsData } from "../pages/Teams"
import AsyncTeamWishes, { loadData as loadTeamWishesData } from "../pages/TeamWishes"
import AsyncWish, { loadData as loadWishData } from "../pages/Wish"
import AsyncVolunteerPage, { loadData as loadVolunteerPageData } from "../pages/VolunteerPage"
import Login from "../pages/Login"
@ -43,6 +44,11 @@ export default [
component: AsyncTeams,
loadData: loadTeamsData,
},
{
path: "/teamWishes",
component: AsyncTeamWishes,
loadData: loadTeamWishesData,
},
{
path: "/wish",
component: AsyncWish,

View File

@ -8,6 +8,7 @@ import {
VolunteerWithoutId,
VolunteerLogin,
VolunteerNotifs,
VolunteerTeamWishes,
translationVolunteer,
} from "../../services/volunteers"
import { canonicalEmail } from "../../utils/standardization"
@ -119,6 +120,38 @@ export const volunteerNotifsSet = expressAccessor.set(
}
)
export const volunteerTeamWishesSet = expressAccessor.set(
async (list: Volunteer[], body: RequestBody, id: number) => {
console.log("volunteerTeamWishesSet", body)
const requestedId = +body[0]
if (requestedId !== id && requestedId !== 0) {
throw Error(`On ne peut acceder qu'à ses propres notifs`)
}
const wishes = body[1] as VolunteerTeamWishes
const volunteer = list.find((v) => v.id === id)
if (!volunteer) {
throw Error(`Il n'y a aucun bénévole avec cet identifiant ${id}`)
}
const newVolunteer = _.cloneDeep(volunteer)
if (wishes.teamWishes !== undefined) {
newVolunteer.teamWishes = wishes.teamWishes
}
if (wishes.teamWishComment !== undefined) {
newVolunteer.teamWishComment = wishes.teamWishComment
}
return {
toDatabase: newVolunteer,
toCaller: {
id: newVolunteer.id,
teamWishes: newVolunteer.teamWishes,
teamWishComment: newVolunteer.teamWishComment,
} as VolunteerTeamWishes,
}
}
)
function getByEmail(list: Volunteer[], rawEmail: string): Volunteer | undefined {
const email = canonicalEmail(rawEmail || "")
const volunteer = list.find((v) => canonicalEmail(v.email) === email)

View File

@ -21,10 +21,11 @@ import { javGameListGet } from "./gsheets/javGames"
import { preVolunteerAdd, preVolunteerCountGet } from "./gsheets/preVolunteers"
import { teamListGet } from "./gsheets/teams"
import {
volunteerNotifsSet,
volunteerSet,
volunteerLogin,
volunteerForgot,
volunteerNotifsSet,
volunteerTeamWishesSet,
} from "./gsheets/volunteers"
import { wishListGet, wishAdd } from "./gsheets/wishes"
import config from "../config"
@ -75,6 +76,7 @@ app.post("/VolunteerSet", secure as RequestHandler, volunteerSet)
app.get("/TeamListGet", teamListGet)
// UNSAFE app.post("/VolunteerGet", secure as RequestHandler, volunteerGet)
app.post("/VolunteerNotifsSet", secure as RequestHandler, volunteerNotifsSet)
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)
// Push notification subscription
app.post("/notifications/subscribe", notificationsSubscribe)

View File

@ -21,6 +21,12 @@ export class Volunteer {
active = ""
participingDays = []
teamWishes: string[] = []
teamWishComment = ""
hiddenNotifs: number[] = []
created = new Date()
@ -45,6 +51,9 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
adult: "majeur",
privileges: "privilege",
active: "actif",
participingDays: "joursPrésent",
teamWishes: "enviesEquipe",
teamWishComment: "commentaireEnviesEquipe",
hiddenNotifs: "notifsCachees",
created: "creation",
password1: "passe1",
@ -66,6 +75,9 @@ export const volunteerExample: Volunteer = {
adult: 1,
privileges: 0,
active: "inconnu",
participingDays: [],
teamWishes: [],
teamWishComment: "",
hiddenNotifs: [],
created: new Date(0),
password1: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPkdq9d5fqpbl8ASimSjNj4SR.9O",
@ -110,3 +122,11 @@ export interface VolunteerNotifs {
}
export const volunteerNotifsSet =
serviceAccessors.securedCustomPost<[number, Partial<VolunteerNotifs>]>("NotifsSet")
export interface VolunteerTeamWishes {
id: number
teamWishes: string[]
teamWishComment: string
}
export const volunteerTeamWishesSet =
serviceAccessors.securedCustomPost<[number, Partial<VolunteerTeamWishes>]>("TeamWishesSet")

View File

@ -13,6 +13,7 @@ import volunteerSet from "./volunteerSet"
import volunteerLogin from "./volunteerLogin"
import volunteerForgot from "./volunteerForgot"
import volunteerNotifsSet from "./volunteerNotifsSet"
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
import wishAdd from "./wishAdd"
import wishList from "./wishList"
@ -31,6 +32,7 @@ export default (history: History) => ({
volunteerLogin,
volunteerForgot,
volunteerNotifsSet,
volunteerTeamWishesSet,
wishAdd,
wishList,
router: connectRouter(history) as any,

View File

@ -0,0 +1,58 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
import { StateRequest, toastError, elementFetch } from "./utils"
import { VolunteerTeamWishes, volunteerTeamWishesSet } from "../services/volunteers"
import { AppThunk, AppState } from "."
type StateVolunteerTeamWishesSet = { entity?: VolunteerTeamWishes } & StateRequest
export const initialState: StateVolunteerTeamWishesSet = {
readyStatus: "idle",
}
const volunteerTeamWishesSetSlice = createSlice({
name: "volunteerTeamWishesSet",
initialState,
reducers: {
getRequesting: (_) => ({
readyStatus: "request",
}),
getSuccess: (_, { payload }: PayloadAction<VolunteerTeamWishes>) => ({
readyStatus: "success",
entity: payload,
}),
getFailure: (_, { payload }: PayloadAction<string>) => ({
readyStatus: "failure",
error: payload,
}),
},
})
export default volunteerTeamWishesSetSlice.reducer
export const { getRequesting, getSuccess, getFailure } = volunteerTeamWishesSetSlice.actions
export const fetchVolunteerTeamWishesSet = elementFetch(
volunteerTeamWishesSet,
getRequesting,
getSuccess,
getFailure,
(error: Error) => toastError(`Erreur lors du chargement des notifications: ${error.message}`)
)
const shouldFetchVolunteerTeamWishesSet = (state: AppState, id: number) =>
state.volunteerTeamWishesSet?.readyStatus !== "success" ||
(state.volunteerTeamWishesSet?.entity && state.volunteerTeamWishesSet?.entity?.id !== id)
export const fetchVolunteerTeamWishesSetIfNeed =
(id = 0, wishes: Partial<VolunteerTeamWishes> = {}): AppThunk =>
(dispatch, getState) => {
let jwt = ""
if (!id) {
;({ id, jwt } = getState().auth)
}
if (shouldFetchVolunteerTeamWishesSet(getState(), id))
return dispatch(fetchVolunteerTeamWishesSet(jwt, id, wishes))
return null
}