Rename JavGame to Game because all games are not from or at Jav

This commit is contained in:
pikiou 2022-03-11 13:29:04 +01:00
parent 57057780d8
commit ed8f20072f
17 changed files with 112 additions and 127 deletions

View File

@ -5,15 +5,15 @@ 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 JavGameList from "../index" import GameList from "../index"
describe("<List />", () => { describe("<List />", () => {
const renderHelper = (reducer = { readyStatus: "idle" }) => { const renderHelper = (reducer = { readyStatus: "idle" }) => {
const { dispatch, ProviderWithStore } = mockStore({ javGameList: reducer }) const { dispatch, ProviderWithStore } = mockStore({ gameList: reducer })
const { container } = render( const { container } = render(
<ProviderWithStore> <ProviderWithStore>
<MemoryRouter> <MemoryRouter>
<JavGameList ids={[5]} /> <GameList ids={[5]} />
</MemoryRouter> </MemoryRouter>
</ProviderWithStore> </ProviderWithStore>
) )
@ -39,9 +39,6 @@ describe("<List />", () => {
bggPhoto: bggPhoto:
"https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg", "https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
bggId: 432, bggId: 432,
copies: 1,
lendAvailability: 1,
notStored: 0,
ean: "3421272101313", ean: "3421272101313",
}, },
}, },

View File

@ -2,7 +2,7 @@
exports[`<List /> renders 1`] = ` exports[`<List /> renders 1`] = `
<div <div
class="JavGameList" class="GameList"
> >
<h4> <h4>
Jeux JAV Jeux JAV

View File

@ -10,14 +10,14 @@ interface Props {
ids: EntityId[] ids: EntityId[]
} }
const JavGameList = ({ ids }: Props) => { const GameList = ({ ids }: Props) => {
const { entities: jeuxJav } = useSelector((state: AppState) => state.javGameList, shallowEqual) const { entities: jeux } = useSelector((state: AppState) => state.gameList, shallowEqual)
return ( return (
<div className={styles.JavGameList}> <div className={styles.GameList}>
<h4>Jeux JAV</h4> <h4>Jeux JAV</h4>
<ul> <ul>
{ids.map((id) => { {ids.map((id) => {
const jeu = jeuxJav[id] const jeu = jeux[id]
if (!jeu) { if (!jeu) {
return <li key={id}>Le jeu #{id} n&apos;existe pas</li> return <li key={id}>Le jeu #{id} n&apos;existe pas</li>
} }
@ -33,4 +33,4 @@ const JavGameList = ({ ids }: Props) => {
) )
} }
export default memo(JavGameList) export default memo(GameList)

View File

@ -1,6 +1,6 @@
@import "../../theme/variables"; @import "../../theme/variables";
.JavGameList { .GameList {
color: $color-white; color: $color-white;
ul { ul {

View File

@ -1,6 +1,6 @@
import AnnouncementLink from "./AnnouncementLink" import AnnouncementLink from "./AnnouncementLink"
import ErrorBoundary from "./ErrorBoundary" import ErrorBoundary from "./ErrorBoundary"
import JavGameList from "./JavGameList" import GameList from "./GameList"
import Loading from "./Loading" import Loading from "./Loading"
import LoginForm from "./LoginForm" import LoginForm from "./LoginForm"
import Notifications, { fetchFor as fetchForNotifications } from "./Notifications" import Notifications, { fetchFor as fetchForNotifications } from "./Notifications"
@ -16,7 +16,7 @@ import WishAdd from "./WishAdd"
export { export {
AnnouncementLink, AnnouncementLink,
ErrorBoundary, ErrorBoundary,
JavGameList, GameList,
Loading, Loading,
LoginForm, LoginForm,
Notifications, Notifications,

View File

@ -4,9 +4,9 @@ import { useDispatch, useSelector, shallowEqual } from "react-redux"
import { Helmet } from "react-helmet" import { Helmet } from "react-helmet"
import { AppDispatch, AppState, AppThunk, EntitiesRequest } from "../../store" import { AppDispatch, AppState, AppThunk, EntitiesRequest } from "../../store"
import { fetchJavGameListIfNeed } from "../../store/javGameList" import { fetchGameListIfNeed } from "../../store/gameList"
import { fetchWishListIfNeed } from "../../store/wishList" import { fetchWishListIfNeed } from "../../store/wishList"
import { JavGameList, WishAdd } from "../../components" import { GameList, WishAdd } from "../../components"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
export type Props = RouteComponentProps export type Props = RouteComponentProps
@ -30,7 +30,7 @@ function useList<Entity>(
if (readyStatus === "failure") return <p>Oops, Failed to load list!</p> if (readyStatus === "failure") return <p>Oops, Failed to load list!</p>
return <JavGameList ids={ids} /> return <GameList ids={ids} />
} }
} }
@ -41,7 +41,7 @@ const Wish: FC<Props> = (): JSX.Element => {
<Helmet title="Wish" /> <Helmet title="Wish" />
<WishAdd dispatch={dispatch} /> <WishAdd dispatch={dispatch} />
{/* {useList((state: AppState) => state.wishList, fetchWishListifNeed)()} */} {/* {useList((state: AppState) => state.wishList, fetchWishListifNeed)()} */}
{useList((state: AppState) => state.javGameList, fetchJavGameListIfNeed)()} {useList((state: AppState) => state.gameList, fetchGameListIfNeed)()}
{/* <button type="button" onClick={() => setList([{id: 3, joueurs: 4, duree: 5, description: "abcd"}])}> {/* <button type="button" onClick={() => setList([{id: 3, joueurs: 4, duree: 5, description: "abcd"}])}>
Set list! Set list!
</button> */} </button> */}
@ -50,6 +50,6 @@ const Wish: FC<Props> = (): JSX.Element => {
} }
// Fetch server-side data here // Fetch server-side data here
export const loadData = (): AppThunk[] => [fetchWishListIfNeed(), fetchJavGameListIfNeed()] export const loadData = (): AppThunk[] => [fetchWishListIfNeed(), fetchGameListIfNeed()]
export default memo(Wish) export default memo(Wish)

View File

@ -0,0 +1,13 @@
import ExpressAccessors from "./expressAccessors"
import { Game, GameWithoutId, translationGame } from "../../services/games"
const expressAccessor = new ExpressAccessors<GameWithoutId, Game>(
"Games",
new Game(),
translationGame
)
export const gameListGet = expressAccessor.listGet()
export const gameGet = expressAccessor.get()
export const gameAdd = expressAccessor.add()
export const gameSet = expressAccessor.set()

View File

@ -1,13 +0,0 @@
import ExpressAccessors from "./expressAccessors"
import { JavGame, JavGameWithoutId, translationJavGame } from "../../services/javGames"
const expressAccessor = new ExpressAccessors<JavGameWithoutId, JavGame>(
"JavGames",
new JavGame(),
translationJavGame
)
export const javGameListGet = expressAccessor.listGet()
export const javGameGet = expressAccessor.get()
export const javGameAdd = expressAccessor.add()
export const javGameSet = expressAccessor.set()

View File

@ -12,7 +12,7 @@ const ANONYMIZED_DB_PATH = path.resolve(process.cwd(), "access/dbAnonymized.json
export class SheetNames { export class SheetNames {
Announcements = "Annonces" Announcements = "Annonces"
JavGames = "Jeux JAV" Games = "Jeux"
PreVolunteers = "PreMembres" PreVolunteers = "PreMembres"

View File

@ -18,7 +18,7 @@ import ssr from "./ssr"
import certbotRouter from "../routes/certbot" import certbotRouter from "../routes/certbot"
import { hasSecret, secure } from "./secure" import { hasSecret, secure } from "./secure"
import { announcementListGet } from "./gsheets/announcements" import { announcementListGet } from "./gsheets/announcements"
import { javGameListGet } from "./gsheets/javGames" import { gameListGet } from "./gsheets/games"
import { preVolunteerAdd, preVolunteerCountGet } from "./gsheets/preVolunteers" import { preVolunteerAdd, preVolunteerCountGet } from "./gsheets/preVolunteers"
import { teamListGet } from "./gsheets/teams" import { teamListGet } from "./gsheets/teams"
import { import {
@ -79,7 +79,7 @@ app.get(
* APIs * APIs
*/ */
// Google Sheets API // Google Sheets API
app.get("/JavGameListGet", javGameListGet) app.get("/GameListGet", gameListGet)
app.get("/WishListGet", wishListGet) app.get("/WishListGet", wishListGet)
app.post("/WishAdd", wishAdd) app.post("/WishAdd", wishAdd)
app.post("/PreVolunteerAdd", preVolunteerAdd) app.post("/PreVolunteerAdd", preVolunteerAdd)

View File

@ -1,4 +1,4 @@
export class JavGame { export class Game {
id = 0 id = 0
title = "" title = ""
@ -19,18 +19,12 @@ export class JavGame {
bggId = 0 bggId = 0
copies = 1
lendAvailability = 0
notStored = 0
ean = "" ean = ""
bggPhoto = "" bggPhoto = ""
} }
export const translationJavGame: { [k in keyof JavGame]: string } = { export const translationGame: { [k in keyof Game]: string } = {
id: "id", id: "id",
title: "titre", title: "titre",
author: "auteur", author: "auteur",
@ -41,13 +35,10 @@ export const translationJavGame: { [k in keyof JavGame]: string } = {
type: "type", type: "type",
poufpaf: "poufpaf", poufpaf: "poufpaf",
bggId: "bggId", bggId: "bggId",
copies: "exemplaires",
lendAvailability: "dispoPret",
notStored: "nonRangee",
ean: "ean", ean: "ean",
bggPhoto: "bggPhoto", bggPhoto: "bggPhoto",
} }
export const elementName = "JavGame" export const elementName = "Game"
export type JavGameWithoutId = Omit<JavGame, "id"> export type GameWithoutId = Omit<Game, "id">

View File

@ -0,0 +1,9 @@
import ServiceAccessors from "./accessors"
import { elementName, Game, GameWithoutId } from "./games"
const serviceAccessors = new ServiceAccessors<GameWithoutId, Game>(elementName)
export const gameListGet = serviceAccessors.listGet()
export const gameGet = serviceAccessors.get()
export const gameAdd = serviceAccessors.add()
export const gameSet = serviceAccessors.set()

View File

@ -1,9 +0,0 @@
import ServiceAccessors from "./accessors"
import { elementName, JavGame, JavGameWithoutId } from "./javGames"
const serviceAccessors = new ServiceAccessors<JavGameWithoutId, JavGame>(elementName)
export const javGameListGet = serviceAccessors.listGet()
export const javGameGet = serviceAccessors.get()
export const javGameAdd = serviceAccessors.add()
export const javGameSet = serviceAccessors.set()

View File

@ -2,18 +2,18 @@ import axios from "axios"
import _ from "lodash" import _ from "lodash"
import mockStore from "../../utils/mockStore" import mockStore from "../../utils/mockStore"
import JavGameList, { import GameList, {
initialState, initialState,
getRequesting, getRequesting,
getSuccess, getSuccess,
getFailure, getFailure,
fetchJavGameList, fetchGameList,
} from "../javGameList" } from "../gameList"
import { JavGame } from "../../services/javGames" import { Game } from "../../services/games"
jest.mock("axios") jest.mock("axios")
const mockData: JavGame[] = [ const mockData: Game[] = [
{ {
id: 5, id: 5,
title: "6 qui prend!", title: "6 qui prend!",
@ -27,22 +27,19 @@ const mockData: JavGame[] = [
bggPhoto: bggPhoto:
"https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg", "https://cf.geekdo-images.com/thumb/img/lzczxR5cw7an7tRWeHdOrRtLyes=/fit-in/200x150/pic772547.jpg",
bggId: 432, bggId: 432,
copies: 1,
lendAvailability: 1,
notStored: 0,
ean: "3421272101313", ean: "3421272101313",
}, },
] ]
const mockError = "Oops! Something went wrong." const mockError = "Oops! Something went wrong."
describe("JavGameList reducer", () => { describe("GameList reducer", () => {
it("should handle initial state", () => { it("should handle initial state", () => {
// @ts-expect-error // @ts-expect-error
expect(JavGameList(undefined, {})).toEqual(initialState) expect(GameList(undefined, {})).toEqual(initialState)
}) })
it("should handle requesting correctly", () => { it("should handle requesting correctly", () => {
expect(JavGameList(undefined, { type: getRequesting.type })).toEqual({ expect(GameList(undefined, { type: getRequesting.type })).toEqual({
readyStatus: "request", readyStatus: "request",
ids: [], ids: [],
entities: {}, entities: {},
@ -50,7 +47,7 @@ describe("JavGameList reducer", () => {
}) })
it("should handle success correctly", () => { it("should handle success correctly", () => {
expect(JavGameList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({ expect(GameList(undefined, { type: getSuccess.type, payload: mockData })).toEqual({
...initialState, ...initialState,
readyStatus: "success", readyStatus: "success",
ids: _.map(mockData, "id"), ids: _.map(mockData, "id"),
@ -59,7 +56,7 @@ describe("JavGameList reducer", () => {
}) })
it("should handle failure correctly", () => { it("should handle failure correctly", () => {
expect(JavGameList(undefined, { type: getFailure.type, payload: mockError })).toEqual({ expect(GameList(undefined, { type: getFailure.type, payload: mockError })).toEqual({
...initialState, ...initialState,
readyStatus: "failure", readyStatus: "failure",
error: mockError, error: mockError,
@ -67,8 +64,8 @@ describe("JavGameList reducer", () => {
}) })
}) })
describe("JavGameList action", () => { describe("GameList action", () => {
it("fetches JavGame list successful", async () => { it("fetches Game list successful", async () => {
const { dispatch, getActions } = mockStore() const { dispatch, getActions } = mockStore()
const expectedActions = [ const expectedActions = [
{ type: getRequesting.type, payload: undefined }, { type: getRequesting.type, payload: undefined },
@ -78,11 +75,11 @@ describe("JavGameList action", () => {
// @ts-expect-error // @ts-expect-error
axios.get.mockResolvedValue({ data: mockData }) axios.get.mockResolvedValue({ data: mockData })
await dispatch(fetchJavGameList()) await dispatch(fetchGameList())
expect(getActions()).toEqual(expectedActions) expect(getActions()).toEqual(expectedActions)
}) })
it("fetches JavGame list failed", async () => { it("fetches Game list failed", async () => {
const { dispatch, getActions } = mockStore() const { dispatch, getActions } = mockStore()
const expectedActions = [ const expectedActions = [
{ type: getRequesting.type }, { type: getRequesting.type },
@ -92,7 +89,7 @@ describe("JavGameList action", () => {
// @ts-expect-error // @ts-expect-error
axios.get.mockRejectedValue({ message: mockError }) axios.get.mockRejectedValue({ message: mockError })
await dispatch(fetchJavGameList()) await dispatch(fetchGameList())
expect(getActions()).toEqual(expectedActions) expect(getActions()).toEqual(expectedActions)
}) })
}) })

49
src/store/gameList.ts Normal file
View File

@ -0,0 +1,49 @@
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
import { StateRequest, toastError, elementListFetch } from "./utils"
import { Game } from "../services/games"
import { AppThunk, AppState } from "."
import { gameListGet } from "../services/gamesAccessors"
const gameAdapter = createEntityAdapter<Game>()
export const initialState = gameAdapter.getInitialState({
readyStatus: "idle",
} as StateRequest)
const gameList = createSlice({
name: "gameList",
initialState,
reducers: {
getRequesting: (state) => {
state.readyStatus = "request"
},
getSuccess: (state, { payload }: PayloadAction<Game[]>) => {
state.readyStatus = "success"
gameAdapter.setAll(state, payload)
},
getFailure: (state, { payload }: PayloadAction<string>) => {
state.readyStatus = "failure"
state.error = payload
},
},
})
export default gameList.reducer
export const { getRequesting, getSuccess, getFailure } = gameList.actions
export const fetchGameList = elementListFetch(
gameListGet,
getRequesting,
getSuccess,
getFailure,
(error: Error) => toastError(`Erreur lors du chargement des jeux JAV: ${error.message}`)
)
const shouldFetchGameList = (state: AppState) => state.gameList.readyStatus !== "success"
export const fetchGameListIfNeed = (): AppThunk => (dispatch, getState) => {
if (shouldFetchGameList(getState())) return dispatch(fetchGameList())
return null
}

View File

@ -1,49 +0,0 @@
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
import { StateRequest, toastError, elementListFetch } from "./utils"
import { JavGame } from "../services/javGames"
import { AppThunk, AppState } from "."
import { javGameListGet } from "../services/javGamesAccessors"
const javGameAdapter = createEntityAdapter<JavGame>()
export const initialState = javGameAdapter.getInitialState({
readyStatus: "idle",
} as StateRequest)
const javGameList = createSlice({
name: "javGameList",
initialState,
reducers: {
getRequesting: (state) => {
state.readyStatus = "request"
},
getSuccess: (state, { payload }: PayloadAction<JavGame[]>) => {
state.readyStatus = "success"
javGameAdapter.setAll(state, payload)
},
getFailure: (state, { payload }: PayloadAction<string>) => {
state.readyStatus = "failure"
state.error = payload
},
},
})
export default javGameList.reducer
export const { getRequesting, getSuccess, getFailure } = javGameList.actions
export const fetchJavGameList = elementListFetch(
javGameListGet,
getRequesting,
getSuccess,
getFailure,
(error: Error) => toastError(`Erreur lors du chargement des jeux JAV: ${error.message}`)
)
const shouldFetchJavGameList = (state: AppState) => state.javGameList.readyStatus !== "success"
export const fetchJavGameListIfNeed = (): AppThunk => (dispatch, getState) => {
if (shouldFetchJavGameList(getState())) return dispatch(fetchJavGameList())
return null
}

View File

@ -2,7 +2,7 @@ import { History } from "history"
import { connectRouter } from "connected-react-router" import { connectRouter } from "connected-react-router"
import auth from "./auth" import auth from "./auth"
import javGameList from "./javGameList" import gameList from "./gameList"
import announcementList from "./announcementList" import announcementList from "./announcementList"
import preVolunteerAdd from "./preVolunteerAdd" import preVolunteerAdd from "./preVolunteerAdd"
import preVolunteerCount from "./preVolunteerCount" import preVolunteerCount from "./preVolunteerCount"
@ -25,7 +25,7 @@ import wishList from "./wishList"
// 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) => ({
auth, auth,
javGameList, gameList,
announcementList, announcementList,
preVolunteerAdd, preVolunteerAdd,
preVolunteerCount, preVolunteerCount,