mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-09 17:14:21 +02:00
Adds redux list add example
This commit is contained in:
parent
2616b109d7
commit
1ddb710a6c
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable max-classes-per-file */
|
||||||
import * as _ from "lodash"
|
import * as _ from "lodash"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { promises as fs } from "fs"
|
import { promises as fs } from "fs"
|
||||||
@ -329,6 +330,20 @@ 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[] = [
|
||||||
@ -368,6 +383,15 @@ async function testGSheetAPi(): Promise<void> {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// console.log("Lecture des Membres...")
|
||||||
|
// const datasetMembresLu = await getList<Membre>("Membres", new Membre())
|
||||||
|
// if (!datasetMembresLu) {
|
||||||
|
// console.log("ECHEC de la lecture des membres", datasetMembresLu)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// console.log("Extraction des membres réussie")
|
||||||
|
// await fs.writeFile("membres.json", JSON.stringify(datasetMembresLu))
|
||||||
|
|
||||||
console.log("Test d'écriture...")
|
console.log("Test d'écriture...")
|
||||||
const resultatEcriture = await setList<Test>("Tests de l'API", dataset)
|
const resultatEcriture = await setList<Test>("Tests de l'API", dataset)
|
||||||
if (!resultatEcriture) {
|
if (!resultatEcriture) {
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
"react-router": "^5.2.0",
|
"react-router": "^5.2.0",
|
||||||
"react-router-config": "^5.1.1",
|
"react-router-config": "^5.1.1",
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^5.3.0",
|
||||||
|
"react-toastify": "^8.1.0",
|
||||||
"readline": "^1.3.0",
|
"readline": "^1.3.0",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"serialize-javascript": "^6.0.0",
|
"serialize-javascript": "^6.0.0",
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { Link } from "react-router-dom"
|
import { Link } from "react-router-dom"
|
||||||
import { RouteConfig, renderRoutes } from "react-router-config"
|
import { RouteConfig, renderRoutes } from "react-router-config"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet"
|
||||||
|
import { ToastContainer } from "react-toastify"
|
||||||
|
|
||||||
import logo from "../static/logo.svg"
|
import logo from "../static/logo.svg"
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
// Import your global styles here
|
// Import your global styles here
|
||||||
import "normalize.css/normalize.css"
|
import "normalize.css/normalize.css"
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
|
import "react-toastify/dist/ReactToastify.css"
|
||||||
|
|
||||||
interface Route {
|
interface Route {
|
||||||
route: { routes: RouteConfig[] }
|
route: { routes: RouteConfig[] }
|
||||||
@ -24,6 +26,7 @@ const App = ({ route }: Route): JSX.Element => (
|
|||||||
<hr />
|
<hr />
|
||||||
{/* Child routes won't render without this */}
|
{/* Child routes won't render without this */}
|
||||||
{renderRoutes(route.routes)}
|
{renderRoutes(route.routes)}
|
||||||
|
<ToastContainer />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
20
src/components/AddEnvie/__tests__/AddEnvie.tsx
Normal file
20
src/components/AddEnvie/__tests__/AddEnvie.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @jest-environment jsdom
|
||||||
|
*/
|
||||||
|
import { render } from "@testing-library/react"
|
||||||
|
import { MemoryRouter } from "react-router-dom"
|
||||||
|
|
||||||
|
import AddEnvie from "../index"
|
||||||
|
|
||||||
|
describe("<AddEnvie />", () => {
|
||||||
|
it("renders", () => {
|
||||||
|
const dispatch = jest.fn()
|
||||||
|
const tree = render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<AddEnvie dispatch={dispatch} />
|
||||||
|
</MemoryRouter>
|
||||||
|
).container.firstChild
|
||||||
|
|
||||||
|
expect(tree).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
@ -0,0 +1,69 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<AddEnvie /> renders 1`] = `
|
||||||
|
<section
|
||||||
|
class="EnvieList"
|
||||||
|
>
|
||||||
|
<h2>
|
||||||
|
Ajouter une nouvelle envie
|
||||||
|
</h2>
|
||||||
|
<form>
|
||||||
|
<label
|
||||||
|
for="postDomaine"
|
||||||
|
>
|
||||||
|
Domaine:
|
||||||
|
<input
|
||||||
|
id="postDomaine"
|
||||||
|
name="postDomaine"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEnvies"
|
||||||
|
>
|
||||||
|
Envies:
|
||||||
|
<textarea
|
||||||
|
id="postEnvies"
|
||||||
|
name="postEnvies"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postPrecisions"
|
||||||
|
>
|
||||||
|
Precisions:
|
||||||
|
<textarea
|
||||||
|
id="postPrecisions"
|
||||||
|
name="postPrecisions"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEquipes"
|
||||||
|
>
|
||||||
|
Equipes:
|
||||||
|
<input
|
||||||
|
id="postEquipes"
|
||||||
|
name="postEquipes"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postDateAjout"
|
||||||
|
>
|
||||||
|
DateAjout:
|
||||||
|
<input
|
||||||
|
id="postDateAjout"
|
||||||
|
name="postDateAjout"
|
||||||
|
type="date"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Save Post
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
`;
|
117
src/components/AddEnvie/index.tsx
Normal file
117
src/components/AddEnvie/index.tsx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import React, { useState, memo } from "react"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
|
import { AppDispatch } from "../../store"
|
||||||
|
|
||||||
|
import { postEnvie } from "../../store/envieAdd"
|
||||||
|
import styles from "./styles.module.scss"
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
dispatch: AppDispatch
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddEnvie = ({ dispatch }: Props) => {
|
||||||
|
const [domaine, setDomaine] = useState("")
|
||||||
|
const [envies, setEnvies] = useState("")
|
||||||
|
const [precisions, setPrecisions] = useState("")
|
||||||
|
const [equipes, setEquipes] = useState([""])
|
||||||
|
const [dateAjout, setDateAjout] = useState("")
|
||||||
|
|
||||||
|
const onDomaineChanged = (e: React.ChangeEvent<HTMLInputElement>) => setDomaine(e.target.value)
|
||||||
|
const onEnviesChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => setEnvies(e.target.value)
|
||||||
|
const onPrecisionsChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||||
|
setPrecisions(e.target.value)
|
||||||
|
const onEquipesChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setEquipes(e.target.value.split(/, ?/))
|
||||||
|
const onDateAjoutChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setDateAjout(e.target.value)
|
||||||
|
|
||||||
|
const onSavePostClicked = () => {
|
||||||
|
if (domaine && envies) {
|
||||||
|
dispatch(
|
||||||
|
postEnvie({
|
||||||
|
domaine,
|
||||||
|
envies,
|
||||||
|
precisions,
|
||||||
|
equipes,
|
||||||
|
dateAjout,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
setDomaine("")
|
||||||
|
setEnvies("")
|
||||||
|
setPrecisions("")
|
||||||
|
setEquipes([""])
|
||||||
|
setDateAjout("")
|
||||||
|
} else {
|
||||||
|
toast.warning("Il faut au moins préciser un domaine et l'envie", {
|
||||||
|
position: "top-center",
|
||||||
|
autoClose: 6000,
|
||||||
|
hideProgressBar: true,
|
||||||
|
closeOnClick: true,
|
||||||
|
pauseOnHover: true,
|
||||||
|
draggable: true,
|
||||||
|
progress: undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<section className={styles.EnvieList}>
|
||||||
|
<h2>Ajouter une nouvelle envie</h2>
|
||||||
|
<form>
|
||||||
|
<label htmlFor="postDomaine">
|
||||||
|
Domaine:
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="postDomaine"
|
||||||
|
name="postDomaine"
|
||||||
|
value={domaine}
|
||||||
|
onChange={onDomaineChanged}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label htmlFor="postEnvies">
|
||||||
|
Envies:
|
||||||
|
<textarea
|
||||||
|
id="postEnvies"
|
||||||
|
name="postEnvies"
|
||||||
|
value={envies}
|
||||||
|
onChange={onEnviesChanged}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label htmlFor="postPrecisions">
|
||||||
|
Precisions:
|
||||||
|
<textarea
|
||||||
|
id="postPrecisions"
|
||||||
|
name="postPrecisions"
|
||||||
|
value={precisions}
|
||||||
|
onChange={onPrecisionsChanged}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label htmlFor="postEquipes">
|
||||||
|
Equipes:
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="postEquipes"
|
||||||
|
name="postEquipes"
|
||||||
|
value={equipes.join(", ")}
|
||||||
|
onChange={onEquipesChanged}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label htmlFor="postDateAjout">
|
||||||
|
DateAjout:
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
id="postDateAjout"
|
||||||
|
name="postDateAjout"
|
||||||
|
value={dateAjout}
|
||||||
|
onChange={onDateAjoutChanged}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button type="button" onClick={onSavePostClicked}>
|
||||||
|
Save Post
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default memo(AddEnvie)
|
17
src/components/AddEnvie/styles.module.scss
Normal file
17
src/components/AddEnvie/styles.module.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -3,5 +3,6 @@ import JeuxJavList from "./JeuxJavList"
|
|||||||
import Info from "./Info"
|
import Info from "./Info"
|
||||||
import ErrorBoundary from "./ErrorBoundary"
|
import ErrorBoundary from "./ErrorBoundary"
|
||||||
import Loading from "./Loading"
|
import Loading from "./Loading"
|
||||||
|
import AddEnvie from "./AddEnvie"
|
||||||
|
|
||||||
export { List, JeuxJavList, Info, ErrorBoundary, Loading }
|
export { List, JeuxJavList, Info, ErrorBoundary, Loading, AddEnvie }
|
||||||
|
@ -1,25 +1,33 @@
|
|||||||
import { Request, Response, NextFunction } from "express"
|
import { Request, Response, NextFunction } from "express"
|
||||||
import { getList, setList } from "./utils"
|
import { getList, add } from "./utils"
|
||||||
import { Envie } from "../services/envies"
|
import { Envie, EnvieWithoutId } from "../services/envies"
|
||||||
|
|
||||||
export const getEnvieList = async (
|
export const getEnvieList = async (
|
||||||
_request: Request,
|
_request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
_next: NextFunction
|
_next: NextFunction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
|
try {
|
||||||
const list = await getList<Envie>("Envies d'aider", new Envie())
|
const list = await getList<Envie>("Envies d'aider", new Envie())
|
||||||
if (list) {
|
if (list) {
|
||||||
response.status(200).json(list)
|
response.status(200).json(list)
|
||||||
}
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
response.status(400).json(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setEnvieList = async (
|
export const addEnvie = async (
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
_next: NextFunction
|
_next: NextFunction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const success = await setList<Envie>("Envies d'aider", request.body)
|
try {
|
||||||
if (success) {
|
const envie = await add<EnvieWithoutId, Envie>("Envies d'aider", "envieId", request.body)
|
||||||
response.status(200).json()
|
if (envie) {
|
||||||
|
response.status(200).json(envie)
|
||||||
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
response.status(400).json(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,14 @@ export const getJeuxJavList = async (
|
|||||||
response: Response,
|
response: Response,
|
||||||
_next: NextFunction
|
_next: NextFunction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
|
try {
|
||||||
const list = await getList<JeuxJav>("Jeux JAV", new JeuxJav())
|
const list = await getList<JeuxJav>("Jeux JAV", new JeuxJav())
|
||||||
if (list) {
|
if (list) {
|
||||||
response.status(200).json(list)
|
response.status(200).json(list)
|
||||||
}
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
response.status(400).json(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getJeuxJavData = async (
|
export const getJeuxJavData = async (
|
||||||
|
@ -18,8 +18,7 @@ export async function getList<Element extends object>(
|
|||||||
const rows = (await sheet.getRows()) as StringifiedElement[]
|
const rows = (await sheet.getRows()) as StringifiedElement[]
|
||||||
const elements: Element[] = []
|
const elements: Element[] = []
|
||||||
if (!rows[0]) {
|
if (!rows[0]) {
|
||||||
// TODO: Report format error to database maintainers
|
throw new Error(`No column types defined in sheet ${sheetName}`)
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
const types = _.pick(rows[0], Object.keys(specimen)) as Record<keyof Element, string>
|
const types = _.pick(rows[0], Object.keys(specimen)) as Record<keyof Element, string>
|
||||||
rows.shift()
|
rows.shift()
|
||||||
@ -47,7 +46,7 @@ export async function setList<Element extends object>(
|
|||||||
// Load sheet into an array of objects
|
// Load sheet into an array of objects
|
||||||
const rows = await sheet.getRows()
|
const rows = await sheet.getRows()
|
||||||
if (!rows[0]) {
|
if (!rows[0]) {
|
||||||
return undefined
|
throw new Error(`No column types defined in sheet ${sheetName}`)
|
||||||
}
|
}
|
||||||
const types = _.pick(rows[0], Object.keys(elements[0] || {})) as Record<keyof Element, string>
|
const types = _.pick(rows[0], Object.keys(elements[0] || {})) as Record<keyof Element, string>
|
||||||
|
|
||||||
@ -58,10 +57,6 @@ export async function setList<Element extends object>(
|
|||||||
const row = rows[rowid]
|
const row = rows[rowid]
|
||||||
const stringifiedRow = stringifyElement(element, types)
|
const stringifiedRow = stringifyElement(element, types)
|
||||||
|
|
||||||
if (stringifiedRow === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await sheet.addRow(stringifiedRow)
|
await sheet.addRow(stringifiedRow)
|
||||||
@ -94,6 +89,39 @@ export async function setList<Element extends object>(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
export async function add<ElementNoId extends object, Element extends ElementNoId>(
|
||||||
|
sheetName: string,
|
||||||
|
idFieldName: string,
|
||||||
|
partialElement: Partial<ElementNoId>
|
||||||
|
): Promise<Element | undefined> {
|
||||||
|
if (!partialElement) {
|
||||||
|
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 = {
|
||||||
|
[idFieldName]: "number",
|
||||||
|
...(_.pick(rows[0], Object.keys(partialElement || {})) as Record<keyof Element, string>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create full element
|
||||||
|
rows.shift()
|
||||||
|
const highestId = rows.reduce((id: number, row) => Math.max(id, +row[idFieldName] || 0), 0)
|
||||||
|
const element = { [idFieldName]: highestId + 1, ...partialElement } as Element
|
||||||
|
|
||||||
|
// Add element
|
||||||
|
const stringifiedRow = stringifyElement(element, types)
|
||||||
|
await sheet.addRow(stringifiedRow)
|
||||||
|
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
async function getGSheet(sheetName: string): Promise<GoogleSpreadsheetWorksheet> {
|
async function getGSheet(sheetName: string): Promise<GoogleSpreadsheetWorksheet> {
|
||||||
const doc = new GoogleSpreadsheet("1pMMKcYx6NXLOqNn6pLHJTPMTOLRYZmSNg2QQcAu7-Pw")
|
const doc = new GoogleSpreadsheet("1pMMKcYx6NXLOqNn6pLHJTPMTOLRYZmSNg2QQcAu7-Pw")
|
||||||
const creds = await fs.readFile(CRED_PATH)
|
const creds = await fs.readFile(CRED_PATH)
|
||||||
@ -108,13 +136,10 @@ function parseElement<Element extends object>(
|
|||||||
rawElement: Record<keyof Element, string>,
|
rawElement: Record<keyof Element, string>,
|
||||||
types: Record<keyof Element, string>,
|
types: Record<keyof Element, string>,
|
||||||
specimen: Element
|
specimen: Element
|
||||||
): Element | undefined {
|
): Element {
|
||||||
const fullElement = _.reduce(
|
const fullElement = _.reduce(
|
||||||
types,
|
types,
|
||||||
(element: any, type: string, prop: string) => {
|
(element: any, type: string, prop: string) => {
|
||||||
if (element === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
const rawProp: string = rawElement[prop as keyof Element]
|
const rawProp: string = rawElement[prop as keyof Element]
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "string":
|
case "string":
|
||||||
@ -136,14 +161,13 @@ function parseElement<Element extends object>(
|
|||||||
element[prop] = new Date(+matchDate[3], +matchDate[2] - 1, +matchDate[1])
|
element[prop] = new Date(+matchDate[3], +matchDate[2] - 1, +matchDate[1])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return undefined // TODO: Report format error to database maintainers
|
throw new Error(`Unable to read date from ${rawProp}`)
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// eslint-disable-next-line no-case-declarations
|
// eslint-disable-next-line no-case-declarations
|
||||||
const matchArrayType = type.match(/^(number|string|boolean|date)\[([^\]]+)\]$/)
|
const matchArrayType = type.match(/^(number|string|boolean|date)\[([^\]]+)\]$/)
|
||||||
if (!matchArrayType) {
|
if (!matchArrayType) {
|
||||||
return undefined
|
throw new Error(`Unknown array type for ${type}`)
|
||||||
}
|
}
|
||||||
if (!rawProp) {
|
if (!rawProp) {
|
||||||
element[prop] = []
|
element[prop] = []
|
||||||
@ -189,10 +213,11 @@ function parseElement<Element extends object>(
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if (!rightFormat) {
|
if (!rightFormat) {
|
||||||
return undefined
|
throw new Error(`One array item is not a date in ${rawProp}`)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
throw new Error(`Unknown array type ${arrayType}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,17 +232,10 @@ function parseElement<Element extends object>(
|
|||||||
function stringifyElement<Element extends object>(
|
function stringifyElement<Element extends object>(
|
||||||
element: Element,
|
element: Element,
|
||||||
types: Record<keyof Element, string>
|
types: Record<keyof Element, string>
|
||||||
): Record<keyof Element, string> | undefined {
|
): Record<keyof Element, string> {
|
||||||
const rawElement: Record<keyof Element, string> | undefined = _.reduce(
|
const rawElement: Record<keyof Element, string> = _.reduce(
|
||||||
types,
|
types,
|
||||||
(
|
(stringifiedElement: Record<keyof Element, string>, type: string, prop: string) => {
|
||||||
stringifiedElement: Record<keyof Element, string> | undefined,
|
|
||||||
type: string,
|
|
||||||
prop: string
|
|
||||||
) => {
|
|
||||||
if (stringifiedElement === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
const value = element[prop as keyof Element]
|
const value = element[prop as keyof Element]
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "string":
|
case "string":
|
||||||
@ -233,22 +251,16 @@ function stringifyElement<Element extends object>(
|
|||||||
break
|
break
|
||||||
|
|
||||||
case "date":
|
case "date":
|
||||||
if (value instanceof Date) {
|
stringifiedElement[prop as keyof Element] = stringifiedDate(value)
|
||||||
stringifiedElement[prop as keyof Element] = `${value.getDate()}/${
|
|
||||||
value.getMonth() + 1
|
|
||||||
}/${value.getFullYear()}`
|
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
console.error("Wrong date format in stringifyElement")
|
|
||||||
return undefined // TODO: Report format error to database maintainers
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// eslint-disable-next-line no-case-declarations
|
// eslint-disable-next-line no-case-declarations
|
||||||
const matchArrayType = type.match(/^(number|string|boolean|date)\[([^\]]+)\]$/)
|
const matchArrayType = type.match(/^(number|string|boolean|date)\[([^\]]+)\]$/)
|
||||||
if (!matchArrayType || !_.isArray(value)) {
|
if (!matchArrayType || !_.isArray(value)) {
|
||||||
console.error("Unknown matchArrayType or not an array in stringifyElement")
|
throw new Error(
|
||||||
return undefined
|
"Unknown matchArrayType or not an array in stringifyElement"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-case-declarations
|
// eslint-disable-next-line no-case-declarations
|
||||||
const arrayType = matchArrayType[1]
|
const arrayType = matchArrayType[1]
|
||||||
@ -258,7 +270,7 @@ function stringifyElement<Element extends object>(
|
|||||||
switch (arrayType) {
|
switch (arrayType) {
|
||||||
case "string":
|
case "string":
|
||||||
if (!_.every(value, _.isString)) {
|
if (!_.every(value, _.isString)) {
|
||||||
return undefined
|
throw new Error(`Each date of ${value} is not a string`)
|
||||||
}
|
}
|
||||||
stringifiedElement[prop as keyof Element] = formulaSafe(
|
stringifiedElement[prop as keyof Element] = formulaSafe(
|
||||||
value.join(delimiter)
|
value.join(delimiter)
|
||||||
@ -267,14 +279,14 @@ function stringifyElement<Element extends object>(
|
|||||||
|
|
||||||
case "number":
|
case "number":
|
||||||
if (!_.every(value, _.isNumber)) {
|
if (!_.every(value, _.isNumber)) {
|
||||||
return undefined
|
throw new Error(`Each date of ${value} is not a number`)
|
||||||
}
|
}
|
||||||
stringifiedElement[prop as keyof Element] = value.join(delimiter)
|
stringifiedElement[prop as keyof Element] = value.join(delimiter)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "boolean":
|
case "boolean":
|
||||||
if (!_.every(value, _.isBoolean)) {
|
if (!_.every(value, _.isBoolean)) {
|
||||||
return undefined
|
throw new Error(`Each date of ${value} is not a boolean`)
|
||||||
}
|
}
|
||||||
stringifiedElement[prop as keyof Element] = _.map(value, (val) =>
|
stringifiedElement[prop as keyof Element] = _.map(value, (val) =>
|
||||||
val ? "X" : ""
|
val ? "X" : ""
|
||||||
@ -283,7 +295,7 @@ function stringifyElement<Element extends object>(
|
|||||||
|
|
||||||
case "date":
|
case "date":
|
||||||
if (!_.every(value, _.isDate)) {
|
if (!_.every(value, _.isDate)) {
|
||||||
return undefined
|
throw new Error(`Each date of ${value} is not a date`)
|
||||||
}
|
}
|
||||||
stringifiedElement[prop as keyof Element] = _.map(
|
stringifiedElement[prop as keyof Element] = _.map(
|
||||||
value,
|
value,
|
||||||
@ -293,7 +305,7 @@ function stringifyElement<Element extends object>(
|
|||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return undefined
|
throw new Error(`Unknown array type ${arrayType}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,4 +321,19 @@ function formulaSafe(value: string): string {
|
|||||||
return value.replace(/^=+/, "")
|
return value.replace(/^=+/, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stringifiedDate(value: unknown): string {
|
||||||
|
let date: Date
|
||||||
|
if (value instanceof Date) {
|
||||||
|
date = value
|
||||||
|
} else if (typeof value === "string") {
|
||||||
|
try {
|
||||||
|
date = new Date(value)
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error("Wrong date string format in stringifyElement")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Wrong date format in stringifyElement")
|
||||||
|
}
|
||||||
|
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`
|
||||||
|
}
|
||||||
export { SCOPES }
|
export { SCOPES }
|
||||||
|
@ -6,7 +6,7 @@ import { Helmet } from "react-helmet"
|
|||||||
import { AppState, AppThunk } from "../../store"
|
import { AppState, AppThunk } from "../../store"
|
||||||
import { fetchJeuxJavListIfNeed } from "../../store/jeuxJavList"
|
import { fetchJeuxJavListIfNeed } from "../../store/jeuxJavList"
|
||||||
import { fetchEnvieListIfNeed } from "../../store/envieList"
|
import { fetchEnvieListIfNeed } from "../../store/envieList"
|
||||||
import { JeuxJavList } from "../../components"
|
import { JeuxJavList, AddEnvie } from "../../components"
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
|
|
||||||
export type Props = RouteComponentProps
|
export type Props = RouteComponentProps
|
||||||
@ -31,9 +31,12 @@ function useList(stateToProp: (state: AppState) => any, fetchDataIfNeed: () => A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Home: FC<Props> = (): JSX.Element => (
|
const Home: FC<Props> = (): JSX.Element => {
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
return (
|
||||||
<div className={styles.Home}>
|
<div className={styles.Home}>
|
||||||
<Helmet title="Home" />
|
<Helmet title="Home" />
|
||||||
|
<AddEnvie dispatch={dispatch} />
|
||||||
{/* {useList((state: AppState) => state.envieList, fetchEnvieListifNeed)()} */}
|
{/* {useList((state: AppState) => state.envieList, fetchEnvieListifNeed)()} */}
|
||||||
{useList((state: AppState) => state.jeuxJavList, fetchJeuxJavListIfNeed)()}
|
{useList((state: AppState) => state.jeuxJavList, fetchJeuxJavListIfNeed)()}
|
||||||
{/* <button type="button" onClick={() => setList([{id: 3, joueurs: 4, duree: 5, description: "abcd"}])}>
|
{/* <button type="button" onClick={() => setList([{id: 3, joueurs: 4, duree: 5, description: "abcd"}])}>
|
||||||
@ -41,6 +44,7 @@ const Home: FC<Props> = (): JSX.Element => (
|
|||||||
</button> */}
|
</button> */}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch server-side data here
|
// Fetch server-side data here
|
||||||
export const loadData = (): AppThunk[] => [
|
export const loadData = (): AppThunk[] => [
|
||||||
|
@ -4,6 +4,71 @@ exports[`<Home /> renders an error if loading failed 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="Home"
|
class="Home"
|
||||||
>
|
>
|
||||||
|
<section
|
||||||
|
class="EnvieList"
|
||||||
|
>
|
||||||
|
<h2>
|
||||||
|
Ajouter une nouvelle envie
|
||||||
|
</h2>
|
||||||
|
<form>
|
||||||
|
<label
|
||||||
|
for="postDomaine"
|
||||||
|
>
|
||||||
|
Domaine:
|
||||||
|
<input
|
||||||
|
id="postDomaine"
|
||||||
|
name="postDomaine"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEnvies"
|
||||||
|
>
|
||||||
|
Envies:
|
||||||
|
<textarea
|
||||||
|
id="postEnvies"
|
||||||
|
name="postEnvies"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postPrecisions"
|
||||||
|
>
|
||||||
|
Precisions:
|
||||||
|
<textarea
|
||||||
|
id="postPrecisions"
|
||||||
|
name="postPrecisions"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEquipes"
|
||||||
|
>
|
||||||
|
Equipes:
|
||||||
|
<input
|
||||||
|
id="postEquipes"
|
||||||
|
name="postEquipes"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postDateAjout"
|
||||||
|
>
|
||||||
|
DateAjout:
|
||||||
|
<input
|
||||||
|
id="postDateAjout"
|
||||||
|
name="postDateAjout"
|
||||||
|
type="date"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Save Post
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
<p>
|
<p>
|
||||||
Oops, Failed to load list!
|
Oops, Failed to load list!
|
||||||
</p>
|
</p>
|
||||||
@ -14,6 +79,71 @@ exports[`<Home /> renders the <List /> if loading was successful 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="Home"
|
class="Home"
|
||||||
>
|
>
|
||||||
|
<section
|
||||||
|
class="EnvieList"
|
||||||
|
>
|
||||||
|
<h2>
|
||||||
|
Ajouter une nouvelle envie
|
||||||
|
</h2>
|
||||||
|
<form>
|
||||||
|
<label
|
||||||
|
for="postDomaine"
|
||||||
|
>
|
||||||
|
Domaine:
|
||||||
|
<input
|
||||||
|
id="postDomaine"
|
||||||
|
name="postDomaine"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEnvies"
|
||||||
|
>
|
||||||
|
Envies:
|
||||||
|
<textarea
|
||||||
|
id="postEnvies"
|
||||||
|
name="postEnvies"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postPrecisions"
|
||||||
|
>
|
||||||
|
Precisions:
|
||||||
|
<textarea
|
||||||
|
id="postPrecisions"
|
||||||
|
name="postPrecisions"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEquipes"
|
||||||
|
>
|
||||||
|
Equipes:
|
||||||
|
<input
|
||||||
|
id="postEquipes"
|
||||||
|
name="postEquipes"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postDateAjout"
|
||||||
|
>
|
||||||
|
DateAjout:
|
||||||
|
<input
|
||||||
|
id="postDateAjout"
|
||||||
|
name="postDateAjout"
|
||||||
|
type="date"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Save Post
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
<div
|
<div
|
||||||
class="JeuxJavList"
|
class="JeuxJavList"
|
||||||
>
|
>
|
||||||
@ -36,6 +166,71 @@ exports[`<Home /> renders the loading status if data invalid 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="Home"
|
class="Home"
|
||||||
>
|
>
|
||||||
|
<section
|
||||||
|
class="EnvieList"
|
||||||
|
>
|
||||||
|
<h2>
|
||||||
|
Ajouter une nouvelle envie
|
||||||
|
</h2>
|
||||||
|
<form>
|
||||||
|
<label
|
||||||
|
for="postDomaine"
|
||||||
|
>
|
||||||
|
Domaine:
|
||||||
|
<input
|
||||||
|
id="postDomaine"
|
||||||
|
name="postDomaine"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEnvies"
|
||||||
|
>
|
||||||
|
Envies:
|
||||||
|
<textarea
|
||||||
|
id="postEnvies"
|
||||||
|
name="postEnvies"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postPrecisions"
|
||||||
|
>
|
||||||
|
Precisions:
|
||||||
|
<textarea
|
||||||
|
id="postPrecisions"
|
||||||
|
name="postPrecisions"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEquipes"
|
||||||
|
>
|
||||||
|
Equipes:
|
||||||
|
<input
|
||||||
|
id="postEquipes"
|
||||||
|
name="postEquipes"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postDateAjout"
|
||||||
|
>
|
||||||
|
DateAjout:
|
||||||
|
<input
|
||||||
|
id="postDateAjout"
|
||||||
|
name="postDateAjout"
|
||||||
|
type="date"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Save Post
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
<p>
|
<p>
|
||||||
Loading...
|
Loading...
|
||||||
</p>
|
</p>
|
||||||
@ -46,6 +241,71 @@ exports[`<Home /> renders the loading status if requesting data 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="Home"
|
class="Home"
|
||||||
>
|
>
|
||||||
|
<section
|
||||||
|
class="EnvieList"
|
||||||
|
>
|
||||||
|
<h2>
|
||||||
|
Ajouter une nouvelle envie
|
||||||
|
</h2>
|
||||||
|
<form>
|
||||||
|
<label
|
||||||
|
for="postDomaine"
|
||||||
|
>
|
||||||
|
Domaine:
|
||||||
|
<input
|
||||||
|
id="postDomaine"
|
||||||
|
name="postDomaine"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEnvies"
|
||||||
|
>
|
||||||
|
Envies:
|
||||||
|
<textarea
|
||||||
|
id="postEnvies"
|
||||||
|
name="postEnvies"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postPrecisions"
|
||||||
|
>
|
||||||
|
Precisions:
|
||||||
|
<textarea
|
||||||
|
id="postPrecisions"
|
||||||
|
name="postPrecisions"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postEquipes"
|
||||||
|
>
|
||||||
|
Equipes:
|
||||||
|
<input
|
||||||
|
id="postEquipes"
|
||||||
|
name="postEquipes"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
for="postDateAjout"
|
||||||
|
>
|
||||||
|
DateAjout:
|
||||||
|
<input
|
||||||
|
id="postDateAjout"
|
||||||
|
name="postDateAjout"
|
||||||
|
type="date"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Save Post
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
<p>
|
<p>
|
||||||
Loading...
|
Loading...
|
||||||
</p>
|
</p>
|
||||||
|
@ -11,7 +11,7 @@ import devServer from "./devServer"
|
|||||||
import ssr from "./ssr"
|
import ssr from "./ssr"
|
||||||
|
|
||||||
import { getJeuxJavList } from "../gsheets/jeuxJav"
|
import { getJeuxJavList } from "../gsheets/jeuxJav"
|
||||||
import { getEnvieList, setEnvieList } from "../gsheets/envies"
|
import { getEnvieList, addEnvie } from "../gsheets/envies"
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
@ -32,9 +32,10 @@ app.use(express.static(path.resolve(process.cwd(), "public")))
|
|||||||
if (__DEV__) devServer(app)
|
if (__DEV__) devServer(app)
|
||||||
|
|
||||||
// Google Sheets requests
|
// Google Sheets requests
|
||||||
|
app.use(express.json())
|
||||||
app.get("/JeuxJav", getJeuxJavList)
|
app.get("/JeuxJav", getJeuxJavList)
|
||||||
app.get("/GetList", getEnvieList)
|
app.get("/GetEnvieList", getEnvieList)
|
||||||
app.post("/SetList", setEnvieList)
|
app.post("/AddEnvie", addEnvie)
|
||||||
|
|
||||||
// Use React server-side rendering middleware
|
// Use React server-side rendering middleware
|
||||||
app.get("*", ssr)
|
app.get("*", ssr)
|
||||||
|
@ -3,32 +3,40 @@ import axios from "axios"
|
|||||||
import config from "../config"
|
import config from "../config"
|
||||||
|
|
||||||
export class Envie {
|
export class Envie {
|
||||||
|
envieId = 0
|
||||||
|
|
||||||
domaine = ""
|
domaine = ""
|
||||||
|
|
||||||
envies = ""
|
envies = ""
|
||||||
|
|
||||||
precisions = ""
|
precisions = ""
|
||||||
|
|
||||||
equipes = []
|
equipes: string[] = []
|
||||||
|
|
||||||
dateAjout = new Date(0)
|
dateAjout = ""
|
||||||
}
|
}
|
||||||
|
export type EnvieWithoutId = Omit<Envie, "envieId">
|
||||||
|
|
||||||
export interface EnviesResponse {
|
export interface GetEnvieListResponse {
|
||||||
data?: Envie[]
|
data?: Envie[]
|
||||||
error?: Error
|
error?: Error
|
||||||
}
|
}
|
||||||
export const getEnvieList = async (): Promise<EnviesResponse> => {
|
export const getEnvieList = async (): Promise<GetEnvieListResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${config.API_URL}/GetList`)
|
const { data } = await axios.get(`${config.API_URL}/GetEnvieList`)
|
||||||
return { data }
|
return { data }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const setEnvieList = async (list: Envie[]): Promise<EnviesResponse> => {
|
|
||||||
|
export interface AddEnvieResponse {
|
||||||
|
data?: Envie
|
||||||
|
error?: Error
|
||||||
|
}
|
||||||
|
export const addEnvie = async (envieWithoutId: EnvieWithoutId): Promise<AddEnvieResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(`${config.API_URL}/SetList`, list)
|
const { data } = await axios.post(`${config.API_URL}/AddEnvie`, envieWithoutId)
|
||||||
return { data }
|
return { data }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
|
70
src/store/envieAdd.ts
Normal file
70
src/store/envieAdd.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
|
import { Envie, EnvieWithoutId, addEnvie } from "../services/envies"
|
||||||
|
import { AppThunk } from "."
|
||||||
|
|
||||||
|
interface EnvieRequest {
|
||||||
|
readyStatus: string
|
||||||
|
items: Envie | null
|
||||||
|
error: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: EnvieRequest = {
|
||||||
|
readyStatus: "invalid",
|
||||||
|
items: null,
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
const envieList = createSlice({
|
||||||
|
name: "addEnvie",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
getRequesting: (state: EnvieRequest) => {
|
||||||
|
state.readyStatus = "request"
|
||||||
|
},
|
||||||
|
getSuccess: (state, { payload }: PayloadAction<Envie>) => {
|
||||||
|
state.readyStatus = "success"
|
||||||
|
state.items = payload
|
||||||
|
},
|
||||||
|
getFailure: (state, { payload }: PayloadAction<string>) => {
|
||||||
|
state.readyStatus = "failure"
|
||||||
|
state.error = payload
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default envieList.reducer
|
||||||
|
export const { getRequesting, getSuccess, getFailure } = envieList.actions
|
||||||
|
|
||||||
|
export const postEnvie =
|
||||||
|
(envieWithoutId: EnvieWithoutId): AppThunk =>
|
||||||
|
async (dispatch) => {
|
||||||
|
dispatch(getRequesting())
|
||||||
|
|
||||||
|
const { error, data } = await addEnvie(envieWithoutId)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
dispatch(getFailure(error.message))
|
||||||
|
toast.error(`Erreur lors de l'ajout: ${error.message}`, {
|
||||||
|
position: "top-center",
|
||||||
|
autoClose: 6000,
|
||||||
|
hideProgressBar: true,
|
||||||
|
closeOnClick: true,
|
||||||
|
pauseOnHover: true,
|
||||||
|
draggable: true,
|
||||||
|
progress: undefined,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dispatch(getSuccess(data as Envie))
|
||||||
|
toast.success("Envie ajoutée !", {
|
||||||
|
position: "top-center",
|
||||||
|
autoClose: 3000,
|
||||||
|
hideProgressBar: true,
|
||||||
|
closeOnClick: true,
|
||||||
|
pauseOnHover: true,
|
||||||
|
draggable: true,
|
||||||
|
progress: undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -3,23 +3,23 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
|||||||
import { Envie, getEnvieList } from "../services/envies"
|
import { Envie, getEnvieList } from "../services/envies"
|
||||||
import { AppThunk, AppState } from "."
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
interface EnvieList {
|
interface EnvieListRequest {
|
||||||
readyStatus: string
|
readyStatus: string
|
||||||
items: Envie[]
|
items: Envie[]
|
||||||
error: string | null
|
error: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: EnvieList = {
|
export const initialState: EnvieListRequest = {
|
||||||
readyStatus: "invalid",
|
readyStatus: "invalid",
|
||||||
items: [],
|
items: [],
|
||||||
error: null,
|
error: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const envieList = createSlice({
|
const envieList = createSlice({
|
||||||
name: "envieList",
|
name: "getEnvieList",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
getRequesting: (state: EnvieList) => {
|
getRequesting: (state: EnvieListRequest) => {
|
||||||
state.readyStatus = "request"
|
state.readyStatus = "request"
|
||||||
},
|
},
|
||||||
getSuccess: (state, { payload }: PayloadAction<Envie[]>) => {
|
getSuccess: (state, { payload }: PayloadAction<Envie[]>) => {
|
||||||
|
@ -4,7 +4,7 @@ import { JeuxJav, getJeuxJavList } from "../services/jeuxJav"
|
|||||||
import { AppThunk, AppState } from "."
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
interface JeuxJavList {
|
interface JeuxJavList {
|
||||||
readyStatus: string
|
readyStatus: string // TODO Change it to: "invalid" | "request" | "success" | "failure"
|
||||||
items: JeuxJav[]
|
items: JeuxJav[]
|
||||||
error: string | null
|
error: string | null
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user