Add gSheet specific entity write

This commit is contained in:
forceoranj 2021-11-14 23:23:29 +01:00
parent c33b9d8f79
commit b76fbc78ff
22 changed files with 457 additions and 101 deletions

View File

@ -330,20 +330,6 @@ class Test {
tictactoe: boolean[] = [] tictactoe: boolean[] = []
} }
// class Membre {
// membreId = 0
// nom = ""
// prenom = ""
// mail = ""
// telephone = ""
// photo = ""
// }
// Can't run it on every test, it requires private access to a google sheet // Can't run it on every test, it requires private access to a google sheet
async function testGSheetAPi(): Promise<void> { async function testGSheetAPi(): Promise<void> {
const dataset: Test[] = [ const dataset: Test[] = [

View File

@ -3,7 +3,7 @@ import { toast } from "react-toastify"
import { AppDispatch } from "../../store" import { AppDispatch } from "../../store"
import { postEnvie } from "../../store/envieAdd" import { sendAddEnvie } from "../../store/envieAdd"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
interface Props { interface Props {
@ -29,7 +29,7 @@ const AddEnvie = ({ dispatch }: Props) => {
const onSavePostClicked = () => { const onSavePostClicked = () => {
if (domaine && envies) { if (domaine && envies) {
dispatch( dispatch(
postEnvie({ sendAddEnvie({
domaine, domaine,
envies, envies,
precisions, precisions,

View File

@ -0,0 +1,37 @@
/**
* @jest-environment jsdom
*/
import { render } from "@testing-library/react"
import { MemoryRouter } from "react-router-dom"
import MembreSet from "../index"
describe("<SetMembre />", () => {
it("renders", () => {
const dispatch = jest.fn()
const tree = render(
<MemoryRouter>
<MembreSet
dispatch={dispatch}
membre={{
id: 1,
nom: "Aupeix",
prenom: "Amélie",
mail: "pakouille.lakouille@yahoo.fr",
telephone: "0675650392",
photo: "images/membres/$taille/amélie_aupeix.jpg",
alimentation: "Végétarien",
majeur: 1,
privilege: 0,
actif: 0,
commentaire: "",
horodatage: "0000-00-00",
passe: "$2y$10$fSxY9AIuxSiEjwF.J3eXGubIxUPlobkyRrNIal8ASimSjNj4SR.9O",
}}
/>
</MemoryRouter>
).container.firstChild
expect(tree).toMatchSnapshot()
})
})

View File

@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SetMembre /> renders 1`] = `
<section
class="MembreList"
>
<h2>
Modifier un membre
</h2>
<form>
<label
for="postPrenom"
>
Prenom:
<input
id="postPrenom"
name="postPrenom"
type="text"
value="Amélie"
/>
</label>
<label
for="postNom"
>
Nom:
<input
id="postNom"
name="postNom"
type="text"
value="Aupeix"
/>
</label>
<label
for="postMajeur"
>
Majeur:
<input
id="postMajeur"
name="postMajeur"
type="text"
value="1"
/>
</label>
<button
type="button"
>
Save changes
</button>
</form>
</section>
`;

View File

@ -0,0 +1,87 @@
import React, { useState, memo } from "react"
import { toast } from "react-toastify"
import { AppDispatch } from "../../store"
import { sendMembreSet } from "../../store/membreSet"
import { Membre } from "../../services/membres"
import styles from "./styles.module.scss"
interface Props {
dispatch: AppDispatch
membre: Membre
}
const MembreSet = ({ dispatch, membre }: Props) => {
const [prenom, setPrenom] = useState(membre.prenom)
const [nom, setNom] = useState(membre.nom)
const [majeur, setMajeur] = useState(membre.majeur)
const onPrenomChanged = (e: React.ChangeEvent<HTMLInputElement>) => setPrenom(e.target.value)
const onNomChanged = (e: React.ChangeEvent<HTMLInputElement>) => setNom(e.target.value)
const onMajeurChanged = (e: React.ChangeEvent<HTMLInputElement>) => setMajeur(+e.target.value)
const onSavePostClicked = () => {
if (prenom && nom) {
dispatch(
sendMembreSet({
...membre,
prenom,
nom,
majeur,
})
)
} else {
toast.warning("Il faut au moins préciser un prenom et un nom", {
position: "top-center",
autoClose: 6000,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
})
}
}
return (
<section className={styles.MembreList}>
<h2>Modifier un membre</h2>
<form>
<label htmlFor="postPrenom">
Prenom:
<input
type="text"
id="postPrenom"
name="postPrenom"
value={prenom}
onChange={onPrenomChanged}
/>
</label>
<label htmlFor="postNom">
Nom:
<input
type="text"
id="postNom"
name="postNom"
value={nom}
onChange={onNomChanged}
/>
</label>
<label htmlFor="postMajeur">
Majeur:
<input
type="text"
id="postMajeur"
name="postMajeur"
value={majeur}
onChange={onMajeurChanged}
/>
</label>
<button type="button" onClick={onSavePostClicked}>
Save changes
</button>
</form>
</section>
)
}
export default memo(MembreSet)

View File

@ -0,0 +1,17 @@
@import "../../theme/variables";
.jav-game-list {
color: $color-white;
ul {
padding-left: 17px;
li {
margin-bottom: 0.5em;
}
}
a {
color: $color-white;
}
}

View File

@ -1,8 +1,9 @@
import MembreList from "./MembreList" import MembreList from "./MembreList"
import JeuJavList from "./JeuJavList" import JeuJavList from "./JeuJavList"
import MembreInfo from "./MembreInfo" import MembreInfo from "./MembreInfo"
import MembreSet from "./MembreSet"
import ErrorBoundary from "./ErrorBoundary" import ErrorBoundary from "./ErrorBoundary"
import Loading from "./Loading" import Loading from "./Loading"
import AddEnvie from "./AddEnvie" import AddEnvie from "./AddEnvie"
export { MembreList, JeuJavList, MembreInfo, ErrorBoundary, Loading, AddEnvie } export { MembreList, JeuJavList, MembreInfo, MembreSet, ErrorBoundary, Loading, AddEnvie }

View File

@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from "express"
import { getList, add } from "./utils" import { getList, add } from "./utils"
import { Envie, EnvieWithoutId } from "../services/envies" import { Envie, EnvieWithoutId } from "../services/envies"
export const getEnvieList = async ( export const envieListGet = async (
_request: Request, _request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction
@ -17,13 +17,13 @@ export const getEnvieList = async (
} }
} }
export const addEnvie = async ( export const envieAdd = async (
request: Request, request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction
): Promise<void> => { ): Promise<void> => {
try { try {
const envie = await add<EnvieWithoutId, Envie>("Envies d'aider", "id", request.body) const envie = await add<EnvieWithoutId, Envie>("Envies d'aider", request.body)
if (envie) { if (envie) {
response.status(200).json(envie) response.status(200).json(envie)
} }

View File

@ -3,7 +3,7 @@ import _ from "lodash"
import { getList } from "./utils" import { getList } from "./utils"
import { JeuJav } from "../services/jeuJav" import { JeuJav } from "../services/jeuJav"
export const getJeuJavList = async ( export const jeuJavListGet = async (
_request: Request, _request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction
@ -18,7 +18,7 @@ export const getJeuJavList = async (
} }
} }
export const getJeuJavData = async ( export const jeuJavGet = async (
_request: Request, _request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction

View File

@ -1,8 +1,8 @@
import { Request, Response, NextFunction } from "express" import { Request, Response, NextFunction } from "express"
import { getList, get, add } from "./utils" import { getList, get, set, add } from "./utils"
import { Membre, MembreWithoutId } from "../services/membres" import { Membre, MembreWithoutId } from "../services/membres"
export const getMembreList = async ( export const membreListGet = async (
_request: Request, _request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction
@ -17,7 +17,7 @@ export const getMembreList = async (
} }
} }
export const getMembre = async ( export const membreGet = async (
request: Request, request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction
@ -31,13 +31,28 @@ export const getMembre = async (
} }
} }
export const addMembre = async ( export const membreSet = async (
request: Request, request: Request,
response: Response, response: Response,
_next: NextFunction _next: NextFunction
): Promise<void> => { ): Promise<void> => {
try { try {
const membre = await add<MembreWithoutId, Membre>("Membres", "membreId", request.body) const envie = await set<Membre>("Membres", request.body)
if (envie) {
response.status(200).json(envie)
}
} catch (e: unknown) {
response.status(400).json(e)
}
}
export const membreAdd = async (
request: Request,
response: Response,
_next: NextFunction
): Promise<void> => {
try {
const membre = await add<MembreWithoutId, Membre>("Membres", request.body)
if (membre) { if (membre) {
response.status(200).json(membre) response.status(200).json(membre)
} }

View File

@ -101,10 +101,38 @@ export async function setList<Element extends ElementWithId>(
return true return true
} }
// eslint-disable-next-line @typescript-eslint/ban-types
export async function set<Element extends ElementWithId>(
sheetName: string,
element: Element
): Promise<Element | undefined> {
if (!element) {
return undefined
}
const sheet = await getGSheet(sheetName)
// Load sheet into an array of objects
const rows = await sheet.getRows()
if (!rows[0]) {
throw new Error(`No column types defined in sheet ${sheetName}`)
}
const types = _.pick(rows[0], Object.keys(element || {})) as Record<keyof Element, string>
rows.shift()
// Replace previous row
const stringifiedRow = stringifyElement(element, types)
const row = rows.find((rowItem) => +rowItem.id === element.id)
if (!row) {
return undefined
}
Object.assign(row, stringifiedRow)
await row.save()
return element
}
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
export async function add<ElementNoId extends object, Element extends ElementNoId & ElementWithId>( export async function add<ElementNoId extends object, Element extends ElementNoId & ElementWithId>(
sheetName: string, sheetName: string,
idFieldName: string,
partialElement: Partial<ElementNoId> partialElement: Partial<ElementNoId>
): Promise<Element | undefined> { ): Promise<Element | undefined> {
if (!partialElement) { if (!partialElement) {
@ -118,14 +146,17 @@ export async function add<ElementNoId extends object, Element extends ElementNoI
throw new Error(`No column types defined in sheet ${sheetName}`) throw new Error(`No column types defined in sheet ${sheetName}`)
} }
const types = { const types = {
[idFieldName]: "number", id: "number",
...(_.pick(rows[0], Object.keys(partialElement || {})) as Record<keyof Element, string>), ...(_.pick(rows[0], Object.keys(partialElement || {})) as Record<
keyof ElementNoId,
string
>),
} }
// Create full element // Create full element
rows.shift() rows.shift()
const highestId = rows.reduce((id: number, row) => Math.max(id, +row[idFieldName] || 0), 0) const highestId = rows.reduce((id: number, row) => Math.max(id, +row.id || 0), 0)
const element = { [idFieldName]: highestId + 1, ...partialElement } as Element const element = { id: highestId + 1, ...partialElement } as Element
// Add element // Add element
const stringifiedRow = stringifyElement(element, types) const stringifiedRow = stringifyElement(element, types)
@ -241,9 +272,9 @@ function parseElement<Element extends object>(
} }
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
function stringifyElement<Element extends object>( function stringifyElement<ElementNoId extends object, Element extends ElementNoId & ElementWithId>(
element: Element, element: Element,
types: Record<keyof Element, string> types: { id: string } & Record<keyof ElementNoId, string>
): Record<keyof Element, string> { ): Record<keyof Element, string> {
const rawElement: Record<keyof Element, string> = _.reduce( const rawElement: Record<keyof Element, string> = _.reduce(
types, types,

View File

@ -5,7 +5,7 @@ import { Helmet } from "react-helmet"
import { AppState, AppThunk } from "../../store" import { AppState, AppThunk } from "../../store"
import { fetchMembreDataIfNeed } from "../../store/membre" import { fetchMembreDataIfNeed } from "../../store/membre"
import { MembreInfo } from "../../components" import { MembreInfo, MembreSet } from "../../components"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
export type Props = RouteComponentProps<{ id: string }> export type Props = RouteComponentProps<{ id: string }>
@ -28,7 +28,12 @@ const MembrePage = ({ match }: Props): JSX.Element => {
if (membreInfo.readyStatus === "failure" || !membreInfo.entity) if (membreInfo.readyStatus === "failure" || !membreInfo.entity)
return <p>Oops! Failed to load data.</p> return <p>Oops! Failed to load data.</p>
return <MembreInfo item={membreInfo.entity} /> return (
<div>
<MembreInfo item={membreInfo.entity} />
<MembreSet dispatch={dispatch} membre={membreInfo.entity} />
</div>
)
} }
return ( return (

View File

@ -14,6 +14,7 @@ exports[`<MembrePage /> renders the <Info /> if loading was successful 1`] = `
<div <div
class="Membre" class="Membre"
> >
<div>
<div <div
class="MembreCard" class="MembreCard"
> >
@ -31,6 +32,54 @@ exports[`<MembrePage /> renders the <Info /> if loading was successful 1`] = `
</li> </li>
</ul> </ul>
</div> </div>
<section
class="MembreList"
>
<h2>
Modifier un membre
</h2>
<form>
<label
for="postPrenom"
>
Prenom:
<input
id="postPrenom"
name="postPrenom"
type="text"
value="Amélie"
/>
</label>
<label
for="postNom"
>
Nom:
<input
id="postNom"
name="postNom"
type="text"
value="Aupeix"
/>
</label>
<label
for="postMajeur"
>
Majeur:
<input
id="postMajeur"
name="postMajeur"
type="text"
value="1"
/>
</label>
<button
type="button"
>
Save changes
</button>
</form>
</section>
</div>
</div> </div>
`; `;

View File

@ -10,9 +10,9 @@ import chalk from "chalk"
import devServer from "./devServer" import devServer from "./devServer"
import ssr from "./ssr" import ssr from "./ssr"
import { getJeuJavList } from "../gsheets/jeuJav" import { jeuJavListGet } from "../gsheets/jeuJav"
import { getEnvieList, addEnvie } from "../gsheets/envies" import { envieListGet, envieAdd } from "../gsheets/envies"
import { getMembre } from "../gsheets/membres" import { membreGet, membreSet } from "../gsheets/membres"
import config from "../config" import config from "../config"
const app = express() const app = express()
@ -34,10 +34,11 @@ if (__DEV__) devServer(app)
// Google Sheets requests // Google Sheets requests
app.use(express.json()) app.use(express.json())
app.get("/JeuJavList", getJeuJavList) app.get("/JeuJavListGet", jeuJavListGet)
app.get("/GetEnvieList", getEnvieList) app.get("/EnvieListGet", envieListGet)
app.get("/GetMembre", getMembre) app.get("/MembreGet", membreGet)
app.post("/AddEnvie", addEnvie) app.post("/MembreSet", membreSet)
app.post("/EnvieAdd", envieAdd)
// Use React server-side rendering middleware // Use React server-side rendering middleware
app.get("*", ssr) app.get("*", ssr)

View File

@ -17,26 +17,26 @@ export class Envie {
} }
export type EnvieWithoutId = Omit<Envie, "id"> export type EnvieWithoutId = Omit<Envie, "id">
export interface GetEnvieListResponse { export interface EnvieListGetResponse {
data?: Envie[] data?: Envie[]
error?: Error error?: Error
} }
export const getEnvieList = async (): Promise<GetEnvieListResponse> => { export const envieListGet = async (): Promise<EnvieListGetResponse> => {
try { try {
const { data } = await axios.get(`${config.API_URL}/GetEnvieList`) const { data } = await axios.get(`${config.API_URL}/EnvieListGet`)
return { data } return { data }
} catch (error) { } catch (error) {
return { error: error as Error } return { error: error as Error }
} }
} }
export interface AddEnvieResponse { export interface EnvieAddResponse {
data?: Envie data?: Envie
error?: Error error?: Error
} }
export const addEnvie = async (envieWithoutId: EnvieWithoutId): Promise<AddEnvieResponse> => { export const envieAdd = async (envieWithoutId: EnvieWithoutId): Promise<EnvieAddResponse> => {
try { try {
const { data } = await axios.post(`${config.API_URL}/AddEnvie`, envieWithoutId) const { data } = await axios.post(`${config.API_URL}/EnvieAdd`, envieWithoutId)
return { data } return { data }
} catch (error) { } catch (error) {
return { error: error as Error } return { error: error as Error }

View File

@ -34,28 +34,26 @@ export class JeuJav {
bggPhoto = "" bggPhoto = ""
} }
export interface JeuJavList { export interface JeuJavListResponse {
data?: JeuJav[] data?: JeuJav[]
error?: Error error?: Error
} }
export const getJeuJavList = async (): Promise<JeuJavListResponse> => {
try {
const { data } = await axios.get(`${config.API_URL}/JeuJavListGet`)
return { data }
} catch (error) {
return { error: error as Error }
}
}
export interface JeuJavData { export interface JeuJavResponse {
data?: JeuJav data?: JeuJav
error?: Error error?: Error
} }
export const getJeuJavData = async (id: string): Promise<JeuJavResponse> => {
export const getJeuJavList = async (): Promise<JeuJavList> => {
try { try {
const { data } = await axios.get(`${config.API_URL}/JeuJavList`) const { data } = await axios.get(`${config.API_URL}/JeuJavGet`, { params: { id } })
return { data }
} catch (error) {
return { error: error as Error }
}
}
export const getJeuJavData = async (id: string): Promise<JeuJavData> => {
try {
const { data } = await axios.get(`${config.API_URL}/JeuJav`, { params: { id } })
return { data } return { data }
} catch (error) { } catch (error) {
return { error: error as Error } return { error: error as Error }

View File

@ -29,41 +29,54 @@ export class Membre {
passe = "" passe = ""
} }
export type MembreWithoutId = Omit<Membre, "membreId"> export type MembreWithoutId = Omit<Membre, "id">
export interface GetMembreListResponse { export interface MembreListGetResponse {
data?: Membre[] data?: Membre[]
error?: Error error?: Error
} }
export const getMembreList = async (): Promise<GetMembreListResponse> => { export const membreListGet = async (): Promise<MembreListGetResponse> => {
try { try {
const { data } = await axios.get(`${config.API_URL}/GetMembreList`) const { data } = await axios.get(`${config.API_URL}/MembreListGet`)
return { data } return { data }
} catch (error) { } catch (error) {
return { error: error as Error } return { error: error as Error }
} }
} }
export interface GetMembreResponse { export interface MembreGetResponse {
data?: Membre data?: Membre
error?: Error error?: Error
} }
export const getMembre = async (id: number): Promise<GetMembreResponse> => { export const membreGet = async (id: number): Promise<MembreGetResponse> => {
try { try {
const { data } = await axios.get(`${config.API_URL}/GetMembre`, { params: { id } }) const { data } = await axios.get(`${config.API_URL}/MembreGet`, { params: { id } })
return { data } return { data }
} catch (error) { } catch (error) {
return { error: error as Error } return { error: error as Error }
} }
} }
export interface AddMembreResponse { export interface MembreSetResponse {
data?: Membre data?: Membre
error?: Error error?: Error
} }
export const addMembre = async (membreWithoutId: MembreWithoutId): Promise<AddMembreResponse> => { export const membreSet = async (membre: Membre): Promise<MembreSetResponse> => {
try { try {
const { data } = await axios.post(`${config.API_URL}/AddMembre`, membreWithoutId) const { data } = await axios.post(`${config.API_URL}/MembreSet`, membre)
return { data }
} catch (error) {
return { error: error as Error }
}
}
export interface MembreAddResponse {
data?: Membre
error?: Error
}
export const membreAdd = async (membreWithoutId: MembreWithoutId): Promise<MembreAddResponse> => {
try {
const { data } = await axios.post(`${config.API_URL}/MembreAdd`, membreWithoutId)
return { data } return { data }
} catch (error) { } catch (error) {
return { error: error as Error } return { error: error as Error }

View File

@ -2,14 +2,14 @@ import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolki
import { toast } from "react-toastify" import { toast } from "react-toastify"
import { StateRequest } from "./utils" import { StateRequest } from "./utils"
import { Envie, EnvieWithoutId, addEnvie } from "../services/envies" import { Envie, EnvieWithoutId, envieAdd } from "../services/envies"
import { AppThunk } from "." import { AppThunk } from "."
const envieAdapter = createEntityAdapter<Envie>({ const envieAdapter = createEntityAdapter<Envie>({
selectId: (envie) => envie.id, selectId: (envie) => envie.id,
}) })
const envieAdd = createSlice({ const envieAddSlice = createSlice({
name: "addEnvie", name: "addEnvie",
initialState: envieAdapter.getInitialState({ initialState: envieAdapter.getInitialState({
readyStatus: "idle", readyStatus: "idle",
@ -29,15 +29,15 @@ const envieAdd = createSlice({
}, },
}) })
export default envieAdd.reducer export default envieAddSlice.reducer
export const { getRequesting, getSuccess, getFailure } = envieAdd.actions export const { getRequesting, getSuccess, getFailure } = envieAddSlice.actions
export const postEnvie = export const sendAddEnvie =
(envieWithoutId: EnvieWithoutId): AppThunk => (envieWithoutId: EnvieWithoutId): AppThunk =>
async (dispatch) => { async (dispatch) => {
dispatch(getRequesting()) dispatch(getRequesting())
const { error, data } = await addEnvie(envieWithoutId) const { error, data } = await envieAdd(envieWithoutId)
if (error) { if (error) {
dispatch(getFailure(error.message)) dispatch(getFailure(error.message))

View File

@ -2,7 +2,7 @@ import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolki
import { toast } from "react-toastify" import { toast } from "react-toastify"
import { StateRequest } from "./utils" import { StateRequest } from "./utils"
import { Envie, getEnvieList } from "../services/envies" import { Envie, envieListGet } from "../services/envies"
import { AppThunk, AppState } from "." import { AppThunk, AppState } from "."
const envieAdapter = createEntityAdapter<Envie>({ const envieAdapter = createEntityAdapter<Envie>({
@ -35,7 +35,7 @@ export const { getRequesting, getSuccess, getFailure } = envieList.actions
export const fetchEnvieList = (): AppThunk => async (dispatch) => { export const fetchEnvieList = (): AppThunk => async (dispatch) => {
dispatch(getRequesting()) dispatch(getRequesting())
const { error, data } = await getEnvieList() const { error, data } = await envieListGet()
if (error) { if (error) {
dispatch(getFailure(error.message)) dispatch(getFailure(error.message))

View File

@ -2,7 +2,7 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit"
import { toast } from "react-toastify" import { toast } from "react-toastify"
import { StateRequest } from "./utils" import { StateRequest } from "./utils"
import { Membre, getMembre } from "../services/membres" import { Membre, membreGet } from "../services/membres"
import { AppThunk, AppState } from "." import { AppThunk, AppState } from "."
type StateMembre = { entity?: Membre } & StateRequest type StateMembre = { entity?: Membre } & StateRequest
@ -37,7 +37,7 @@ export const fetchMembreData =
async (dispatch) => { async (dispatch) => {
dispatch(getRequesting()) dispatch(getRequesting())
const { error, data } = await getMembre(id) const { error, data } = await membreGet(id)
if (error) { if (error) {
dispatch(getFailure(error.message)) dispatch(getFailure(error.message))

View File

@ -2,7 +2,7 @@ import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolki
import { toast } from "react-toastify" import { toast } from "react-toastify"
import { StateRequest } from "./utils" import { StateRequest } from "./utils"
import { Membre, getMembreList } from "../services/membres" import { Membre, membreListGet } from "../services/membres"
import { AppThunk, AppState } from "." import { AppThunk, AppState } from "."
const membreAdapter = createEntityAdapter<Membre>() const membreAdapter = createEntityAdapter<Membre>()
@ -35,7 +35,7 @@ export const { getRequesting, getSuccess, getFailure } = membreList.actions
export const fetchMembreList = (): AppThunk => async (dispatch) => { export const fetchMembreList = (): AppThunk => async (dispatch) => {
dispatch(getRequesting()) dispatch(getRequesting())
const { error, data } = await getMembreList() const { error, data } = await membreListGet()
if (error) { if (error) {
dispatch(getFailure(error.message)) dispatch(getFailure(error.message))

65
src/store/membreSet.ts Normal file
View File

@ -0,0 +1,65 @@
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
import { toast } from "react-toastify"
import { StateRequest } from "./utils"
import { Membre, membreSet } from "../services/membres"
import { AppThunk } from "."
const membreAdapter = createEntityAdapter<Membre>({
selectId: (membre) => membre.id,
})
const membreSetSlice = createSlice({
name: "membreSet",
initialState: membreAdapter.getInitialState({
readyStatus: "idle",
} as StateRequest),
reducers: {
getRequesting: (state) => {
state.readyStatus = "request"
},
getSuccess: (state, { payload }: PayloadAction<Membre>) => {
state.readyStatus = "success"
membreAdapter.addOne(state, payload)
},
getFailure: (state, { payload }: PayloadAction<string>) => {
state.readyStatus = "failure"
state.error = payload
},
},
})
export default membreSetSlice.reducer
export const { getRequesting, getSuccess, getFailure } = membreSetSlice.actions
export const sendMembreSet =
(membre: Membre): AppThunk =>
async (dispatch) => {
dispatch(getRequesting())
const { error, data } = await membreSet(membre)
if (error) {
dispatch(getFailure(error.message))
toast.error(`Erreur lors de la modification d'un membre: ${error.message}`, {
position: "top-center",
autoClose: 6000,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
})
} else {
dispatch(getSuccess(data as Membre))
toast.success("Membre modifié !", {
position: "top-center",
autoClose: 3000,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
})
}
}