Start to create accommodations UI
This commit is contained in:
parent
9600acab0f
commit
f83cbe1386
@ -16,29 +16,31 @@ import { NewAccountRoute } from "./routes/auth/NewAccountRoute";
|
|||||||
import { OIDCCbRoute } from "./routes/auth/OIDCCbRoute";
|
import { OIDCCbRoute } from "./routes/auth/OIDCCbRoute";
|
||||||
import { PasswordForgottenRoute } from "./routes/auth/PasswordForgottenRoute";
|
import { PasswordForgottenRoute } from "./routes/auth/PasswordForgottenRoute";
|
||||||
import { ResetPasswordRoute } from "./routes/auth/ResetPasswordRoute";
|
import { ResetPasswordRoute } from "./routes/auth/ResetPasswordRoute";
|
||||||
import { FamilyHomeRoute } from "./routes/family/genealogy/FamilyHomeRoute";
|
|
||||||
import {
|
|
||||||
FamilyCreateMemberRoute,
|
|
||||||
FamilyEditMemberRoute,
|
|
||||||
FamilyMemberRoute,
|
|
||||||
} from "./routes/family/genealogy/FamilyMemberRoute";
|
|
||||||
import { FamilySettingsRoute } from "./routes/family/FamilySettingsRoute";
|
import { FamilySettingsRoute } from "./routes/family/FamilySettingsRoute";
|
||||||
import { FamilyUsersListRoute } from "./routes/family/FamilyUsersListRoute";
|
import { FamilyUsersListRoute } from "./routes/family/FamilyUsersListRoute";
|
||||||
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
|
import { AccommodationsSettingsRoute } from "./routes/family/accommodations/AccommodationsSettingsRoute";
|
||||||
import { BaseFamilyRoute } from "./widgets/BaseFamilyRoute";
|
|
||||||
import { BaseLoginPage } from "./widgets/BaseLoginpage";
|
|
||||||
import { FamilyMembersListRoute } from "./routes/family/genealogy/FamilyMembersListRoute";
|
|
||||||
import {
|
import {
|
||||||
FamilyCoupleRoute,
|
FamilyCoupleRoute,
|
||||||
FamilyCreateCoupleRoute,
|
FamilyCreateCoupleRoute,
|
||||||
FamilyEditCoupleRoute,
|
FamilyEditCoupleRoute,
|
||||||
} from "./routes/family/genealogy/FamilyCoupleRoute";
|
} from "./routes/family/genealogy/FamilyCoupleRoute";
|
||||||
import { FamilyCouplesListRoute } from "./routes/family/genealogy/FamilyCouplesListRoute";
|
import { FamilyCouplesListRoute } from "./routes/family/genealogy/FamilyCouplesListRoute";
|
||||||
import { FamilyTreeRoute } from "./routes/family/genealogy/FamilyTreeRoute";
|
import { FamilyHomeRoute } from "./routes/family/genealogy/FamilyHomeRoute";
|
||||||
|
import {
|
||||||
|
FamilyCreateMemberRoute,
|
||||||
|
FamilyEditMemberRoute,
|
||||||
|
FamilyMemberRoute,
|
||||||
|
} from "./routes/family/genealogy/FamilyMemberRoute";
|
||||||
import { FamilyMemberTreeRoute } from "./routes/family/genealogy/FamilyMemberTreeRoute";
|
import { FamilyMemberTreeRoute } from "./routes/family/genealogy/FamilyMemberTreeRoute";
|
||||||
import { GenealogyHomeRoute } from "./routes/family/genealogy/GenealogyHomeRoute";
|
import { FamilyMembersListRoute } from "./routes/family/genealogy/FamilyMembersListRoute";
|
||||||
import { BaseGenealogyRoute } from "./widgets/genealogy/BaseGenealogyRoute";
|
import { FamilyTreeRoute } from "./routes/family/genealogy/FamilyTreeRoute";
|
||||||
import { GenalogySettingsRoute } from "./routes/family/genealogy/GenalogySettingsRoute";
|
import { GenalogySettingsRoute } from "./routes/family/genealogy/GenalogySettingsRoute";
|
||||||
|
import { GenealogyHomeRoute } from "./routes/family/genealogy/GenealogyHomeRoute";
|
||||||
|
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
|
||||||
|
import { BaseFamilyRoute } from "./widgets/BaseFamilyRoute";
|
||||||
|
import { BaseLoginPage } from "./widgets/BaseLoginpage";
|
||||||
|
import { BaseAccommodationsRoute } from "./widgets/accommodations/BaseAccommodationsRoute";
|
||||||
|
import { BaseGenealogyRoute } from "./widgets/genealogy/BaseGenealogyRoute";
|
||||||
|
|
||||||
interface AuthContext {
|
interface AuthContext {
|
||||||
signedIn: boolean;
|
signedIn: boolean;
|
||||||
@ -110,6 +112,17 @@ export function App(): React.ReactElement {
|
|||||||
<Route path="*" element={<NotFoundRoute />} />
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
path="accommodations/*"
|
||||||
|
element={<BaseAccommodationsRoute />}
|
||||||
|
>
|
||||||
|
<Route
|
||||||
|
path="settings"
|
||||||
|
element={<AccommodationsSettingsRoute />}
|
||||||
|
/>
|
||||||
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
<Route path="settings" element={<FamilySettingsRoute />} />
|
<Route path="settings" element={<FamilySettingsRoute />} />
|
||||||
<Route path="users" element={<FamilyUsersListRoute />} />
|
<Route path="users" element={<FamilyUsersListRoute />} />
|
||||||
<Route path="*" element={<NotFoundRoute />} />
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
|
67
geneit_app/src/api/accommodations/AccommodationListApi.tsx
Normal file
67
geneit_app/src/api/accommodations/AccommodationListApi.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { APIClient } from "../ApiClient";
|
||||||
|
import { Family } from "../FamilyApi";
|
||||||
|
|
||||||
|
export interface Accommodation {
|
||||||
|
id: number;
|
||||||
|
family_id: number;
|
||||||
|
time_create: number;
|
||||||
|
time_update: number;
|
||||||
|
name: string;
|
||||||
|
need_validation: boolean;
|
||||||
|
description: string;
|
||||||
|
open_to_reservations: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AccommodationsList {
|
||||||
|
private list: Accommodation[];
|
||||||
|
private map: Map<number, Accommodation>;
|
||||||
|
|
||||||
|
constructor(list: Accommodation[]) {
|
||||||
|
this.list = list;
|
||||||
|
this.map = new Map();
|
||||||
|
|
||||||
|
for (const m of list) {
|
||||||
|
this.map.set(m.id, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.list.sort((a, b) =>
|
||||||
|
a.name.toLowerCase().localeCompare(b.name.toLocaleLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isEmpty(): boolean {
|
||||||
|
return this.list.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get size(): number {
|
||||||
|
return this.list.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get fullList(): Accommodation[] {
|
||||||
|
return this.list;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(predicate: (m: Accommodation) => boolean): Accommodation[] {
|
||||||
|
return this.list.filter(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(id: number): Accommodation | undefined {
|
||||||
|
return this.map.get(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AccommodationListApi {
|
||||||
|
/**
|
||||||
|
* Get the list of accommodation of a family
|
||||||
|
*/
|
||||||
|
static async GetListOfFamily(family: Family): Promise<AccommodationsList> {
|
||||||
|
const data = (
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "GET",
|
||||||
|
uri: `/family/${family.family_id}/accommodations/list/list`,
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
|
return new AccommodationsList(data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import { CardContent, Typography, Alert, Button } from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
import { useAlert } from "../../../hooks/context_providers/AlertDialogProvider";
|
||||||
|
import { useConfirm } from "../../../hooks/context_providers/ConfirmDialogProvider";
|
||||||
|
import { useLoadingMessage } from "../../../hooks/context_providers/LoadingMessageProvider";
|
||||||
|
import { useFamily } from "../../../widgets/BaseFamilyRoute";
|
||||||
|
import { FamilyCard } from "../../../widgets/FamilyCard";
|
||||||
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
|
||||||
|
export function AccommodationsSettingsRoute(): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AccommodationsListCard />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AccommodationsListCard(): React.ReactElement {
|
||||||
|
const loading = useLoadingMessage();
|
||||||
|
const confirm = useConfirm();
|
||||||
|
const alert = useAlert();
|
||||||
|
|
||||||
|
const family = useFamily();
|
||||||
|
|
||||||
|
const [error, setError] = React.useState<string>();
|
||||||
|
const [success, setSuccess] = React.useState<string>();
|
||||||
|
|
||||||
|
const createAccommodation = () => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FamilyCard error={error} success={success}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography gutterBottom variant="h5" component="div">
|
||||||
|
Logements
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="info"
|
||||||
|
fullWidth
|
||||||
|
onClick={createAccommodation}
|
||||||
|
disabled={!family.family.is_admin}
|
||||||
|
size={"large"}
|
||||||
|
>
|
||||||
|
Ajouter un nouveau logement
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</FamilyCard>
|
||||||
|
);
|
||||||
|
}
|
@ -5,6 +5,7 @@ import {
|
|||||||
mdiCrowd,
|
mdiCrowd,
|
||||||
mdiFamilyTree,
|
mdiFamilyTree,
|
||||||
mdiFileTree,
|
mdiFileTree,
|
||||||
|
mdiHomeGroup,
|
||||||
mdiHumanMaleFemale,
|
mdiHumanMaleFemale,
|
||||||
mdiLockCheck,
|
mdiLockCheck,
|
||||||
mdiPlus,
|
mdiPlus,
|
||||||
@ -207,6 +208,14 @@ export function BaseFamilyRoute(): React.ReactElement {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{family?.enable_accommodations && (
|
||||||
|
<FamilyLink
|
||||||
|
icon={<Icon path={mdiHomeGroup} size={1} />}
|
||||||
|
label="Logements"
|
||||||
|
uri="accommodations/settings"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Invitation code */}
|
{/* Invitation code */}
|
||||||
|
|
||||||
<ListItem
|
<ListItem
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Outlet } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
AccommodationListApi,
|
||||||
|
AccommodationsList,
|
||||||
|
} from "../../api/accommodations/AccommodationListApi";
|
||||||
|
import { AsyncWidget } from "../AsyncWidget";
|
||||||
|
import { useFamily } from "../BaseFamilyRoute";
|
||||||
|
|
||||||
|
interface AccommodationsContext {
|
||||||
|
accommodations: AccommodationsList;
|
||||||
|
reloadAccommodationsList: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccommodationsContextK =
|
||||||
|
React.createContext<AccommodationsContext | null>(null);
|
||||||
|
|
||||||
|
export function BaseAccommodationsRoute(): React.ReactElement {
|
||||||
|
const family = useFamily();
|
||||||
|
|
||||||
|
const [accommodations, setAccommodations] =
|
||||||
|
React.useState<null | AccommodationsList>(null);
|
||||||
|
|
||||||
|
const loadKey = React.useRef(1);
|
||||||
|
|
||||||
|
const loadPromise = React.useRef<() => void>();
|
||||||
|
|
||||||
|
const load = async () => {
|
||||||
|
setAccommodations(
|
||||||
|
await AccommodationListApi.GetListOfFamily(family.family)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReload = async () => {
|
||||||
|
loadKey.current += 1;
|
||||||
|
setAccommodations(null);
|
||||||
|
|
||||||
|
return new Promise<void>((res, _rej) => {
|
||||||
|
loadPromise.current = () => res();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AsyncWidget
|
||||||
|
ready={accommodations !== null}
|
||||||
|
loadKey={`${family.familyId}-${loadKey.current}`}
|
||||||
|
load={load}
|
||||||
|
errMsg="Échec du chargement des informations sur les logements de la famille !"
|
||||||
|
build={() => {
|
||||||
|
if (loadPromise.current != null) {
|
||||||
|
loadPromise.current?.();
|
||||||
|
loadPromise.current = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AccommodationsContextK.Provider
|
||||||
|
value={{
|
||||||
|
accommodations: accommodations!,
|
||||||
|
reloadAccommodationsList: onReload,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Outlet />
|
||||||
|
</AccommodationsContextK.Provider>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAccommodations(): AccommodationsContext {
|
||||||
|
return React.useContext(AccommodationsContextK)!;
|
||||||
|
}
|
@ -5,14 +5,14 @@ import { MemberApi, MembersList } from "../../api/genealogy/MemberApi";
|
|||||||
import { AsyncWidget } from "../AsyncWidget";
|
import { AsyncWidget } from "../AsyncWidget";
|
||||||
import { useFamily } from "../BaseFamilyRoute";
|
import { useFamily } from "../BaseFamilyRoute";
|
||||||
|
|
||||||
interface FamilyContext {
|
interface GenealogyContext {
|
||||||
members: MembersList;
|
members: MembersList;
|
||||||
couples: CouplesList;
|
couples: CouplesList;
|
||||||
reloadMembersList: () => Promise<void>;
|
reloadMembersList: () => Promise<void>;
|
||||||
reloadCouplesList: () => Promise<void>;
|
reloadCouplesList: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GenealogyContextK = React.createContext<FamilyContext | null>(null);
|
const GenealogyContextK = React.createContext<GenealogyContext | null>(null);
|
||||||
|
|
||||||
export function BaseGenealogyRoute(): React.ReactElement {
|
export function BaseGenealogyRoute(): React.ReactElement {
|
||||||
const family = useFamily();
|
const family = useFamily();
|
||||||
@ -68,6 +68,6 @@ export function BaseGenealogyRoute(): React.ReactElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useGenealogy(): FamilyContext {
|
export function useGenealogy(): GenealogyContext {
|
||||||
return React.useContext(GenealogyContextK)!;
|
return React.useContext(GenealogyContextK)!;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user