mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-09 09:04: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 }
|
export { SCOPES }
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
envieId = 5
|
id = 5
|
||||||
|
|
||||||
envies = ""
|
envies = ""
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ class Test {
|
|||||||
async function testGSheetAPi(): Promise<void> {
|
async function testGSheetAPi(): Promise<void> {
|
||||||
const dataset: Test[] = [
|
const dataset: Test[] = [
|
||||||
{
|
{
|
||||||
envieId: 1,
|
id: 1,
|
||||||
envies: "Présenter le festival et son organisation à un nouveau bénévol au téléphone",
|
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"),
|
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
||||||
ignore: true,
|
ignore: true,
|
||||||
@ -362,7 +362,7 @@ async function testGSheetAPi(): Promise<void> {
|
|||||||
tictactoe: [true, false, true, false, false, true],
|
tictactoe: [true, false, true, false, false, true],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
envieId: 5,
|
id: 5,
|
||||||
envies: "Créer de jolies pages webs",
|
envies: "Créer de jolies pages webs",
|
||||||
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
||||||
ignore: false,
|
ignore: false,
|
||||||
@ -372,7 +372,7 @@ async function testGSheetAPi(): Promise<void> {
|
|||||||
tictactoe: [],
|
tictactoe: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
envieId: 6,
|
id: 6,
|
||||||
envies: "Modérer un salon Discord",
|
envies: "Modérer un salon Discord",
|
||||||
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
dateAjout: new Date("2021-10-18T22:00:00.000Z"),
|
||||||
ignore: true,
|
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 { MemoryRouter } from "react-router-dom"
|
||||||
|
|
||||||
import mockStore from "../../../utils/mockStore"
|
import mockStore from "../../../utils/mockStore"
|
||||||
import List from "../index"
|
import JeuJavList from "../index"
|
||||||
|
|
||||||
describe("<List />", () => {
|
describe("<List />", () => {
|
||||||
const renderHelper = (reducer = { readyStatus: "idle" }) => {
|
const renderHelper = (reducer = { readyStatus: "idle" }) => {
|
||||||
@ -13,7 +13,7 @@ describe("<List />", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<ProviderWithStore>
|
<ProviderWithStore>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<List ids={[5]} />
|
<JeuJavList ids={[5]} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</ProviderWithStore>
|
</ProviderWithStore>
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ interface Props {
|
|||||||
ids: EntityId[]
|
ids: EntityId[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const List = ({ ids }: Props) => {
|
const JeuJavList = ({ ids }: Props) => {
|
||||||
const { entities: jeuxJav } = useSelector((state: AppState) => state.jeuJavList, shallowEqual)
|
const { entities: jeuxJav } = useSelector((state: AppState) => state.jeuJavList, shallowEqual)
|
||||||
return (
|
return (
|
||||||
<div className={styles.JeuJavList}>
|
<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 {
|
ul {
|
||||||
padding-left: 17px;
|
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 JeuJavList from "./JeuJavList"
|
||||||
import Info from "./Info"
|
import MembreInfo from "./MembreInfo"
|
||||||
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 { List, JeuJavList, Info, ErrorBoundary, Loading, AddEnvie }
|
export { MembreList, JeuJavList, MembreInfo, ErrorBoundary, Loading, AddEnvie }
|
||||||
|
@ -23,7 +23,7 @@ export const addEnvie = async (
|
|||||||
_next: NextFunction
|
_next: NextFunction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
try {
|
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) {
|
if (envie) {
|
||||||
response.status(200).json(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 SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
|
||||||
const CRED_PATH = path.resolve(process.cwd(), "access/gsheets.json")
|
const CRED_PATH = path.resolve(process.cwd(), "access/gsheets.json")
|
||||||
|
|
||||||
|
type ElementWithId = unknown & { id: number }
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
export async function getList<Element extends object>(
|
export async function getList<Element extends ElementWithId>(
|
||||||
sheetName: string,
|
sheetName: string,
|
||||||
specimen: Element
|
specimen: Element
|
||||||
): Promise<Element[]> {
|
): Promise<Element[]> {
|
||||||
@ -37,7 +39,17 @@ export async function getList<Element extends object>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// 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,
|
sheetName: string,
|
||||||
elements: Element[]
|
elements: Element[]
|
||||||
): Promise<true | undefined> {
|
): Promise<true | undefined> {
|
||||||
@ -90,7 +102,7 @@ export async function setList<Element extends object>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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>(
|
export async function add<ElementNoId extends object, Element extends ElementNoId & ElementWithId>(
|
||||||
sheetName: string,
|
sheetName: string,
|
||||||
idFieldName: string,
|
idFieldName: string,
|
||||||
partialElement: Partial<ElementNoId>
|
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 { render } from "@testing-library/react"
|
||||||
import { MemoryRouter } from "react-router-dom"
|
import { MemoryRouter } from "react-router-dom"
|
||||||
|
|
||||||
|
import { fetchMembreDataIfNeed } from "../../../store/membre"
|
||||||
import mockStore from "../../../utils/mockStore"
|
import mockStore from "../../../utils/mockStore"
|
||||||
import UserInfo from "../UserInfo"
|
import MembrePage from "../MembrePage"
|
||||||
|
|
||||||
describe("<UserInfo />", () => {
|
describe("<MembrePage />", () => {
|
||||||
const mockData = {
|
const mockData = {
|
||||||
memberId: 1,
|
id: 1,
|
||||||
name: "PeL",
|
nom: "Aupeix",
|
||||||
phone: "+886 0970...",
|
prenom: "Amélie",
|
||||||
email: "forceoranj@gmail.com",
|
mail: "pakouille.lakouille@yahoo.fr",
|
||||||
website: "https://www.parisestludique.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 renderHelper = (reducer = {}) => {
|
||||||
const { dispatch, ProviderWithStore } = mockStore({ userData: reducer })
|
const { dispatch, ProviderWithStore } = mockStore({ membre: reducer })
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<ProviderWithStore>
|
<ProviderWithStore>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
{/*
|
{/*
|
||||||
@ts-expect-error */}
|
@ts-expect-error */}
|
||||||
<UserInfo match={{ params: { memberId } }} />
|
<MembrePage match={{ params: { id } }} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</ProviderWithStore>
|
</ProviderWithStore>
|
||||||
)
|
)
|
||||||
@ -32,6 +41,13 @@ describe("<UserInfo />", () => {
|
|||||||
return { dispatch, firstChild: container.firstChild }
|
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", () => {
|
it("renders the loading status if data invalid", () => {
|
||||||
expect(renderHelper().firstChild).toMatchSnapshot()
|
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 loadable from "@loadable/component"
|
||||||
|
|
||||||
import { Loading, ErrorBoundary } from "../../components"
|
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 />,
|
fallback: <Loading />,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default (props: Props): JSX.Element => (
|
export default (props: Props): JSX.Element => (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<UserInfo {...props} />
|
<MembrePage {...props} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
)
|
)
|
||||||
export { loadData }
|
export { loadData }
|
@ -1,3 +1,3 @@
|
|||||||
.UserInfo {
|
.Membre {
|
||||||
padding: 0 15px;
|
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 App from "../app"
|
||||||
import AsyncHome, { loadData as loadHomeData } from "../pages/Home"
|
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"
|
import NotFound from "../pages/NotFound"
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
@ -16,9 +16,9 @@ export default [
|
|||||||
loadData: loadHomeData, // Add your pre-fetch method here
|
loadData: loadHomeData, // Add your pre-fetch method here
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/UserInfo/:id",
|
path: "/MembrePage/:id",
|
||||||
component: AsyncUserInfo,
|
component: AsyncMembrePage,
|
||||||
loadData: loadUserInfoData,
|
loadData: loadMembrePageData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
component: NotFound,
|
component: NotFound,
|
||||||
|
@ -12,6 +12,7 @@ import ssr from "./ssr"
|
|||||||
|
|
||||||
import { getJeuJavList } from "../gsheets/jeuJav"
|
import { getJeuJavList } from "../gsheets/jeuJav"
|
||||||
import { getEnvieList, addEnvie } from "../gsheets/envies"
|
import { getEnvieList, addEnvie } from "../gsheets/envies"
|
||||||
|
import { getMembre } from "../gsheets/membres"
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
@ -33,8 +34,9 @@ if (__DEV__) devServer(app)
|
|||||||
|
|
||||||
// Google Sheets requests
|
// Google Sheets requests
|
||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
app.get("/JeuJav", getJeuJavList)
|
app.get("/JeuJavList", getJeuJavList)
|
||||||
app.get("/GetEnvieList", getEnvieList)
|
app.get("/GetEnvieList", getEnvieList)
|
||||||
|
app.get("/GetMembre", getMembre)
|
||||||
app.post("/AddEnvie", addEnvie)
|
app.post("/AddEnvie", addEnvie)
|
||||||
|
|
||||||
// Use React server-side rendering middleware
|
// Use React server-side rendering middleware
|
||||||
|
@ -3,7 +3,7 @@ import axios from "axios"
|
|||||||
import config from "../config"
|
import config from "../config"
|
||||||
|
|
||||||
export class Envie {
|
export class Envie {
|
||||||
envieId = 0
|
id = 0
|
||||||
|
|
||||||
domaine = ""
|
domaine = ""
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ export class Envie {
|
|||||||
|
|
||||||
dateAjout = ""
|
dateAjout = ""
|
||||||
}
|
}
|
||||||
export type EnvieWithoutId = Omit<Envie, "envieId">
|
export type EnvieWithoutId = Omit<Envie, "id">
|
||||||
|
|
||||||
export interface GetEnvieListResponse {
|
export interface GetEnvieListResponse {
|
||||||
data?: Envie[]
|
data?: Envie[]
|
||||||
|
@ -3,7 +3,7 @@ import axios from "axios"
|
|||||||
import config from "../config"
|
import config from "../config"
|
||||||
|
|
||||||
export class JeuJav {
|
export class JeuJav {
|
||||||
jeuId = 0
|
id = 0
|
||||||
|
|
||||||
titre = ""
|
titre = ""
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ export interface JeuJavData {
|
|||||||
|
|
||||||
export const getJeuJavList = async (): Promise<JeuJavList> => {
|
export const getJeuJavList = async (): Promise<JeuJavList> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${config.API_URL}/JeuJav`)
|
const { data } = await axios.get(`${config.API_URL}/JeuJavList`)
|
||||||
return { data }
|
return { data }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error as Error }
|
return { error: error as Error }
|
||||||
@ -55,7 +55,7 @@ export const getJeuJavList = async (): Promise<JeuJavList> => {
|
|||||||
|
|
||||||
export const getJeuJavData = async (id: string): Promise<JeuJavData> => {
|
export const getJeuJavData = async (id: string): Promise<JeuJavData> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${config.API_URL}/users/${id}`)
|
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 }
|
||||||
|
@ -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 = {
|
const mockData = {
|
||||||
"5": {
|
"5": {
|
||||||
jeuId: 5,
|
id: 5,
|
||||||
titre: "6 qui prend!",
|
titre: "6 qui prend!",
|
||||||
auteur: "Wolfgang Kramer",
|
auteur: "Wolfgang Kramer",
|
||||||
editeur: "(uncredited) , Design Edge , B",
|
editeur: "(uncredited) , Design Edge , B",
|
||||||
|
@ -1,41 +1,49 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
|
||||||
import mockStore from "../../utils/mockStore"
|
import mockStore from "../../utils/mockStore"
|
||||||
import userData, {
|
import membre, {
|
||||||
getRequesting,
|
getRequesting,
|
||||||
getSuccess,
|
getSuccess,
|
||||||
getFailure,
|
getFailure,
|
||||||
fetchUserData,
|
fetchMembreData,
|
||||||
initialState,
|
initialState,
|
||||||
} from "../userData"
|
} from "../membre"
|
||||||
|
|
||||||
jest.mock("axios")
|
jest.mock("axios")
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
membreId: 1,
|
id: 1,
|
||||||
name: "PeL",
|
nom: "Aupeix",
|
||||||
phone: "+886 0970...",
|
prenom: "Amélie",
|
||||||
email: "forceoranj@gmail.com",
|
mail: "pakouille.lakouille@yahoo.fr",
|
||||||
website: "https://www.parisestludique.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."
|
const mockError = "Oops! Something went wrong."
|
||||||
|
|
||||||
describe("userData reducer", () => {
|
describe("membre reducer", () => {
|
||||||
it("should handle initial state correctly", () => {
|
it("should handle initial state correctly", () => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
expect(userData(undefined, {})).toEqual(initialState)
|
expect(membre(undefined, {})).toEqual(initialState)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle requesting correctly", () => {
|
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",
|
readyStatus: "request",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle success correctly", () => {
|
it("should handle success correctly", () => {
|
||||||
expect(
|
expect(
|
||||||
userData(undefined, {
|
membre(undefined, {
|
||||||
type: getSuccess.type,
|
type: getSuccess.type,
|
||||||
payload: mockData,
|
payload: mockData,
|
||||||
})
|
})
|
||||||
@ -44,7 +52,7 @@ describe("userData reducer", () => {
|
|||||||
|
|
||||||
it("should handle failure correctly", () => {
|
it("should handle failure correctly", () => {
|
||||||
expect(
|
expect(
|
||||||
userData(undefined, {
|
membre(undefined, {
|
||||||
type: getFailure.type,
|
type: getFailure.type,
|
||||||
payload: mockError,
|
payload: mockError,
|
||||||
})
|
})
|
||||||
@ -52,8 +60,8 @@ describe("userData reducer", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("userData action", () => {
|
describe("membre action", () => {
|
||||||
it("fetches user data successful", async () => {
|
it("fetches membre data successful", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type },
|
||||||
@ -63,11 +71,11 @@ describe("userData action", () => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockResolvedValue({ data: mockData })
|
axios.get.mockResolvedValue({ data: mockData })
|
||||||
|
|
||||||
await dispatch(fetchUserData(membreId))
|
await dispatch(fetchMembreData(id))
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("fetches user data failed", async () => {
|
it("fetches membre data failed", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type },
|
||||||
@ -77,7 +85,7 @@ describe("userData action", () => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockRejectedValue({ message: mockError })
|
axios.get.mockRejectedValue({ message: mockError })
|
||||||
|
|
||||||
await dispatch(fetchUserData(membreId))
|
await dispatch(fetchMembreData(id))
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
})
|
})
|
||||||
})
|
})
|
@ -1,35 +1,43 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
|
||||||
import mockStore from "../../utils/mockStore"
|
import mockStore from "../../utils/mockStore"
|
||||||
import userList, {
|
import membreList, {
|
||||||
initialState,
|
initialState,
|
||||||
getRequesting,
|
getRequesting,
|
||||||
getSuccess,
|
getSuccess,
|
||||||
getFailure,
|
getFailure,
|
||||||
fetchUserList,
|
fetchMembreList,
|
||||||
} from "../userList"
|
} from "../membreList"
|
||||||
|
|
||||||
jest.mock("axios")
|
jest.mock("axios")
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
"1": {
|
"1": {
|
||||||
membreId: 1,
|
id: 1,
|
||||||
name: "PeL",
|
nom: "Aupeix",
|
||||||
phone: "+886 0970...",
|
prenom: "Amélie",
|
||||||
email: "forceoranj@gmail.com",
|
mail: "pakouille.lakouille@yahoo.fr",
|
||||||
website: "https://www.parisestludique.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."
|
const mockError = "Oops! Something went wrong."
|
||||||
|
|
||||||
describe("userList reducer", () => {
|
describe("membreList reducer", () => {
|
||||||
it("should handle initial state", () => {
|
it("should handle initial state", () => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
expect(userList(undefined, {})).toEqual(initialState)
|
expect(membreList(undefined, {})).toEqual(initialState)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle requesting correctly", () => {
|
it("should handle requesting correctly", () => {
|
||||||
expect(userList(undefined, { type: getRequesting.type })).toEqual({
|
expect(membreList(undefined, { type: getRequesting.type })).toEqual({
|
||||||
readyStatus: "request",
|
readyStatus: "request",
|
||||||
ids: [],
|
ids: [],
|
||||||
entities: {},
|
entities: {},
|
||||||
@ -37,7 +45,7 @@ describe("userList reducer", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should handle success correctly", () => {
|
it("should handle success correctly", () => {
|
||||||
expect(userList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
|
expect(membreList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
readyStatus: "success",
|
readyStatus: "success",
|
||||||
ids: [1],
|
ids: [1],
|
||||||
@ -46,7 +54,7 @@ describe("userList reducer", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should handle failure correctly", () => {
|
it("should handle failure correctly", () => {
|
||||||
expect(userList(undefined, { type: getFailure.type, payload: mockError })).toEqual({
|
expect(membreList(undefined, { type: getFailure.type, payload: mockError })).toEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
readyStatus: "failure",
|
readyStatus: "failure",
|
||||||
error: mockError,
|
error: mockError,
|
||||||
@ -54,8 +62,8 @@ describe("userList reducer", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("userList action", () => {
|
describe("membreList action", () => {
|
||||||
it("fetches user list successful", async () => {
|
it("fetches membre list successful", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type },
|
||||||
@ -65,11 +73,11 @@ describe("userList action", () => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockResolvedValue({ data: mockData })
|
axios.get.mockResolvedValue({ data: mockData })
|
||||||
|
|
||||||
await dispatch(fetchUserList())
|
await dispatch(fetchMembreList())
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("fetches user list failed", async () => {
|
it("fetches membre list failed", async () => {
|
||||||
const { dispatch, getActions } = mockStore()
|
const { dispatch, getActions } = mockStore()
|
||||||
const expectedActions = [
|
const expectedActions = [
|
||||||
{ type: getRequesting.type },
|
{ type: getRequesting.type },
|
||||||
@ -79,7 +87,7 @@ describe("userList action", () => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
axios.get.mockRejectedValue({ message: mockError })
|
axios.get.mockRejectedValue({ message: mockError })
|
||||||
|
|
||||||
await dispatch(fetchUserList())
|
await dispatch(fetchMembreList())
|
||||||
expect(getActions()).toEqual(expectedActions)
|
expect(getActions()).toEqual(expectedActions)
|
||||||
})
|
})
|
||||||
})
|
})
|
@ -6,7 +6,7 @@ import { Envie, EnvieWithoutId, addEnvie } from "../services/envies"
|
|||||||
import { AppThunk } from "."
|
import { AppThunk } from "."
|
||||||
|
|
||||||
const envieAdapter = createEntityAdapter<Envie>({
|
const envieAdapter = createEntityAdapter<Envie>({
|
||||||
selectId: (envie) => envie.envieId,
|
selectId: (envie) => envie.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const envieAdd = createSlice({
|
const envieAdd = createSlice({
|
||||||
|
@ -6,7 +6,7 @@ import { Envie, getEnvieList } from "../services/envies"
|
|||||||
import { AppThunk, AppState } from "."
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
const envieAdapter = createEntityAdapter<Envie>({
|
const envieAdapter = createEntityAdapter<Envie>({
|
||||||
selectId: (envie) => envie.envieId,
|
selectId: (envie) => envie.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const envieList = createSlice({
|
const envieList = createSlice({
|
||||||
|
@ -6,7 +6,7 @@ import { JeuJav, getJeuJavList } from "../services/jeuJav"
|
|||||||
import { AppThunk, AppState } from "."
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
const jeuJavAdapter = createEntityAdapter<JeuJav>({
|
const jeuJavAdapter = createEntityAdapter<JeuJav>({
|
||||||
selectId: (jeuJav) => jeuJav.jeuId,
|
selectId: (jeuJav) => jeuJav.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const initialState = jeuJavAdapter.getInitialState({
|
export const initialState = jeuJavAdapter.getInitialState({
|
||||||
|
@ -2,23 +2,23 @@ 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 { User, getUserData } from "../services/jsonPlaceholder"
|
import { Membre, getMembre } from "../services/membres"
|
||||||
import { AppThunk, AppState } from "."
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
type StateUser = { entity?: User } & StateRequest
|
type StateMembre = { entity?: Membre } & StateRequest
|
||||||
|
|
||||||
export const initialState: StateUser = {
|
export const initialState: StateMembre = {
|
||||||
readyStatus: "idle",
|
readyStatus: "idle",
|
||||||
}
|
}
|
||||||
|
|
||||||
const userData = createSlice({
|
const membre = createSlice({
|
||||||
name: "userData",
|
name: "membre",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
getRequesting: (_) => ({
|
getRequesting: (_) => ({
|
||||||
readyStatus: "request",
|
readyStatus: "request",
|
||||||
}),
|
}),
|
||||||
getSuccess: (_, { payload }: PayloadAction<User>) => ({
|
getSuccess: (_, { payload }: PayloadAction<Membre>) => ({
|
||||||
readyStatus: "success",
|
readyStatus: "success",
|
||||||
entity: payload,
|
entity: payload,
|
||||||
}),
|
}),
|
||||||
@ -29,19 +29,19 @@ const userData = createSlice({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default userData.reducer
|
export default membre.reducer
|
||||||
export const { getRequesting, getSuccess, getFailure } = userData.actions
|
export const { getRequesting, getSuccess, getFailure } = membre.actions
|
||||||
|
|
||||||
export const fetchUserData =
|
export const fetchMembreData =
|
||||||
(id: number): AppThunk =>
|
(id: number): AppThunk =>
|
||||||
async (dispatch) => {
|
async (dispatch) => {
|
||||||
dispatch(getRequesting())
|
dispatch(getRequesting())
|
||||||
|
|
||||||
const { error, data } = await getUserData(id)
|
const { error, data } = await getMembre(id)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
dispatch(getFailure(error.message))
|
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",
|
position: "top-center",
|
||||||
autoClose: 6000,
|
autoClose: 6000,
|
||||||
hideProgressBar: true,
|
hideProgressBar: true,
|
||||||
@ -51,18 +51,17 @@ export const fetchUserData =
|
|||||||
progress: undefined,
|
progress: undefined,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
dispatch(getSuccess(data as User))
|
dispatch(getSuccess(data as Membre))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldFetchUserData = (state: AppState, id: number) =>
|
const shouldFetchMembreData = (state: AppState, id: number) =>
|
||||||
state.userData.readyStatus !== "success" ||
|
state.membre.readyStatus !== "success" || (state.membre.entity && state.membre.entity.id !== id)
|
||||||
(state.userData.entity && state.userData.entity.membreId !== id)
|
|
||||||
|
|
||||||
export const fetchUserDataIfNeed =
|
export const fetchMembreDataIfNeed =
|
||||||
(id: number): AppThunk =>
|
(id: number): AppThunk =>
|
||||||
(dispatch, getState) => {
|
(dispatch, getState) => {
|
||||||
if (shouldFetchUserData(getState(), id)) return dispatch(fetchUserData(id))
|
if (shouldFetchMembreData(getState(), id)) return dispatch(fetchMembreData(id))
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
@ -2,27 +2,25 @@ 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 { User, getUserList } from "../services/jsonPlaceholder"
|
import { Membre, getMembreList } from "../services/membres"
|
||||||
import { AppThunk, AppState } from "."
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
const userAdapter = createEntityAdapter<User>({
|
const membreAdapter = createEntityAdapter<Membre>()
|
||||||
selectId: (user) => user.membreId,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const initialState = userAdapter.getInitialState({
|
export const initialState = membreAdapter.getInitialState({
|
||||||
readyStatus: "idle",
|
readyStatus: "idle",
|
||||||
} as StateRequest)
|
} as StateRequest)
|
||||||
|
|
||||||
const userList = createSlice({
|
const membreList = createSlice({
|
||||||
name: "userList",
|
name: "membreList",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
getRequesting: (state) => {
|
getRequesting: (state) => {
|
||||||
state.readyStatus = "request"
|
state.readyStatus = "request"
|
||||||
},
|
},
|
||||||
getSuccess: (state, { payload }: PayloadAction<User[]>) => {
|
getSuccess: (state, { payload }: PayloadAction<Membre[]>) => {
|
||||||
state.readyStatus = "success"
|
state.readyStatus = "success"
|
||||||
userAdapter.setAll(state, payload)
|
membreAdapter.setAll(state, payload)
|
||||||
},
|
},
|
||||||
getFailure: (state, { payload }: PayloadAction<string>) => {
|
getFailure: (state, { payload }: PayloadAction<string>) => {
|
||||||
state.readyStatus = "failure"
|
state.readyStatus = "failure"
|
||||||
@ -31,13 +29,13 @@ const userList = createSlice({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default userList.reducer
|
export default membreList.reducer
|
||||||
export const { getRequesting, getSuccess, getFailure } = userList.actions
|
export const { getRequesting, getSuccess, getFailure } = membreList.actions
|
||||||
|
|
||||||
export const fetchUserList = (): AppThunk => async (dispatch) => {
|
export const fetchMembreList = (): AppThunk => async (dispatch) => {
|
||||||
dispatch(getRequesting())
|
dispatch(getRequesting())
|
||||||
|
|
||||||
const { error, data } = await getUserList()
|
const { error, data } = await getMembreList()
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
dispatch(getFailure(error.message))
|
dispatch(getFailure(error.message))
|
||||||
@ -51,14 +49,14 @@ export const fetchUserList = (): AppThunk => async (dispatch) => {
|
|||||||
progress: undefined,
|
progress: undefined,
|
||||||
})
|
})
|
||||||
} else {
|
} 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) => {
|
export const fetchMembreListIfNeed = (): AppThunk => (dispatch, getState) => {
|
||||||
if (shouldFetchUserList(getState())) return dispatch(fetchUserList())
|
if (shouldFetchMembreList(getState())) return dispatch(fetchMembreList())
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
@ -1,16 +1,16 @@
|
|||||||
import { History } from "history"
|
import { History } from "history"
|
||||||
import { connectRouter } from "connected-react-router"
|
import { connectRouter } from "connected-react-router"
|
||||||
|
|
||||||
import userList from "./userList"
|
import membreList from "./membreList"
|
||||||
import userData from "./userData"
|
import membre from "./membre"
|
||||||
import jeuJavList from "./jeuJavList"
|
import jeuJavList from "./jeuJavList"
|
||||||
import envieList from "./envieList"
|
import envieList from "./envieList"
|
||||||
|
|
||||||
// Use inferred return type for making correctly Redux types
|
// Use inferred return type for making correctly Redux types
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export default (history: History) => ({
|
export default (history: History) => ({
|
||||||
userList,
|
membreList,
|
||||||
userData,
|
membre,
|
||||||
jeuJavList,
|
jeuJavList,
|
||||||
envieList,
|
envieList,
|
||||||
router: connectRouter(history) as any,
|
router: connectRouter(history) as any,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user