mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-09 00:54:21 +02:00
Add teamList in store
This commit is contained in:
parent
1011a293d0
commit
d5eeb44d2f
63
src/pages/Teams/Teams.tsx
Normal file
63
src/pages/Teams/Teams.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { FC, 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, EntitiesRequest } from "../../store"
|
||||||
|
import { Team } from "../../services/teams"
|
||||||
|
import { fetchTeamListIfNeed } from "../../store/teamList"
|
||||||
|
import styles from "./styles.module.scss"
|
||||||
|
|
||||||
|
export type Props = RouteComponentProps
|
||||||
|
|
||||||
|
function useList(
|
||||||
|
stateToProp: (state: AppState) => EntitiesRequest<Team>,
|
||||||
|
fetchDataIfNeed: () => AppThunk
|
||||||
|
) {
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const { ids, entities, readyStatus } = useSelector(stateToProp, shallowEqual)
|
||||||
|
|
||||||
|
// Fetch client-side data here
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(fetchDataIfNeed())
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [dispatch])
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (!readyStatus || readyStatus === "idle" || readyStatus === "request")
|
||||||
|
return <p>Loading...</p>
|
||||||
|
|
||||||
|
if (readyStatus === "failure") return <p>Oops, Failed to load!</p>
|
||||||
|
|
||||||
|
return ids.map((id) => {
|
||||||
|
const team = entities[id]
|
||||||
|
return team === undefined ? null : (
|
||||||
|
<div key={id}>
|
||||||
|
<b>{team.name}</b>:{team.description}
|
||||||
|
<br />
|
||||||
|
Avant: {team.before}
|
||||||
|
<br />
|
||||||
|
Pendant: {team.during}
|
||||||
|
<br />
|
||||||
|
Après: {team.after}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TeamsPage: FC<Props> = (): JSX.Element => (
|
||||||
|
<div className={styles.teamsPage}>
|
||||||
|
<div className={styles.teamsContent}>
|
||||||
|
<Helmet title="TeamsPage" />
|
||||||
|
{useList((state: AppState) => state.teamList, fetchTeamListIfNeed)()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fetch server-side data here
|
||||||
|
export const loadData = (): AppThunk[] => [fetchTeamListIfNeed()]
|
||||||
|
|
||||||
|
export default memo(TeamsPage)
|
16
src/pages/Teams/index.tsx
Executable file
16
src/pages/Teams/index.tsx
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
import loadable from "@loadable/component"
|
||||||
|
|
||||||
|
import { Loading, ErrorBoundary } from "../../components"
|
||||||
|
import { Props, loadData } from "./Teams"
|
||||||
|
|
||||||
|
const Teams = loadable(() => import("./Teams"), {
|
||||||
|
fallback: <Loading />,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default (props: Props): JSX.Element => (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<Teams {...props} />
|
||||||
|
</ErrorBoundary>
|
||||||
|
)
|
||||||
|
|
||||||
|
export { loadData }
|
9
src/pages/Teams/styles.module.scss
Executable file
9
src/pages/Teams/styles.module.scss
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
@import "../../theme/mixins";
|
||||||
|
|
||||||
|
.teamsPage {
|
||||||
|
@include page-wrapper-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teamsContent {
|
||||||
|
@include page-content-wrapper(600px);
|
||||||
|
}
|
@ -3,6 +3,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 AsyncPreRegisterPage, { loadData as loadPreRegisterPage } from "../pages/PreRegister"
|
import AsyncPreRegisterPage, { loadData as loadPreRegisterPage } from "../pages/PreRegister"
|
||||||
|
import AsyncTeams, { loadData as loadTeamsData } from "../pages/Teams"
|
||||||
import AsyncWish, { loadData as loadWishData } from "../pages/Wish"
|
import AsyncWish, { loadData as loadWishData } from "../pages/Wish"
|
||||||
import AsyncVolunteerPage, { loadData as loadVolunteerPageData } from "../pages/VolunteerPage"
|
import AsyncVolunteerPage, { loadData as loadVolunteerPageData } from "../pages/VolunteerPage"
|
||||||
import Login from "../pages/Login"
|
import Login from "../pages/Login"
|
||||||
@ -37,6 +38,11 @@ export default [
|
|||||||
path: "/forgot",
|
path: "/forgot",
|
||||||
component: Forgot,
|
component: Forgot,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/teams",
|
||||||
|
component: AsyncTeams,
|
||||||
|
loadData: loadTeamsData,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/wish",
|
path: "/wish",
|
||||||
component: AsyncWish,
|
component: AsyncWish,
|
||||||
|
@ -21,10 +21,12 @@ export type ElementWithId<ElementNoId> = { id: number } & ElementNoId
|
|||||||
export class SheetNames {
|
export class SheetNames {
|
||||||
JavGames = "Jeux JAV"
|
JavGames = "Jeux JAV"
|
||||||
|
|
||||||
Volunteers = "Membres"
|
|
||||||
|
|
||||||
PreVolunteers = "PreMembres"
|
PreVolunteers = "PreMembres"
|
||||||
|
|
||||||
|
Teams = "Equipes"
|
||||||
|
|
||||||
|
Volunteers = "Membres"
|
||||||
|
|
||||||
Wishes = "Envies d'aider"
|
Wishes = "Envies d'aider"
|
||||||
}
|
}
|
||||||
export const sheetNames = new SheetNames()
|
export const sheetNames = new SheetNames()
|
||||||
|
10
src/server/gsheets/teams.ts
Normal file
10
src/server/gsheets/teams.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import ExpressAccessors from "./expressAccessors"
|
||||||
|
import { Team, TeamWithoutId, translationTeam } from "../../services/teams"
|
||||||
|
|
||||||
|
const expressAccessor = new ExpressAccessors<TeamWithoutId, Team>(
|
||||||
|
"Teams",
|
||||||
|
new Team(),
|
||||||
|
translationTeam
|
||||||
|
)
|
||||||
|
|
||||||
|
export const teamListGet = expressAccessor.listGet()
|
@ -18,14 +18,15 @@ import ssr from "./ssr"
|
|||||||
import certbotRouter from "../routes/certbot"
|
import certbotRouter from "../routes/certbot"
|
||||||
import { secure } from "./secure"
|
import { secure } from "./secure"
|
||||||
import { javGameListGet } from "./gsheets/javGames"
|
import { javGameListGet } from "./gsheets/javGames"
|
||||||
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
|
||||||
import { preVolunteerAdd, preVolunteerCountGet } from "./gsheets/preVolunteers"
|
import { preVolunteerAdd, preVolunteerCountGet } from "./gsheets/preVolunteers"
|
||||||
|
import { teamListGet } from "./gsheets/teams"
|
||||||
import {
|
import {
|
||||||
volunteerNotifsSet,
|
volunteerNotifsSet,
|
||||||
volunteerSet,
|
volunteerSet,
|
||||||
volunteerLogin,
|
volunteerLogin,
|
||||||
volunteerForgot,
|
volunteerForgot,
|
||||||
} from "./gsheets/volunteers"
|
} from "./gsheets/volunteers"
|
||||||
|
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
||||||
import config from "../config"
|
import config from "../config"
|
||||||
import notificationsSubscribe from "./notificationsSubscribe"
|
import notificationsSubscribe from "./notificationsSubscribe"
|
||||||
import checkAccess from "./checkAccess"
|
import checkAccess from "./checkAccess"
|
||||||
@ -71,6 +72,7 @@ app.post("/VolunteerForgot", volunteerForgot)
|
|||||||
|
|
||||||
// Secured APIs
|
// Secured APIs
|
||||||
app.post("/VolunteerSet", secure as RequestHandler, volunteerSet)
|
app.post("/VolunteerSet", secure as RequestHandler, volunteerSet)
|
||||||
|
app.get("/TeamListGet", teamListGet)
|
||||||
// UNSAFE app.post("/VolunteerGet", secure as RequestHandler, volunteerGet)
|
// UNSAFE app.post("/VolunteerGet", secure as RequestHandler, volunteerGet)
|
||||||
app.post("/VolunteerNotifsSet", secure as RequestHandler, volunteerNotifsSet)
|
app.post("/VolunteerNotifsSet", secure as RequestHandler, volunteerNotifsSet)
|
||||||
|
|
||||||
|
39
src/services/teams.ts
Normal file
39
src/services/teams.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import ServiceAccessors from "./accessors"
|
||||||
|
|
||||||
|
export class Team {
|
||||||
|
id = 0
|
||||||
|
|
||||||
|
name = ""
|
||||||
|
|
||||||
|
min = 0
|
||||||
|
|
||||||
|
max = 0
|
||||||
|
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
before = ""
|
||||||
|
|
||||||
|
during = ""
|
||||||
|
|
||||||
|
after = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
export const translationTeam: { [k in keyof Team]: string } = {
|
||||||
|
id: "id",
|
||||||
|
name: "nom",
|
||||||
|
min: "min",
|
||||||
|
max: "max",
|
||||||
|
description: "description",
|
||||||
|
before: "avant",
|
||||||
|
during: "pendant",
|
||||||
|
after: "après",
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementName = "Team"
|
||||||
|
|
||||||
|
export type TeamWithoutId = Omit<Team, "id">
|
||||||
|
|
||||||
|
const serviceAccessors = new ServiceAccessors<TeamWithoutId, Team>(elementName)
|
||||||
|
|
||||||
|
export const teamListGet = serviceAccessors.listGet()
|
||||||
|
export const teamGet = serviceAccessors.get()
|
@ -2,9 +2,10 @@ 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 wishAdd from "./wishAdd"
|
|
||||||
import wishList from "./wishList"
|
|
||||||
import javGameList from "./javGameList"
|
import javGameList from "./javGameList"
|
||||||
|
import preVolunteerAdd from "./preVolunteerAdd"
|
||||||
|
import preVolunteerCount from "./preVolunteerCount"
|
||||||
|
import teamList from "./teamList"
|
||||||
import volunteer from "./volunteer"
|
import volunteer from "./volunteer"
|
||||||
import volunteerAdd from "./volunteerAdd"
|
import volunteerAdd from "./volunteerAdd"
|
||||||
import volunteerList from "./volunteerList"
|
import volunteerList from "./volunteerList"
|
||||||
@ -12,16 +13,17 @@ import volunteerSet from "./volunteerSet"
|
|||||||
import volunteerLogin from "./volunteerLogin"
|
import volunteerLogin from "./volunteerLogin"
|
||||||
import volunteerForgot from "./volunteerForgot"
|
import volunteerForgot from "./volunteerForgot"
|
||||||
import volunteerNotifsSet from "./volunteerNotifsSet"
|
import volunteerNotifsSet from "./volunteerNotifsSet"
|
||||||
import preVolunteerAdd from "./preVolunteerAdd"
|
import wishAdd from "./wishAdd"
|
||||||
import preVolunteerCount from "./preVolunteerCount"
|
import wishList from "./wishList"
|
||||||
|
|
||||||
// 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) => ({
|
||||||
auth,
|
auth,
|
||||||
wishAdd,
|
|
||||||
wishList,
|
|
||||||
javGameList,
|
javGameList,
|
||||||
|
preVolunteerAdd,
|
||||||
|
preVolunteerCount,
|
||||||
|
teamList,
|
||||||
volunteer,
|
volunteer,
|
||||||
volunteerAdd,
|
volunteerAdd,
|
||||||
volunteerList,
|
volunteerList,
|
||||||
@ -29,8 +31,8 @@ export default (history: History) => ({
|
|||||||
volunteerLogin,
|
volunteerLogin,
|
||||||
volunteerForgot,
|
volunteerForgot,
|
||||||
volunteerNotifsSet,
|
volunteerNotifsSet,
|
||||||
preVolunteerAdd,
|
wishAdd,
|
||||||
preVolunteerCount,
|
wishList,
|
||||||
router: connectRouter(history) as any,
|
router: connectRouter(history) as any,
|
||||||
// Register more reducers...
|
// Register more reducers...
|
||||||
})
|
})
|
||||||
|
48
src/store/teamList.ts
Normal file
48
src/store/teamList.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { PayloadAction, createSlice, createEntityAdapter } from "@reduxjs/toolkit"
|
||||||
|
|
||||||
|
import { StateRequest, toastError, elementListFetch } from "./utils"
|
||||||
|
import { Team, teamListGet } from "../services/teams"
|
||||||
|
import { AppThunk, AppState } from "."
|
||||||
|
|
||||||
|
const teamAdapter = createEntityAdapter<Team>()
|
||||||
|
|
||||||
|
export const initialState = teamAdapter.getInitialState({
|
||||||
|
readyStatus: "idle",
|
||||||
|
} as StateRequest)
|
||||||
|
|
||||||
|
const teamList = createSlice({
|
||||||
|
name: "teamList",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
getRequesting: (state) => {
|
||||||
|
state.readyStatus = "request"
|
||||||
|
},
|
||||||
|
getSuccess: (state, { payload }: PayloadAction<Team[]>) => {
|
||||||
|
state.readyStatus = "success"
|
||||||
|
teamAdapter.setAll(state, payload)
|
||||||
|
},
|
||||||
|
getFailure: (state, { payload }: PayloadAction<string>) => {
|
||||||
|
state.readyStatus = "failure"
|
||||||
|
state.error = payload
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default teamList.reducer
|
||||||
|
export const { getRequesting, getSuccess, getFailure } = teamList.actions
|
||||||
|
|
||||||
|
export const fetchTeamList = elementListFetch(
|
||||||
|
teamListGet,
|
||||||
|
getRequesting,
|
||||||
|
getSuccess,
|
||||||
|
getFailure,
|
||||||
|
(error: Error) => toastError(`Erreur lors du chargement des équipes: ${error.message}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
const shouldFetchTeamList = (state: AppState) => state.teamList.readyStatus !== "success"
|
||||||
|
|
||||||
|
export const fetchTeamListIfNeed = (): AppThunk => (dispatch, getState) => {
|
||||||
|
if (shouldFetchTeamList(getState())) return dispatch(fetchTeamList())
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user