mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-10 01:24:20 +02:00
Add db new line support
This commit is contained in:
parent
da643df6a6
commit
028d703e98
@ -1,3 +1,4 @@
|
|||||||
|
import { max } from "lodash"
|
||||||
import { FC, memo } from "react"
|
import { FC, memo } from "react"
|
||||||
import { useSelector } from "react-redux"
|
import { useSelector } from "react-redux"
|
||||||
import withUserConnected from "../../utils/withUserConnected"
|
import withUserConnected from "../../utils/withUserConnected"
|
||||||
@ -9,13 +10,18 @@ import useAction from "../../utils/useAction"
|
|||||||
import { fetchVolunteerSetIfNeed } from "../../store/volunteerSet"
|
import { fetchVolunteerSetIfNeed } from "../../store/volunteerSet"
|
||||||
import { Volunteer } from "../../services/volunteers"
|
import { Volunteer } from "../../services/volunteers"
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
|
import { fetchVolunteerAddNewIfNeed } from "../../store/volunteerAddNew"
|
||||||
|
|
||||||
const DbEdit: FC = (): JSX.Element => {
|
const DbEdit: FC = (): JSX.Element => {
|
||||||
const volunteers = useSelector(selectVolunteerList)
|
const volunteers = useSelector(selectVolunteerList)
|
||||||
const saveVolunteer = useAction(fetchVolunteerSetIfNeed)
|
const saveVolunteer = useAction(fetchVolunteerSetIfNeed)
|
||||||
|
const addVolunteer = useAction(fetchVolunteerAddNewIfNeed)
|
||||||
if (!volunteers) {
|
if (!volunteers) {
|
||||||
return <>No member found</>
|
return <>No member found</>
|
||||||
}
|
}
|
||||||
|
const nextId = (max(volunteers.map((v) => v.id)) || 0) + 1
|
||||||
|
const nextVolunteer = new Volunteer()
|
||||||
|
nextVolunteer.id = nextId
|
||||||
return (
|
return (
|
||||||
<ul className={styles.list}>
|
<ul className={styles.list}>
|
||||||
{volunteers.map((volunteer: Volunteer) => (
|
{volunteers.map((volunteer: Volunteer) => (
|
||||||
@ -25,6 +31,12 @@ const DbEdit: FC = (): JSX.Element => {
|
|||||||
volunteer={volunteer}
|
volunteer={volunteer}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
<MemberEdit
|
||||||
|
key={nextId}
|
||||||
|
addBefore={addVolunteer}
|
||||||
|
saveVolunteer={saveVolunteer}
|
||||||
|
volunteer={nextVolunteer}
|
||||||
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,16 +10,29 @@ import { toastError } from "../../store/utils"
|
|||||||
interface Props {
|
interface Props {
|
||||||
volunteer: Volunteer
|
volunteer: Volunteer
|
||||||
saveVolunteer: (newVolunteer: Partial<Volunteer>) => void
|
saveVolunteer: (newVolunteer: Partial<Volunteer>) => void
|
||||||
|
addBefore?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const MemberEdit: FC<Props> = ({ volunteer, saveVolunteer }): JSX.Element => {
|
const MemberEdit: FC<Props> = ({ volunteer, saveVolunteer, addBefore }): JSX.Element => {
|
||||||
const [localVolunteer, setLocalVolunteer] = useState(volunteer)
|
const [localVolunteer, setLocalVolunteer] = useState(volunteer)
|
||||||
|
|
||||||
|
async function addAndWait() {
|
||||||
|
if (addBefore) {
|
||||||
|
addBefore()
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
setTimeout(() => resolve(), 1000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const stringDispatch =
|
const stringDispatch =
|
||||||
(propName: string) =>
|
(propName: string) =>
|
||||||
(e: React.ChangeEvent<HTMLInputElement>): void => {
|
async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
saveVolunteer({ id: localVolunteer.id, [propName]: e.target.value })
|
const rawValue = e.target.value
|
||||||
setLocalVolunteer({ ...localVolunteer, [propName]: e.target.value })
|
const value = rawValue
|
||||||
|
await addAndWait()
|
||||||
|
saveVolunteer({ id: localVolunteer.id, [propName]: rawValue })
|
||||||
|
setLocalVolunteer({ ...localVolunteer, [propName]: value })
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringInput(id: string, value: string): JSX.Element {
|
function stringInput(id: string, value: string): JSX.Element {
|
||||||
@ -40,13 +53,15 @@ const MemberEdit: FC<Props> = ({ volunteer, saveVolunteer }): JSX.Element => {
|
|||||||
|
|
||||||
const numberDispatch =
|
const numberDispatch =
|
||||||
(propName: string) =>
|
(propName: string) =>
|
||||||
(e: React.ChangeEvent<HTMLInputElement>): void => {
|
async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
const value: number = +e.target.value
|
const rawValue = e.target.value
|
||||||
|
const value: number = +rawValue
|
||||||
if (!isFinite(value)) {
|
if (!isFinite(value)) {
|
||||||
toastError("Should be a number")
|
toastError("Should be a number")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
saveVolunteer({ id: localVolunteer.id, [propName]: +value })
|
await addAndWait()
|
||||||
|
saveVolunteer({ id: localVolunteer.id, [propName]: rawValue })
|
||||||
setLocalVolunteer({ ...localVolunteer, [propName]: +value })
|
setLocalVolunteer({ ...localVolunteer, [propName]: +value })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,9 +83,11 @@ const MemberEdit: FC<Props> = ({ volunteer, saveVolunteer }): JSX.Element => {
|
|||||||
|
|
||||||
const booleanDispatch =
|
const booleanDispatch =
|
||||||
(propName: string) =>
|
(propName: string) =>
|
||||||
(e: React.ChangeEvent<HTMLInputElement>): void => {
|
async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
const value: boolean = e.target.value !== "0" && e.target.value !== ""
|
const rawValue = e.target.value
|
||||||
saveVolunteer({ id: localVolunteer.id, [propName]: value })
|
const value: boolean = rawValue !== "0" && rawValue !== ""
|
||||||
|
await addAndWait()
|
||||||
|
saveVolunteer({ id: localVolunteer.id, [propName]: rawValue })
|
||||||
setLocalVolunteer({ ...localVolunteer, [propName]: value })
|
setLocalVolunteer({ ...localVolunteer, [propName]: value })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +129,9 @@ const MemberEdit: FC<Props> = ({ volunteer, saveVolunteer }): JSX.Element => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemberEdit.defaultProps = {
|
||||||
|
addBefore: undefined,
|
||||||
|
}
|
||||||
export default withUserRole(ROLES.ADMIN, memo(withUserConnected(MemberEdit)))
|
export default withUserRole(ROLES.ADMIN, memo(withUserConnected(MemberEdit)))
|
||||||
|
|
||||||
export const fetchFor = []
|
export const fetchFor = []
|
||||||
|
@ -133,7 +133,7 @@ const RegisterForm = ({ dispatch }: Props): JSX.Element => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const { error: volunteerError, entities: volunteer } = useSelector(
|
const { error: volunteerError, entities: volunteer } = useSelector(
|
||||||
(state: AppState) => state.volunteerAdd,
|
(state: AppState) => state.volunteerPartialAdd,
|
||||||
shallowEqual
|
shallowEqual
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { assign, cloneDeep, omit, pick } from "lodash"
|
import { assign, cloneDeep, max, omit, pick } from "lodash"
|
||||||
import bcrypt from "bcrypt"
|
import bcrypt from "bcrypt"
|
||||||
import sgMail from "@sendgrid/mail"
|
import sgMail from "@sendgrid/mail"
|
||||||
|
|
||||||
@ -31,6 +31,26 @@ export const volunteerListGet = expressAccessor.get(async (list, _body, id) => {
|
|||||||
return list
|
return list
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const volunteerAddNew = expressAccessor.add(async (list, _body, _id, roles) => {
|
||||||
|
if (!roles.includes("admin")) {
|
||||||
|
throw Error(`À moins d'être admin, on ne peut pas modifier n'importe quel utilisateur`)
|
||||||
|
}
|
||||||
|
const id = (max(list.map((v) => v.id)) || 0) + 1
|
||||||
|
const password = generatePassword()
|
||||||
|
const passwordHash = await bcrypt.hash(password, 10)
|
||||||
|
|
||||||
|
const newVolunteer: Volunteer = new Volunteer()
|
||||||
|
newVolunteer.id = id
|
||||||
|
newVolunteer.password1 = passwordHash
|
||||||
|
newVolunteer.password2 = passwordHash
|
||||||
|
newVolunteer.firstname = password
|
||||||
|
|
||||||
|
return {
|
||||||
|
toDatabase: newVolunteer,
|
||||||
|
toCaller: newVolunteer,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export const volunteerSet = expressAccessor.set(async (list, body, _id, roles) => {
|
export const volunteerSet = expressAccessor.set(async (list, body, _id, roles) => {
|
||||||
if (!roles.includes("admin")) {
|
if (!roles.includes("admin")) {
|
||||||
throw Error(`À moins d'être admin, on ne peut pas modifier n'importe quel utilisateur`)
|
throw Error(`À moins d'être admin, on ne peut pas modifier n'importe quel utilisateur`)
|
||||||
|
@ -35,6 +35,7 @@ import {
|
|||||||
volunteerTeamAssignSet,
|
volunteerTeamAssignSet,
|
||||||
volunteerListGet,
|
volunteerListGet,
|
||||||
volunteerKnowledgeSet,
|
volunteerKnowledgeSet,
|
||||||
|
volunteerAddNew,
|
||||||
} 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"
|
||||||
@ -114,6 +115,7 @@ app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishe
|
|||||||
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
app.post("/VolunteerTeamAssignSet", secure as RequestHandler, volunteerTeamAssignSet)
|
||||||
|
|
||||||
// Admin only
|
// Admin only
|
||||||
|
app.post("/VolunteerAddNew", secure as RequestHandler, volunteerAddNew)
|
||||||
app.post("/VolunteerSet", secure as RequestHandler, volunteerSet)
|
app.post("/VolunteerSet", secure as RequestHandler, volunteerSet)
|
||||||
app.get("/GameDetailsUpdate", secure as RequestHandler, gameDetailsUpdate)
|
app.get("/GameDetailsUpdate", secure as RequestHandler, gameDetailsUpdate)
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ export const volunteerDiscordIdGet = serviceAccessors.securedCustomGet<
|
|||||||
[number],
|
[number],
|
||||||
VolunteerDiscordId
|
VolunteerDiscordId
|
||||||
>("DiscordId")
|
>("DiscordId")
|
||||||
|
export const volunteerAddNew = serviceAccessors.securedCustomPost<[]>("AddNew")
|
||||||
export const volunteerPartialAdd = serviceAccessors.customPost<[Partial<Volunteer>]>("PartialAdd")
|
export const volunteerPartialAdd = serviceAccessors.customPost<[Partial<Volunteer>]>("PartialAdd")
|
||||||
|
|
||||||
export const volunteerSet = serviceAccessors.securedCustomPost<[Partial<Volunteer>]>("Set")
|
export const volunteerSet = serviceAccessors.securedCustomPost<[Partial<Volunteer>]>("Set")
|
||||||
|
@ -11,7 +11,7 @@ import miscMeetingDateList from "./miscMeetingDateList"
|
|||||||
import postulantAdd from "./postulantAdd"
|
import postulantAdd from "./postulantAdd"
|
||||||
import teamList from "./teamList"
|
import teamList from "./teamList"
|
||||||
import ui from "./ui"
|
import ui from "./ui"
|
||||||
import volunteerAdd from "./volunteerPartialAdd"
|
import volunteerPartialAdd from "./volunteerPartialAdd"
|
||||||
import volunteerAsksSet from "./volunteerAsksSet"
|
import volunteerAsksSet from "./volunteerAsksSet"
|
||||||
import volunteerDayWishesSet from "./volunteerDayWishesSet"
|
import volunteerDayWishesSet from "./volunteerDayWishesSet"
|
||||||
import volunteerDiscordId from "./volunteerDiscordId"
|
import volunteerDiscordId from "./volunteerDiscordId"
|
||||||
@ -39,7 +39,7 @@ export default (history: History) => ({
|
|||||||
postulantAdd,
|
postulantAdd,
|
||||||
teamList,
|
teamList,
|
||||||
ui,
|
ui,
|
||||||
volunteerAdd,
|
volunteerPartialAdd,
|
||||||
volunteerAsksSet,
|
volunteerAsksSet,
|
||||||
volunteerDayWishesSet,
|
volunteerDayWishesSet,
|
||||||
volunteerDiscordId,
|
volunteerDiscordId,
|
||||||
|
@ -64,8 +64,8 @@ export function elementFetch<Element, ServiceInput extends Array<any>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function elementAddFetch<Element>(
|
export function elementAddFetch<Element, ServiceInput extends Array<any>>(
|
||||||
elementAddService: (elementWithoutId: Omit<Element, "id">) => Promise<{
|
elementAddService: (...idArgs: ServiceInput) => Promise<{
|
||||||
data?: Element | undefined
|
data?: Element | undefined
|
||||||
error?: Error | undefined
|
error?: Error | undefined
|
||||||
}>,
|
}>,
|
||||||
@ -74,12 +74,12 @@ export function elementAddFetch<Element>(
|
|||||||
getFailure: ActionCreatorWithPayload<string, string>,
|
getFailure: ActionCreatorWithPayload<string, string>,
|
||||||
errorMessage?: (error: Error) => void,
|
errorMessage?: (error: Error) => void,
|
||||||
successMessage?: () => void
|
successMessage?: () => void
|
||||||
): (elementWithoutId: Omit<Element, "id">) => AppThunk {
|
): (...idArgs: ServiceInput) => AppThunk {
|
||||||
return (elementWithoutId: Omit<Element, "id">): AppThunk =>
|
return (...idArgs: ServiceInput): AppThunk =>
|
||||||
async (dispatch) => {
|
async (dispatch) => {
|
||||||
dispatch(getRequesting())
|
dispatch(getRequesting())
|
||||||
|
|
||||||
const { error, data } = await elementAddService(elementWithoutId)
|
const { error, data } = await elementAddService(...idArgs)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
dispatch(getFailure(error.message))
|
dispatch(getFailure(error.message))
|
||||||
|
45
src/store/volunteerAddNew.ts
Normal file
45
src/store/volunteerAddNew.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
|
||||||
|
|
||||||
|
import { StateRequest, elementAddFetch, toastError } from "./utils"
|
||||||
|
import { Volunteer } from "../services/volunteers"
|
||||||
|
import { volunteerAddNew } from "../services/volunteersAccessors"
|
||||||
|
import { AppThunk } from "."
|
||||||
|
|
||||||
|
const volunteerAdapter = createEntityAdapter<Volunteer>()
|
||||||
|
|
||||||
|
const volunteerAddNewSlice = createSlice({
|
||||||
|
name: "volunteerAddNew",
|
||||||
|
initialState: volunteerAdapter.getInitialState({
|
||||||
|
readyStatus: "idle",
|
||||||
|
} as StateRequest),
|
||||||
|
reducers: {
|
||||||
|
getRequesting: (state) => {
|
||||||
|
state.readyStatus = "request"
|
||||||
|
},
|
||||||
|
getSuccess: (state, { payload }: PayloadAction<Volunteer>) => {
|
||||||
|
state.readyStatus = "success"
|
||||||
|
volunteerAdapter.setOne(state, payload)
|
||||||
|
},
|
||||||
|
getFailure: (state, { payload }: PayloadAction<string>) => {
|
||||||
|
state.readyStatus = "failure"
|
||||||
|
state.error = payload
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default volunteerAddNewSlice.reducer
|
||||||
|
export const { getRequesting, getSuccess, getFailure } = volunteerAddNewSlice.actions
|
||||||
|
|
||||||
|
export const fetchVolunteerAddNew = elementAddFetch(
|
||||||
|
volunteerAddNew,
|
||||||
|
getRequesting,
|
||||||
|
getSuccess,
|
||||||
|
getFailure,
|
||||||
|
() => toastError("Erreur d'ajout !"),
|
||||||
|
() => null
|
||||||
|
)
|
||||||
|
|
||||||
|
export const fetchVolunteerAddNewIfNeed = (): AppThunk => (dispatch, getState) => {
|
||||||
|
const { jwt } = getState().auth
|
||||||
|
return dispatch(fetchVolunteerAddNew(jwt))
|
||||||
|
}
|
@ -1,13 +1,13 @@
|
|||||||
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
|
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
|
||||||
|
|
||||||
import { StateRequest, elementAddFetch } from "./utils"
|
import { StateRequest, elementAddFetch, toastError } from "./utils"
|
||||||
import { Volunteer } from "../services/volunteers"
|
import { Volunteer } from "../services/volunteers"
|
||||||
import { volunteerPartialAdd } from "../services/volunteersAccessors"
|
import { volunteerPartialAdd } from "../services/volunteersAccessors"
|
||||||
|
|
||||||
const volunteerAdapter = createEntityAdapter<Volunteer>()
|
const volunteerAdapter = createEntityAdapter<Volunteer>()
|
||||||
|
|
||||||
const volunteerPartialAddSlice = createSlice({
|
const volunteerPartialAddSlice = createSlice({
|
||||||
name: "volunteerAdd",
|
name: "volunteerPartialAdd",
|
||||||
initialState: volunteerAdapter.getInitialState({
|
initialState: volunteerAdapter.getInitialState({
|
||||||
readyStatus: "idle",
|
readyStatus: "idle",
|
||||||
} as StateRequest),
|
} as StateRequest),
|
||||||
@ -34,6 +34,6 @@ export const fetchVolunteerPartialAdd = elementAddFetch(
|
|||||||
getRequesting,
|
getRequesting,
|
||||||
getSuccess,
|
getSuccess,
|
||||||
getFailure,
|
getFailure,
|
||||||
() => null,
|
() => toastError("Erreur d'inscription !"),
|
||||||
() => null
|
() => null
|
||||||
)
|
)
|
||||||
|
@ -41,19 +41,14 @@ export const fetchVolunteerSet = elementFetch(
|
|||||||
() => toastSuccess("Bénévole modifié !")
|
() => toastSuccess("Bénévole modifié !")
|
||||||
)
|
)
|
||||||
|
|
||||||
const shouldFetchVolunteerSet = (_state: AppState) => true
|
|
||||||
|
|
||||||
export const fetchVolunteerSetIfNeed =
|
export const fetchVolunteerSetIfNeed =
|
||||||
(newPartialVolunteer: Partial<Volunteer>): AppThunk =>
|
(newPartialVolunteer: Partial<Volunteer>): AppThunk =>
|
||||||
(dispatch, getState) => {
|
(dispatch, getState) => {
|
||||||
const { jwt } = getState().auth
|
const { jwt } = getState().auth
|
||||||
if (shouldFetchVolunteerSet(getState()))
|
|
||||||
return dispatch(fetchVolunteerSet(jwt, newPartialVolunteer))
|
return dispatch(fetchVolunteerSet(jwt, newPartialVolunteer))
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectVolunteerSet = createSelector(
|
export const selectVolunteerSet = createSelector(
|
||||||
(state: AppState) => state,
|
(state: AppState) => state,
|
||||||
(state): string | undefined => state.volunteerSet?.entity?.discordId
|
(state): Volunteer | undefined => state.volunteerSet?.entity
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user