mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-08 08:34:20 +02:00
Adds gSheet specific entity read
This commit is contained in:
parent
193f51b54d
commit
c33b9d8f79
@ -313,7 +313,7 @@ function formulaSafe(value: string): string {
|
||||
export { SCOPES }
|
||||
|
||||
class Test {
|
||||
envieId = 5
|
||||
id = 5
|
||||
|
||||
envies = ""
|
||||
|
||||
@ -348,7 +348,7 @@ class Test {
|
||||
async function testGSheetAPi(): Promise<void> {
|
||||
const dataset: Test[] = [
|
||||
{
|
||||
envieId: 1,
|
||||
id: 1,
|
||||
envies: "Présenter le festival et son organisation à un nouveau bénévol au téléphone",
|
||||
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
||||
ignore: true,
|
||||
@ -362,7 +362,7 @@ async function testGSheetAPi(): Promise<void> {
|
||||
tictactoe: [true, false, true, false, false, true],
|
||||
},
|
||||
{
|
||||
envieId: 5,
|
||||
id: 5,
|
||||
envies: "Créer de jolies pages webs",
|
||||
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
||||
ignore: false,
|
||||
@ -372,7 +372,7 @@ async function testGSheetAPi(): Promise<void> {
|
||||
tictactoe: [],
|
||||
},
|
||||
{
|
||||
envieId: 6,
|
||||
id: 6,
|
||||
envies: "Modérer un salon Discord",
|
||||
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
||||
ignore: true,
|
||||
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { render } from "@testing-library/react"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
|
||||
import Info from "../index"
|
||||
|
||||
describe("<Info />", () => {
|
||||
it("renders", () => {
|
||||
const tree = render(
|
||||
<MemoryRouter>
|
||||
<Info
|
||||
item={{
|
||||
membreId: 1,
|
||||
name: "PeL",
|
||||
phone: "+886 0970...",
|
||||
email: "forceoranj@gmail.com",
|
||||
website: "https://www.parisestludique.fr",
|
||||
}}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
).container.firstChild
|
||||
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,29 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Info /> renders 1`] = `
|
||||
<div
|
||||
class="UserCard"
|
||||
>
|
||||
<h4>
|
||||
User Info
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
Name:
|
||||
PeL
|
||||
</li>
|
||||
<li>
|
||||
Phone:
|
||||
+886 0970...
|
||||
</li>
|
||||
<li>
|
||||
Email:
|
||||
forceoranj@gmail.com
|
||||
</li>
|
||||
<li>
|
||||
Website:
|
||||
https://www.parisestludique.fr
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
@ -1,22 +0,0 @@
|
||||
import { memo } from "react"
|
||||
|
||||
import { User } from "../../services/jsonPlaceholder"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
interface Props {
|
||||
item: User
|
||||
}
|
||||
|
||||
const Info = ({ item }: Props) => (
|
||||
<div className={styles.UserCard}>
|
||||
<h4>User Info</h4>
|
||||
<ul>
|
||||
<li>Name: {item.name}</li>
|
||||
<li>Phone: {item.phone}</li>
|
||||
<li>Email: {item.email}</li>
|
||||
<li>Website: {item.website}</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default memo(Info)
|
@ -5,7 +5,7 @@ import { render } from "@testing-library/react"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
|
||||
import mockStore from "../../../utils/mockStore"
|
||||
import List from "../index"
|
||||
import JeuJavList from "../index"
|
||||
|
||||
describe("<List />", () => {
|
||||
const renderHelper = (reducer = { readyStatus: "idle" }) => {
|
||||
@ -13,7 +13,7 @@ describe("<List />", () => {
|
||||
const { container } = render(
|
||||
<ProviderWithStore>
|
||||
<MemoryRouter>
|
||||
<List ids={[5]} />
|
||||
<JeuJavList ids={[5]} />
|
||||
</MemoryRouter>
|
||||
</ProviderWithStore>
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ interface Props {
|
||||
ids: EntityId[]
|
||||
}
|
||||
|
||||
const List = ({ ids }: Props) => {
|
||||
const JeuJavList = ({ ids }: Props) => {
|
||||
const { entities: jeuxJav } = useSelector((state: AppState) => state.jeuJavList, shallowEqual)
|
||||
return (
|
||||
<div className={styles.JeuJavList}>
|
||||
@ -33,4 +33,4 @@ const List = ({ ids }: Props) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(List)
|
||||
export default memo(JeuJavList)
|
||||
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { render } from "@testing-library/react"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
|
||||
import List from "../index"
|
||||
|
||||
describe("<List />", () => {
|
||||
it("renders", () => {
|
||||
const tree = render(
|
||||
<MemoryRouter>
|
||||
<List
|
||||
items={[
|
||||
{
|
||||
membreId: 1,
|
||||
name: "PeL",
|
||||
phone: "+886 0970...",
|
||||
email: "forceoranj@gmail.com",
|
||||
website: "https://www.parisestludique.fr",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
).container.firstChild
|
||||
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,20 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<List /> renders 1`] = `
|
||||
<div
|
||||
class="UserList"
|
||||
>
|
||||
<h4>
|
||||
User List
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="/UserInfo/1"
|
||||
>
|
||||
PeL
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
@ -1,24 +0,0 @@
|
||||
import { memo } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
import { User } from "../../services/jsonPlaceholder"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
interface Props {
|
||||
items: User[]
|
||||
}
|
||||
|
||||
const List = ({ items }: Props) => (
|
||||
<div className={styles.UserList}>
|
||||
<h4>User List</h4>
|
||||
<ul>
|
||||
{items.map(({ membreId, name }) => (
|
||||
<li key={membreId}>
|
||||
<Link to={`/UserInfo/${membreId}`}>{name}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default memo(List)
|
35
src/components/MembreInfo/__tests__/MembreInfo.tsx
Executable file
35
src/components/MembreInfo/__tests__/MembreInfo.tsx
Executable file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { render } from "@testing-library/react"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
|
||||
import MembreInfo from "../index"
|
||||
|
||||
describe("<MembreInfo />", () => {
|
||||
it("renders", () => {
|
||||
const tree = render(
|
||||
<MemoryRouter>
|
||||
<MembreInfo
|
||||
item={{
|
||||
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()
|
||||
})
|
||||
})
|
@ -0,0 +1,21 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<MembreInfo /> renders 1`] = `
|
||||
<div
|
||||
class="MembreCard"
|
||||
>
|
||||
<h4>
|
||||
Membre Info
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
Prénom:
|
||||
Amélie
|
||||
</li>
|
||||
<li>
|
||||
Nom:
|
||||
Aupeix
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
20
src/components/MembreInfo/index.tsx
Executable file
20
src/components/MembreInfo/index.tsx
Executable file
@ -0,0 +1,20 @@
|
||||
import { memo } from "react"
|
||||
|
||||
import { Membre } from "../../services/membres"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
interface Props {
|
||||
item: Membre
|
||||
}
|
||||
|
||||
const MembreInfo = ({ item }: Props) => (
|
||||
<div className={styles.MembreCard}>
|
||||
<h4>Membre Info</h4>
|
||||
<ul>
|
||||
<li>Prénom: {item.prenom}</li>
|
||||
<li>Nom: {item.nom}</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default memo(MembreInfo)
|
@ -1,4 +1,4 @@
|
||||
.user-card {
|
||||
.membre-card {
|
||||
ul {
|
||||
padding-left: 17px;
|
||||
|
37
src/components/MembreList/__tests__/MembreList.tsx
Executable file
37
src/components/MembreList/__tests__/MembreList.tsx
Executable file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { render } from "@testing-library/react"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
|
||||
import MembreList from "../index"
|
||||
|
||||
describe("<MembreList />", () => {
|
||||
it("renders", () => {
|
||||
const tree = render(
|
||||
<MemoryRouter>
|
||||
<MembreList
|
||||
items={[
|
||||
{
|
||||
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()
|
||||
})
|
||||
})
|
@ -0,0 +1,24 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<MembreList /> renders 1`] = `
|
||||
<div
|
||||
class="MembreList"
|
||||
>
|
||||
<h4>
|
||||
Membre List
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="/Membre/1"
|
||||
>
|
||||
<b>
|
||||
Amélie
|
||||
</b>
|
||||
|
||||
Aupeix
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
26
src/components/MembreList/index.tsx
Executable file
26
src/components/MembreList/index.tsx
Executable file
@ -0,0 +1,26 @@
|
||||
import { memo } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
import { Membre } from "../../services/membres"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
interface Props {
|
||||
items: Membre[]
|
||||
}
|
||||
|
||||
const MembreList = ({ items }: Props) => (
|
||||
<div className={styles.MembreList}>
|
||||
<h4>Membre List</h4>
|
||||
<ul>
|
||||
{items.map(({ id, nom, prenom }) => (
|
||||
<li key={id}>
|
||||
<Link to={`/Membre/${id}`}>
|
||||
<b>{prenom}</b> {nom}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default memo(MembreList)
|
@ -1,8 +1,8 @@
|
||||
import List from "./List"
|
||||
import MembreList from "./MembreList"
|
||||
import JeuJavList from "./JeuJavList"
|
||||
import Info from "./Info"
|
||||
import MembreInfo from "./MembreInfo"
|
||||
import ErrorBoundary from "./ErrorBoundary"
|
||||
import Loading from "./Loading"
|
||||
import AddEnvie from "./AddEnvie"
|
||||
|
||||
export { List, JeuJavList, Info, ErrorBoundary, Loading, AddEnvie }
|
||||
export { MembreList, JeuJavList, MembreInfo, ErrorBoundary, Loading, AddEnvie }
|
||||
|
@ -23,7 +23,7 @@ export const addEnvie = async (
|
||||
_next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const envie = await add<EnvieWithoutId, Envie>("Envies d'aider", "envieId", request.body)
|
||||
const envie = await add<EnvieWithoutId, Envie>("Envies d'aider", "id", request.body)
|
||||
if (envie) {
|
||||
response.status(200).json(envie)
|
||||
}
|
||||
|
47
src/gsheets/membres.ts
Normal file
47
src/gsheets/membres.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { Request, Response, NextFunction } from "express"
|
||||
import { getList, get, add } from "./utils"
|
||||
import { Membre, MembreWithoutId } from "../services/membres"
|
||||
|
||||
export const getMembreList = async (
|
||||
_request: Request,
|
||||
response: Response,
|
||||
_next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const list = await getList<Membre>("Membres", new Membre())
|
||||
if (list) {
|
||||
response.status(200).json(list)
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
response.status(400).json(e)
|
||||
}
|
||||
}
|
||||
|
||||
export const getMembre = async (
|
||||
request: Request,
|
||||
response: Response,
|
||||
_next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const id = parseInt(request.query.id as string, 10) || -1
|
||||
const membre = await get<Membre>("Membres", id, new Membre())
|
||||
response.status(200).json(membre)
|
||||
} catch (e: unknown) {
|
||||
response.status(400).json(e)
|
||||
}
|
||||
}
|
||||
|
||||
export const addMembre = async (
|
||||
request: Request,
|
||||
response: Response,
|
||||
_next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const membre = await add<MembreWithoutId, Membre>("Membres", "membreId", request.body)
|
||||
if (membre) {
|
||||
response.status(200).json(membre)
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
response.status(400).json(e)
|
||||
}
|
||||
}
|
@ -6,8 +6,10 @@ import { GoogleSpreadsheet, GoogleSpreadsheetWorksheet } from "google-spreadshee
|
||||
const SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
|
||||
const CRED_PATH = path.resolve(process.cwd(), "access/gsheets.json")
|
||||
|
||||
type ElementWithId = unknown & { id: number }
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export async function getList<Element extends object>(
|
||||
export async function getList<Element extends ElementWithId>(
|
||||
sheetName: string,
|
||||
specimen: Element
|
||||
): Promise<Element[]> {
|
||||
@ -37,7 +39,17 @@ export async function getList<Element extends object>(
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export async function setList<Element extends object>(
|
||||
export async function get<Element extends ElementWithId>(
|
||||
sheetName: string,
|
||||
membreId: number,
|
||||
specimen: Element
|
||||
): Promise<Element | undefined> {
|
||||
const list = await getList<Element>(sheetName, specimen)
|
||||
return list.find((element) => element.id === membreId)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export async function setList<Element extends ElementWithId>(
|
||||
sheetName: string,
|
||||
elements: Element[]
|
||||
): Promise<true | undefined> {
|
||||
@ -90,7 +102,7 @@ export async function setList<Element extends object>(
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export async function add<ElementNoId extends object, Element extends ElementNoId>(
|
||||
export async function add<ElementNoId extends object, Element extends ElementNoId & ElementWithId>(
|
||||
sheetName: string,
|
||||
idFieldName: string,
|
||||
partialElement: Partial<ElementNoId>
|
||||
|
48
src/pages/MembrePage/MembrePage.tsx
Executable file
48
src/pages/MembrePage/MembrePage.tsx
Executable file
@ -0,0 +1,48 @@
|
||||
import { useEffect, memo } from "react"
|
||||
import { RouteComponentProps } from "react-router-dom"
|
||||
import { useDispatch, useSelector, shallowEqual } from "react-redux"
|
||||
import { Helmet } from "react-helmet"
|
||||
|
||||
import { AppState, AppThunk } from "../../store"
|
||||
import { fetchMembreDataIfNeed } from "../../store/membre"
|
||||
import { MembreInfo } from "../../components"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
export type Props = RouteComponentProps<{ id: string }>
|
||||
|
||||
const MembrePage = ({ match }: Props): JSX.Element => {
|
||||
const { id: rawId } = match.params
|
||||
const id = +rawId
|
||||
const dispatch = useDispatch()
|
||||
const membre = useSelector((state: AppState) => state.membre, shallowEqual)
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchMembreDataIfNeed(id))
|
||||
}, [dispatch, id])
|
||||
|
||||
const renderInfo = () => {
|
||||
const membreInfo = membre
|
||||
|
||||
if (!membreInfo || membreInfo.readyStatus === "request") return <p>Loading...</p>
|
||||
|
||||
if (membreInfo.readyStatus === "failure" || !membreInfo.entity)
|
||||
return <p>Oops! Failed to load data.</p>
|
||||
|
||||
return <MembreInfo item={membreInfo.entity} />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.Membre}>
|
||||
<Helmet title="User Info" />
|
||||
{renderInfo()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface LoadDataArgs {
|
||||
params: { id: number }
|
||||
}
|
||||
|
||||
export const loadData = ({ params }: LoadDataArgs): AppThunk[] => [fetchMembreDataIfNeed(params.id)]
|
||||
|
||||
export default memo(MembrePage)
|
@ -4,27 +4,36 @@
|
||||
import { render } from "@testing-library/react"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
|
||||
import { fetchMembreDataIfNeed } from "../../../store/membre"
|
||||
import mockStore from "../../../utils/mockStore"
|
||||
import UserInfo from "../UserInfo"
|
||||
import MembrePage from "../MembrePage"
|
||||
|
||||
describe("<UserInfo />", () => {
|
||||
describe("<MembrePage />", () => {
|
||||
const mockData = {
|
||||
memberId: 1,
|
||||
name: "PeL",
|
||||
phone: "+886 0970...",
|
||||
email: "forceoranj@gmail.com",
|
||||
website: "https://www.parisestludique.fr",
|
||||
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",
|
||||
}
|
||||
const { memberId } = mockData
|
||||
const { id } = mockData
|
||||
|
||||
const renderHelper = (reducer = {}) => {
|
||||
const { dispatch, ProviderWithStore } = mockStore({ userData: reducer })
|
||||
const { dispatch, ProviderWithStore } = mockStore({ membre: reducer })
|
||||
const { container } = render(
|
||||
<ProviderWithStore>
|
||||
<MemoryRouter>
|
||||
{/*
|
||||
@ts-expect-error */}
|
||||
<UserInfo match={{ params: { memberId } }} />
|
||||
<MembrePage match={{ params: { id } }} />
|
||||
</MemoryRouter>
|
||||
</ProviderWithStore>
|
||||
)
|
||||
@ -32,6 +41,13 @@ describe("<UserInfo />", () => {
|
||||
return { dispatch, firstChild: container.firstChild }
|
||||
}
|
||||
|
||||
it("should fetch data when page loaded", () => {
|
||||
const { dispatch } = renderHelper()
|
||||
|
||||
expect(dispatch).toHaveBeenCalledTimes(1)
|
||||
expect(dispatch.mock.calls[0][0].toString()).toBe(fetchMembreDataIfNeed(id).toString())
|
||||
})
|
||||
|
||||
it("renders the loading status if data invalid", () => {
|
||||
expect(renderHelper().firstChild).toMatchSnapshot()
|
||||
})
|
@ -0,0 +1,55 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<MembrePage /> renders an error if loading failed 1`] = `
|
||||
<div
|
||||
class="Membre"
|
||||
>
|
||||
<p>
|
||||
Oops! Failed to load data.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<MembrePage /> renders the <Info /> if loading was successful 1`] = `
|
||||
<div
|
||||
class="Membre"
|
||||
>
|
||||
<div
|
||||
class="MembreCard"
|
||||
>
|
||||
<h4>
|
||||
Membre Info
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
Prénom:
|
||||
Amélie
|
||||
</li>
|
||||
<li>
|
||||
Nom:
|
||||
Aupeix
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<MembrePage /> renders the loading status if data invalid 1`] = `
|
||||
<div
|
||||
class="Membre"
|
||||
>
|
||||
<p>
|
||||
Oops! Failed to load data.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<MembrePage /> renders the loading status if requesting data 1`] = `
|
||||
<div
|
||||
class="Membre"
|
||||
>
|
||||
<p>
|
||||
Loading...
|
||||
</p>
|
||||
</div>
|
||||
`;
|
@ -1,15 +1,15 @@
|
||||
import loadable from "@loadable/component"
|
||||
|
||||
import { Loading, ErrorBoundary } from "../../components"
|
||||
import { Props, loadData } from "./UserInfo"
|
||||
import { Props, loadData } from "./MembrePage"
|
||||
|
||||
const UserInfo = loadable(() => import("./UserInfo"), {
|
||||
const MembrePage = loadable(() => import("./MembrePage"), {
|
||||
fallback: <Loading />,
|
||||
})
|
||||
|
||||
export default (props: Props): JSX.Element => (
|
||||
<ErrorBoundary>
|
||||
<UserInfo {...props} />
|
||||
<MembrePage {...props} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
export { loadData }
|
@ -1,3 +1,3 @@
|
||||
.UserInfo {
|
||||
.Membre {
|
||||
padding: 0 15px;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { useEffect, memo } from "react"
|
||||
import { RouteComponentProps } from "react-router-dom"
|
||||
import { useDispatch, useSelector, shallowEqual } from "react-redux"
|
||||
import { Helmet } from "react-helmet"
|
||||
|
||||
import { AppState, AppThunk } from "../../store"
|
||||
import { fetchUserDataIfNeed } from "../../store/userData"
|
||||
import { Info } from "../../components"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
export type Props = RouteComponentProps<{ memberId: string }>
|
||||
|
||||
const UserInfo = ({ match }: Props): JSX.Element => {
|
||||
const { memberId: rawId } = match.params
|
||||
const id = +rawId
|
||||
const dispatch = useDispatch()
|
||||
const userData = useSelector((state: AppState) => state.userData, shallowEqual)
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchUserDataIfNeed(id))
|
||||
}, [dispatch, id])
|
||||
|
||||
const renderInfo = () => {
|
||||
const userInfo = userData
|
||||
|
||||
if (!userInfo || userInfo.readyStatus === "request") return <p>Loading...</p>
|
||||
|
||||
if (userInfo.readyStatus === "failure" || !userInfo.entity)
|
||||
return <p>Oops! Failed to load data.</p>
|
||||
|
||||
return <Info item={userInfo.entity} />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.UserInfo}>
|
||||
<Helmet title="User Info" />
|
||||
{renderInfo()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface LoadDataArgs {
|
||||
params: { id: number }
|
||||
}
|
||||
|
||||
export const loadData = ({ params }: LoadDataArgs): AppThunk[] => [fetchUserDataIfNeed(params.id)]
|
||||
|
||||
export default memo(UserInfo)
|
@ -1,63 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<UserInfo /> renders an error if loading failed 1`] = `
|
||||
<div
|
||||
class="UserInfo"
|
||||
>
|
||||
<p>
|
||||
Oops! Failed to load data.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<UserInfo /> renders the <Info /> if loading was successful 1`] = `
|
||||
<div
|
||||
class="UserInfo"
|
||||
>
|
||||
<div
|
||||
class="UserCard"
|
||||
>
|
||||
<h4>
|
||||
User Info
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
Name:
|
||||
PeL
|
||||
</li>
|
||||
<li>
|
||||
Phone:
|
||||
+886 0970...
|
||||
</li>
|
||||
<li>
|
||||
Email:
|
||||
forceoranj@gmail.com
|
||||
</li>
|
||||
<li>
|
||||
Website:
|
||||
https://www.parisestludique.fr
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<UserInfo /> renders the loading status if data invalid 1`] = `
|
||||
<div
|
||||
class="UserInfo"
|
||||
>
|
||||
<p>
|
||||
Oops! Failed to load data.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<UserInfo /> renders the loading status if requesting data 1`] = `
|
||||
<div
|
||||
class="UserInfo"
|
||||
>
|
||||
<p>
|
||||
Loading...
|
||||
</p>
|
||||
</div>
|
||||
`;
|
@ -2,7 +2,7 @@ import { RouteConfig } from "react-router-config"
|
||||
|
||||
import App from "../app"
|
||||
import AsyncHome, { loadData as loadHomeData } from "../pages/Home"
|
||||
import AsyncUserInfo, { loadData as loadUserInfoData } from "../pages/UserInfo"
|
||||
import AsyncMembrePage, { loadData as loadMembrePageData } from "../pages/MembrePage"
|
||||
import NotFound from "../pages/NotFound"
|
||||
|
||||
export default [
|
||||
@ -16,9 +16,9 @@ export default [
|
||||
loadData: loadHomeData, // Add your pre-fetch method here
|
||||
},
|
||||
{
|
||||
path: "/UserInfo/:id",
|
||||
component: AsyncUserInfo,
|
||||
loadData: loadUserInfoData,
|
||||
path: "/MembrePage/:id",
|
||||
component: AsyncMembrePage,
|
||||
loadData: loadMembrePageData,
|
||||
},
|
||||
{
|
||||
component: NotFound,
|
||||
|
@ -12,6 +12,7 @@ import ssr from "./ssr"
|
||||
|
||||
import { getJeuJavList } from "../gsheets/jeuJav"
|
||||
import { getEnvieList, addEnvie } from "../gsheets/envies"
|
||||
import { getMembre } from "../gsheets/membres"
|
||||
import config from "../config"
|
||||
|
||||
const app = express()
|
||||
@ -33,8 +34,9 @@ if (__DEV__) devServer(app)
|
||||
|
||||
// Google Sheets requests
|
||||
app.use(express.json())
|
||||
app.get("/JeuJav", getJeuJavList)
|
||||
app.get("/JeuJavList", getJeuJavList)
|
||||
app.get("/GetEnvieList", getEnvieList)
|
||||
app.get("/GetMembre", getMembre)
|
||||
app.post("/AddEnvie", addEnvie)
|
||||
|
||||
// Use React server-side rendering middleware
|
||||
|
@ -3,7 +3,7 @@ import axios from "axios"
|
||||
import config from "../config"
|
||||
|
||||
export class Envie {
|
||||
envieId = 0
|
||||
id = 0
|
||||
|
||||
domaine = ""
|
||||
|
||||
@ -15,7 +15,7 @@ export class Envie {
|
||||
|
||||
dateAjout = ""
|
||||
}
|
||||
export type EnvieWithoutId = Omit<Envie, "envieId">
|
||||
export type EnvieWithoutId = Omit<Envie, "id">
|
||||
|
||||
export interface GetEnvieListResponse {
|
||||
data?: Envie[]
|
||||
|
@ -3,7 +3,7 @@ import axios from "axios"
|
||||
import config from "../config"
|
||||
|
||||
export class JeuJav {
|
||||
jeuId = 0
|
||||
id = 0
|
||||
|
||||
titre = ""
|
||||
|
||||
@ -46,7 +46,7 @@ export interface JeuJavData {
|
||||
|
||||
export const getJeuJavList = async (): Promise<JeuJavList> => {
|
||||
try {
|
||||
const { data } = await axios.get(`${config.API_URL}/JeuJav`)
|
||||
const { data } = await axios.get(`${config.API_URL}/JeuJavList`)
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
@ -55,7 +55,7 @@ export const getJeuJavList = async (): Promise<JeuJavList> => {
|
||||
|
||||
export const getJeuJavData = async (id: string): Promise<JeuJavData> => {
|
||||
try {
|
||||
const { data } = await axios.get(`${config.API_URL}/users/${id}`)
|
||||
const { data } = await axios.get(`${config.API_URL}/JeuJav`, { params: { id } })
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
|
@ -1,37 +0,0 @@
|
||||
import axios from "axios"
|
||||
|
||||
export interface User {
|
||||
membreId: number
|
||||
name: string
|
||||
phone: string
|
||||
email: string
|
||||
website: string
|
||||
}
|
||||
|
||||
interface UserList {
|
||||
data?: User[]
|
||||
error?: Error
|
||||
}
|
||||
|
||||
interface UserData {
|
||||
data?: User
|
||||
error?: Error
|
||||
}
|
||||
|
||||
export const getUserList = async (): Promise<UserList> => {
|
||||
try {
|
||||
const { data } = await axios.get(`https://jsonplaceholder.typicode.com/users`)
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
}
|
||||
}
|
||||
|
||||
export const getUserData = async (id: number): Promise<UserData> => {
|
||||
try {
|
||||
const { data } = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`)
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
}
|
||||
}
|
71
src/services/membres.ts
Normal file
71
src/services/membres.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import axios from "axios"
|
||||
|
||||
import config from "../config"
|
||||
|
||||
export class Membre {
|
||||
id = 0
|
||||
|
||||
nom = ""
|
||||
|
||||
prenom = ""
|
||||
|
||||
mail = ""
|
||||
|
||||
telephone = ""
|
||||
|
||||
photo = ""
|
||||
|
||||
alimentation = ""
|
||||
|
||||
majeur = 1
|
||||
|
||||
privilege = 0
|
||||
|
||||
actif = 0
|
||||
|
||||
commentaire = ""
|
||||
|
||||
horodatage = ""
|
||||
|
||||
passe = ""
|
||||
}
|
||||
export type MembreWithoutId = Omit<Membre, "membreId">
|
||||
|
||||
export interface GetMembreListResponse {
|
||||
data?: Membre[]
|
||||
error?: Error
|
||||
}
|
||||
export const getMembreList = async (): Promise<GetMembreListResponse> => {
|
||||
try {
|
||||
const { data } = await axios.get(`${config.API_URL}/GetMembreList`)
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
}
|
||||
}
|
||||
|
||||
export interface GetMembreResponse {
|
||||
data?: Membre
|
||||
error?: Error
|
||||
}
|
||||
export const getMembre = async (id: number): Promise<GetMembreResponse> => {
|
||||
try {
|
||||
const { data } = await axios.get(`${config.API_URL}/GetMembre`, { params: { id } })
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
}
|
||||
}
|
||||
|
||||
export interface AddMembreResponse {
|
||||
data?: Membre
|
||||
error?: Error
|
||||
}
|
||||
export const addMembre = async (membreWithoutId: MembreWithoutId): Promise<AddMembreResponse> => {
|
||||
try {
|
||||
const { data } = await axios.post(`${config.API_URL}/AddMembre`, membreWithoutId)
|
||||
return { data }
|
||||
} catch (error) {
|
||||
return { error: error as Error }
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ jest.mock("axios")
|
||||
|
||||
const mockData = {
|
||||
"5": {
|
||||
jeuId: 5,
|
||||
id: 5,
|
||||
titre: "6 qui prend!",
|
||||
auteur: "Wolfgang Kramer",
|
||||
editeur: "(uncredited) , Design Edge , B",
|
||||
|
@ -1,41 +1,49 @@
|
||||
import axios from "axios"
|
||||
|
||||
import mockStore from "../../utils/mockStore"
|
||||
import userData, {
|
||||
import membre, {
|
||||
getRequesting,
|
||||
getSuccess,
|
||||
getFailure,
|
||||
fetchUserData,
|
||||
fetchMembreData,
|
||||
initialState,
|
||||
} from "../userData"
|
||||
} from "../membre"
|
||||
|
||||
jest.mock("axios")
|
||||
|
||||
const mockData = {
|
||||
membreId: 1,
|
||||
name: "PeL",
|
||||
phone: "+886 0970...",
|
||||
email: "forceoranj@gmail.com",
|
||||
website: "https://www.parisestludique.fr",
|
||||
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",
|
||||
}
|
||||
const { membreId } = mockData
|
||||
const { id } = mockData
|
||||
const mockError = "Oops! Something went wrong."
|
||||
|
||||
describe("userData reducer", () => {
|
||||
describe("membre reducer", () => {
|
||||
it("should handle initial state correctly", () => {
|
||||
// @ts-expect-error
|
||||
expect(userData(undefined, {})).toEqual(initialState)
|
||||
expect(membre(undefined, {})).toEqual(initialState)
|
||||
})
|
||||
|
||||
it("should handle requesting correctly", () => {
|
||||
expect(userData(undefined, { type: getRequesting.type, payload: membreId })).toEqual({
|
||||
expect(membre(undefined, { type: getRequesting.type, payload: id })).toEqual({
|
||||
readyStatus: "request",
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle success correctly", () => {
|
||||
expect(
|
||||
userData(undefined, {
|
||||
membre(undefined, {
|
||||
type: getSuccess.type,
|
||||
payload: mockData,
|
||||
})
|
||||
@ -44,7 +52,7 @@ describe("userData reducer", () => {
|
||||
|
||||
it("should handle failure correctly", () => {
|
||||
expect(
|
||||
userData(undefined, {
|
||||
membre(undefined, {
|
||||
type: getFailure.type,
|
||||
payload: mockError,
|
||||
})
|
||||
@ -52,8 +60,8 @@ describe("userData reducer", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("userData action", () => {
|
||||
it("fetches user data successful", async () => {
|
||||
describe("membre action", () => {
|
||||
it("fetches membre data successful", async () => {
|
||||
const { dispatch, getActions } = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: getRequesting.type },
|
||||
@ -63,11 +71,11 @@ describe("userData action", () => {
|
||||
// @ts-expect-error
|
||||
axios.get.mockResolvedValue({ data: mockData })
|
||||
|
||||
await dispatch(fetchUserData(membreId))
|
||||
await dispatch(fetchMembreData(id))
|
||||
expect(getActions()).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("fetches user data failed", async () => {
|
||||
it("fetches membre data failed", async () => {
|
||||
const { dispatch, getActions } = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: getRequesting.type },
|
||||
@ -77,7 +85,7 @@ describe("userData action", () => {
|
||||
// @ts-expect-error
|
||||
axios.get.mockRejectedValue({ message: mockError })
|
||||
|
||||
await dispatch(fetchUserData(membreId))
|
||||
await dispatch(fetchMembreData(id))
|
||||
expect(getActions()).toEqual(expectedActions)
|
||||
})
|
||||
})
|
@ -1,35 +1,43 @@
|
||||
import axios from "axios"
|
||||
|
||||
import mockStore from "../../utils/mockStore"
|
||||
import userList, {
|
||||
import membreList, {
|
||||
initialState,
|
||||
getRequesting,
|
||||
getSuccess,
|
||||
getFailure,
|
||||
fetchUserList,
|
||||
} from "../userList"
|
||||
fetchMembreList,
|
||||
} from "../membreList"
|
||||
|
||||
jest.mock("axios")
|
||||
|
||||
const mockData = {
|
||||
"1": {
|
||||
membreId: 1,
|
||||
name: "PeL",
|
||||
phone: "+886 0970...",
|
||||
email: "forceoranj@gmail.com",
|
||||
website: "https://www.parisestludique.fr",
|
||||
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",
|
||||
},
|
||||
}
|
||||
const mockError = "Oops! Something went wrong."
|
||||
|
||||
describe("userList reducer", () => {
|
||||
describe("membreList reducer", () => {
|
||||
it("should handle initial state", () => {
|
||||
// @ts-expect-error
|
||||
expect(userList(undefined, {})).toEqual(initialState)
|
||||
expect(membreList(undefined, {})).toEqual(initialState)
|
||||
})
|
||||
|
||||
it("should handle requesting correctly", () => {
|
||||
expect(userList(undefined, { type: getRequesting.type })).toEqual({
|
||||
expect(membreList(undefined, { type: getRequesting.type })).toEqual({
|
||||
readyStatus: "request",
|
||||
ids: [],
|
||||
entities: {},
|
||||
@ -37,7 +45,7 @@ describe("userList reducer", () => {
|
||||
})
|
||||
|
||||
it("should handle success correctly", () => {
|
||||
expect(userList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
|
||||
expect(membreList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
|
||||
...initialState,
|
||||
readyStatus: "success",
|
||||
ids: [1],
|
||||
@ -46,7 +54,7 @@ describe("userList reducer", () => {
|
||||
})
|
||||
|
||||
it("should handle failure correctly", () => {
|
||||
expect(userList(undefined, { type: getFailure.type, payload: mockError })).toEqual({
|
||||
expect(membreList(undefined, { type: getFailure.type, payload: mockError })).toEqual({
|
||||
...initialState,
|
||||
readyStatus: "failure",
|
||||
error: mockError,
|
||||
@ -54,8 +62,8 @@ describe("userList reducer", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("userList action", () => {
|
||||
it("fetches user list successful", async () => {
|
||||
describe("membreList action", () => {
|
||||
it("fetches membre list successful", async () => {
|
||||
const { dispatch, getActions } = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: getRequesting.type },
|
||||
@ -65,11 +73,11 @@ describe("userList action", () => {
|
||||
// @ts-expect-error
|
||||
axios.get.mockResolvedValue({ data: mockData })
|
||||
|
||||
await dispatch(fetchUserList())
|
||||
await dispatch(fetchMembreList())
|
||||
expect(getActions()).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("fetches user list failed", async () => {
|
||||
it("fetches membre list failed", async () => {
|
||||
const { dispatch, getActions } = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: getRequesting.type },
|
||||
@ -79,7 +87,7 @@ describe("userList action", () => {
|
||||
// @ts-expect-error
|
||||
axios.get.mockRejectedValue({ message: mockError })
|
||||
|
||||
await dispatch(fetchUserList())
|
||||
await dispatch(fetchMembreList())
|
||||
expect(getActions()).toEqual(expectedActions)
|
||||
})
|
||||
})
|
@ -6,7 +6,7 @@ import { Envie, EnvieWithoutId, addEnvie } from "../services/envies"
|
||||
import { AppThunk } from "."
|
||||
|
||||
const envieAdapter = createEntityAdapter<Envie>({
|
||||
selectId: (envie) => envie.envieId,
|
||||
selectId: (envie) => envie.id,
|
||||
})
|
||||
|
||||
const envieAdd = createSlice({
|
||||
|
@ -6,7 +6,7 @@ import { Envie, getEnvieList } from "../services/envies"
|
||||
import { AppThunk, AppState } from "."
|
||||
|
||||
const envieAdapter = createEntityAdapter<Envie>({
|
||||
selectId: (envie) => envie.envieId,
|
||||
selectId: (envie) => envie.id,
|
||||
})
|
||||
|
||||
const envieList = createSlice({
|
||||
|
@ -6,7 +6,7 @@ import { JeuJav, getJeuJavList } from "../services/jeuJav"
|
||||
import { AppThunk, AppState } from "."
|
||||
|
||||
const jeuJavAdapter = createEntityAdapter<JeuJav>({
|
||||
selectId: (jeuJav) => jeuJav.jeuId,
|
||||
selectId: (jeuJav) => jeuJav.id,
|
||||
})
|
||||
|
||||
export const initialState = jeuJavAdapter.getInitialState({
|
||||
|
@ -2,23 +2,23 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
||||
import { toast } from "react-toastify"
|
||||
|
||||
import { StateRequest } from "./utils"
|
||||
import { User, getUserData } from "../services/jsonPlaceholder"
|
||||
import { Membre, getMembre } from "../services/membres"
|
||||
import { AppThunk, AppState } from "."
|
||||
|
||||
type StateUser = { entity?: User } & StateRequest
|
||||
type StateMembre = { entity?: Membre } & StateRequest
|
||||
|
||||
export const initialState: StateUser = {
|
||||
export const initialState: StateMembre = {
|
||||
readyStatus: "idle",
|
||||
}
|
||||
|
||||
const userData = createSlice({
|
||||
name: "userData",
|
||||
const membre = createSlice({
|
||||
name: "membre",
|
||||
initialState,
|
||||
reducers: {
|
||||
getRequesting: (_) => ({
|
||||
readyStatus: "request",
|
||||
}),
|
||||
getSuccess: (_, { payload }: PayloadAction<User>) => ({
|
||||
getSuccess: (_, { payload }: PayloadAction<Membre>) => ({
|
||||
readyStatus: "success",
|
||||
entity: payload,
|
||||
}),
|
||||
@ -29,19 +29,19 @@ const userData = createSlice({
|
||||
},
|
||||
})
|
||||
|
||||
export default userData.reducer
|
||||
export const { getRequesting, getSuccess, getFailure } = userData.actions
|
||||
export default membre.reducer
|
||||
export const { getRequesting, getSuccess, getFailure } = membre.actions
|
||||
|
||||
export const fetchUserData =
|
||||
export const fetchMembreData =
|
||||
(id: number): AppThunk =>
|
||||
async (dispatch) => {
|
||||
dispatch(getRequesting())
|
||||
|
||||
const { error, data } = await getUserData(id)
|
||||
const { error, data } = await getMembre(id)
|
||||
|
||||
if (error) {
|
||||
dispatch(getFailure(error.message))
|
||||
toast.error(`Erreur lors du chargement de l'utilisateur ${id}: ${error.message}`, {
|
||||
toast.error(`Erreur lors du chargement du membre ${id}: ${error.message}`, {
|
||||
position: "top-center",
|
||||
autoClose: 6000,
|
||||
hideProgressBar: true,
|
||||
@ -51,18 +51,17 @@ export const fetchUserData =
|
||||
progress: undefined,
|
||||
})
|
||||
} else {
|
||||
dispatch(getSuccess(data as User))
|
||||
dispatch(getSuccess(data as Membre))
|
||||
}
|
||||
}
|
||||
|
||||
const shouldFetchUserData = (state: AppState, id: number) =>
|
||||
state.userData.readyStatus !== "success" ||
|
||||
(state.userData.entity && state.userData.entity.membreId !== id)
|
||||
const shouldFetchMembreData = (state: AppState, id: number) =>
|
||||
state.membre.readyStatus !== "success" || (state.membre.entity && state.membre.entity.id !== id)
|
||||
|
||||
export const fetchUserDataIfNeed =
|
||||
export const fetchMembreDataIfNeed =
|
||||
(id: number): AppThunk =>
|
||||
(dispatch, getState) => {
|
||||
if (shouldFetchUserData(getState(), id)) return dispatch(fetchUserData(id))
|
||||
if (shouldFetchMembreData(getState(), id)) return dispatch(fetchMembreData(id))
|
||||
|
||||
return null
|
||||
}
|
@ -2,27 +2,25 @@ import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolki
|
||||
import { toast } from "react-toastify"
|
||||
|
||||
import { StateRequest } from "./utils"
|
||||
import { User, getUserList } from "../services/jsonPlaceholder"
|
||||
import { Membre, getMembreList } from "../services/membres"
|
||||
import { AppThunk, AppState } from "."
|
||||
|
||||
const userAdapter = createEntityAdapter<User>({
|
||||
selectId: (user) => user.membreId,
|
||||
})
|
||||
const membreAdapter = createEntityAdapter<Membre>()
|
||||
|
||||
export const initialState = userAdapter.getInitialState({
|
||||
export const initialState = membreAdapter.getInitialState({
|
||||
readyStatus: "idle",
|
||||
} as StateRequest)
|
||||
|
||||
const userList = createSlice({
|
||||
name: "userList",
|
||||
const membreList = createSlice({
|
||||
name: "membreList",
|
||||
initialState,
|
||||
reducers: {
|
||||
getRequesting: (state) => {
|
||||
state.readyStatus = "request"
|
||||
},
|
||||
getSuccess: (state, { payload }: PayloadAction<User[]>) => {
|
||||
getSuccess: (state, { payload }: PayloadAction<Membre[]>) => {
|
||||
state.readyStatus = "success"
|
||||
userAdapter.setAll(state, payload)
|
||||
membreAdapter.setAll(state, payload)
|
||||
},
|
||||
getFailure: (state, { payload }: PayloadAction<string>) => {
|
||||
state.readyStatus = "failure"
|
||||
@ -31,13 +29,13 @@ const userList = createSlice({
|
||||
},
|
||||
})
|
||||
|
||||
export default userList.reducer
|
||||
export const { getRequesting, getSuccess, getFailure } = userList.actions
|
||||
export default membreList.reducer
|
||||
export const { getRequesting, getSuccess, getFailure } = membreList.actions
|
||||
|
||||
export const fetchUserList = (): AppThunk => async (dispatch) => {
|
||||
export const fetchMembreList = (): AppThunk => async (dispatch) => {
|
||||
dispatch(getRequesting())
|
||||
|
||||
const { error, data } = await getUserList()
|
||||
const { error, data } = await getMembreList()
|
||||
|
||||
if (error) {
|
||||
dispatch(getFailure(error.message))
|
||||
@ -51,14 +49,14 @@ export const fetchUserList = (): AppThunk => async (dispatch) => {
|
||||
progress: undefined,
|
||||
})
|
||||
} else {
|
||||
dispatch(getSuccess(data as User[]))
|
||||
dispatch(getSuccess(data as Membre[]))
|
||||
}
|
||||
}
|
||||
|
||||
const shouldFetchUserList = (state: AppState) => state.userList.readyStatus !== "success"
|
||||
const shouldFetchMembreList = (state: AppState) => state.membreList.readyStatus !== "success"
|
||||
|
||||
export const fetchUserListIfNeed = (): AppThunk => (dispatch, getState) => {
|
||||
if (shouldFetchUserList(getState())) return dispatch(fetchUserList())
|
||||
export const fetchMembreListIfNeed = (): AppThunk => (dispatch, getState) => {
|
||||
if (shouldFetchMembreList(getState())) return dispatch(fetchMembreList())
|
||||
|
||||
return null
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
import { History } from "history"
|
||||
import { connectRouter } from "connected-react-router"
|
||||
|
||||
import userList from "./userList"
|
||||
import userData from "./userData"
|
||||
import membreList from "./membreList"
|
||||
import membre from "./membre"
|
||||
import jeuJavList from "./jeuJavList"
|
||||
import envieList from "./envieList"
|
||||
|
||||
// Use inferred return type for making correctly Redux types
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export default (history: History) => ({
|
||||
userList,
|
||||
userData,
|
||||
membreList,
|
||||
membre,
|
||||
jeuJavList,
|
||||
envieList,
|
||||
router: connectRouter(history) as any,
|
||||
|
Loading…
x
Reference in New Issue
Block a user