Make members information globally available
This commit is contained in:
parent
1128b5ebd4
commit
359dd2f9ee
@ -2,7 +2,7 @@ import { APIClient } from "./ApiClient";
|
|||||||
|
|
||||||
export type Sex = "M" | "F";
|
export type Sex = "M" | "F";
|
||||||
|
|
||||||
export interface MemberApi {
|
export interface MemberDataApi {
|
||||||
id: number;
|
id: number;
|
||||||
family_id: number;
|
family_id: number;
|
||||||
first_name?: string;
|
first_name?: string;
|
||||||
@ -31,7 +31,7 @@ export interface MemberApi {
|
|||||||
note?: string;
|
note?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Member implements MemberApi {
|
export class Member implements MemberDataApi {
|
||||||
id: number;
|
id: number;
|
||||||
family_id: number;
|
family_id: number;
|
||||||
first_name?: string;
|
first_name?: string;
|
||||||
@ -59,7 +59,7 @@ export class Member implements MemberApi {
|
|||||||
death_day?: number;
|
death_day?: number;
|
||||||
note?: string;
|
note?: string;
|
||||||
|
|
||||||
constructor(m: MemberApi) {
|
constructor(m: MemberDataApi) {
|
||||||
this.id = m.id;
|
this.id = m.id;
|
||||||
this.family_id = m.family_id;
|
this.family_id = m.family_id;
|
||||||
this.first_name = m.first_name;
|
this.first_name = m.first_name;
|
||||||
@ -108,6 +108,20 @@ export class Member implements MemberApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MembersList {
|
||||||
|
private list: Member[];
|
||||||
|
private map: Map<number, Member>;
|
||||||
|
|
||||||
|
constructor(list: Member[]) {
|
||||||
|
this.list = list;
|
||||||
|
this.map = new Map();
|
||||||
|
|
||||||
|
for (const m of list) {
|
||||||
|
this.map.set(m.id, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MemberApi {
|
export class MemberApi {
|
||||||
/**
|
/**
|
||||||
* Create a new member
|
* Create a new member
|
||||||
@ -137,6 +151,18 @@ export class MemberApi {
|
|||||||
return new Member(res.data);
|
return new Member(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the entire list of family members of a family
|
||||||
|
*/
|
||||||
|
static async GetEntireList(family_id: number): Promise<MembersList> {
|
||||||
|
const res = await APIClient.exec({
|
||||||
|
uri: `/family/${family_id}/members`,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
|
||||||
|
return new MembersList(res.data.map((d: any) => new Member(d)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a member information
|
* Update a member information
|
||||||
*/
|
*/
|
||||||
|
@ -33,7 +33,7 @@ export function FamilyCreateMemberRoute(): React.ReactElement {
|
|||||||
try {
|
try {
|
||||||
const r = await MemberApi.Create(m);
|
const r = await MemberApi.Create(m);
|
||||||
|
|
||||||
// TODO : trigger update
|
await family.reloadMembersList();
|
||||||
|
|
||||||
setShouldQuit(true);
|
setShouldQuit(true);
|
||||||
n(family.family.URL(`member/${r.id}`));
|
n(family.family.URL(`member/${r.id}`));
|
||||||
@ -92,7 +92,7 @@ export function FamilyMemberRoute(): React.ReactElement {
|
|||||||
snackbar("La fiche de membre a été supprimée avec succès !");
|
snackbar("La fiche de membre a été supprimée avec succès !");
|
||||||
n(family.family.URL("members"));
|
n(family.family.URL("members"));
|
||||||
|
|
||||||
// TODO : refresh cached members list
|
await family.reloadMembersList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
alert("Échec de la suppression du membre !");
|
alert("Échec de la suppression du membre !");
|
||||||
@ -148,7 +148,7 @@ export function FamilyEditMemberRoute(): React.ReactElement {
|
|||||||
|
|
||||||
snackbar("Les informations du membre ont été mises à jour avec succès !");
|
snackbar("Les informations du membre ont été mises à jour avec succès !");
|
||||||
|
|
||||||
// TODO : update family hook info
|
await family.reloadMembersList();
|
||||||
|
|
||||||
setShouldQuit(true);
|
setShouldQuit(true);
|
||||||
n(family.family.URL(`member/${member!.id}`));
|
n(family.family.URL(`member/${member!.id}`));
|
||||||
@ -193,7 +193,6 @@ export function MemberPage(p: {
|
|||||||
const [member, setMember] = React.useState(structuredClone(p.member));
|
const [member, setMember] = React.useState(structuredClone(p.member));
|
||||||
|
|
||||||
const updatedMember = () => {
|
const updatedMember = () => {
|
||||||
// TODO : add confirmation
|
|
||||||
setChanged(true);
|
setChanged(true);
|
||||||
setMember(structuredClone(member));
|
setMember(structuredClone(member));
|
||||||
};
|
};
|
||||||
|
@ -30,11 +30,14 @@ import { RouterLink } from "./RouterLink";
|
|||||||
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
||||||
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
|
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
|
||||||
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
||||||
|
import { Member, MemberApi, MembersList } from "../api/MemberApi";
|
||||||
|
|
||||||
interface FamilyContext {
|
interface FamilyContext {
|
||||||
family: Family;
|
family: Family;
|
||||||
|
members: MembersList;
|
||||||
familyId: number;
|
familyId: number;
|
||||||
reloadFamilyInfo: () => void;
|
reloadFamilyInfo: () => void;
|
||||||
|
reloadMembersList: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FamilyContextK = React.createContext<FamilyContext | null>(null);
|
const FamilyContextK = React.createContext<FamilyContext | null>(null);
|
||||||
@ -46,16 +49,26 @@ export function BaseFamilyRoute(): React.ReactElement {
|
|||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
const [family, setFamily] = React.useState<null | Family>(null);
|
const [family, setFamily] = React.useState<null | Family>(null);
|
||||||
|
const [members, setMembers] = React.useState<null | MembersList>(null);
|
||||||
|
|
||||||
const loadKey = React.useRef(1);
|
const loadKey = React.useRef(1);
|
||||||
|
|
||||||
|
const loadPromise = React.useRef<() => void>();
|
||||||
|
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
setFamily(await FamilyApi.GetSingle(Number(familyId)));
|
const familyID = Number(familyId);
|
||||||
|
setFamily(await FamilyApi.GetSingle(familyID));
|
||||||
|
setMembers(await MemberApi.GetEntireList(familyID));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onReload = () => {
|
const onReload = async () => {
|
||||||
loadKey.current += 1;
|
loadKey.current += 1;
|
||||||
setFamily(null);
|
setFamily(null);
|
||||||
|
setMembers(null);
|
||||||
|
|
||||||
|
return new Promise<void>((res, _rej) => {
|
||||||
|
loadPromise.current = () => res();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyInvitationCode = async () => {
|
const copyInvitationCode = async () => {
|
||||||
@ -85,113 +98,122 @@ export function BaseFamilyRoute(): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncWidget
|
<AsyncWidget
|
||||||
ready={family != null}
|
ready={family !== null && members !== null}
|
||||||
loadKey={`${familyId}-${loadKey.current}`}
|
loadKey={`${familyId}-${loadKey.current}`}
|
||||||
load={load}
|
load={load}
|
||||||
errMsg="Échec du chargement des informations de la famille !"
|
errMsg="Échec du chargement des informations de la famille !"
|
||||||
build={() => (
|
build={() => {
|
||||||
<FamilyContextK.Provider
|
if (loadPromise.current != null) {
|
||||||
value={{
|
loadPromise.current?.();
|
||||||
family: family!,
|
loadPromise.current = undefined;
|
||||||
familyId: family!.family_id,
|
}
|
||||||
reloadFamilyInfo: onReload,
|
|
||||||
}}
|
return (
|
||||||
>
|
<FamilyContextK.Provider
|
||||||
<Box
|
value={{
|
||||||
sx={{
|
family: family!,
|
||||||
display: "flex",
|
members: members!,
|
||||||
flex: "2",
|
familyId: family!.family_id,
|
||||||
|
reloadFamilyInfo: onReload,
|
||||||
|
reloadMembersList: onReload,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<List
|
<Box
|
||||||
component="nav"
|
|
||||||
sx={{
|
sx={{
|
||||||
minWidth: "280px",
|
display: "flex",
|
||||||
backgroundColor: "background.paper",
|
flex: "2",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FamilyLink icon={<HomeIcon />} label="Accueil" uri="" />
|
<List
|
||||||
|
component="nav"
|
||||||
|
sx={{
|
||||||
|
minWidth: "280px",
|
||||||
|
backgroundColor: "background.paper",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FamilyLink icon={<HomeIcon />} label="Accueil" uri="" />
|
||||||
|
|
||||||
<FamilyLink
|
<FamilyLink
|
||||||
icon={<Icon path={mdiCrowd} size={1} />}
|
icon={<Icon path={mdiCrowd} size={1} />}
|
||||||
label="Membres"
|
label="Membres"
|
||||||
uri="members"
|
uri="members"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FamilyLink
|
<FamilyLink
|
||||||
icon={<Icon path={mdiHumanMaleFemale} size={1} />}
|
icon={<Icon path={mdiHumanMaleFemale} size={1} />}
|
||||||
label="Couples"
|
label="Couples"
|
||||||
uri="couples"
|
uri="couples"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FamilyLink
|
<FamilyLink
|
||||||
icon={<Icon path={mdiFamilyTree} size={1} />}
|
icon={<Icon path={mdiFamilyTree} size={1} />}
|
||||||
label="Arbre"
|
label="Arbre"
|
||||||
uri="tree"
|
uri="tree"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Divider sx={{ my: 1 }} />
|
<Divider sx={{ my: 1 }} />
|
||||||
<ListSubheader component="div">Administration</ListSubheader>
|
<ListSubheader component="div">Administration</ListSubheader>
|
||||||
|
|
||||||
<FamilyLink
|
<FamilyLink
|
||||||
icon={<Icon path={mdiAccountMultiple} size={1} />}
|
icon={<Icon path={mdiAccountMultiple} size={1} />}
|
||||||
label="Utilisateurs"
|
label="Utilisateurs"
|
||||||
uri="users"
|
uri="users"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FamilyLink
|
<FamilyLink
|
||||||
icon={<Icon path={mdiCog} size={1} />}
|
icon={<Icon path={mdiCog} size={1} />}
|
||||||
label="Paramètres"
|
label="Paramètres"
|
||||||
uri="settings"
|
uri="settings"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Invitation code */}
|
{/* Invitation code */}
|
||||||
|
|
||||||
<ListItem
|
<ListItem
|
||||||
dense
|
dense
|
||||||
secondaryAction={
|
secondaryAction={
|
||||||
<span>
|
<span>
|
||||||
<Tooltip title="Copier le code d'invitation dans le presse papier">
|
<Tooltip title="Copier le code d'invitation dans le presse papier">
|
||||||
<IconButton onClick={copyInvitationCode}>
|
<IconButton onClick={copyInvitationCode}>
|
||||||
<Icon path={mdiContentCopy} size={0.75} />
|
<Icon path={mdiContentCopy} size={0.75} />
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
{family!.is_admin && (
|
|
||||||
<Tooltip title="Changer le code d'activation">
|
|
||||||
<IconButton onClick={changeInvitationCode}>
|
|
||||||
<Icon path={mdiRefresh} size={0.75} />
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ListItemIcon>
|
|
||||||
<Icon path={mdiLockCheck} size={1} />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText
|
|
||||||
primary="Code d'invitation"
|
|
||||||
secondary={family?.invitation_code}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
|
|
||||||
<Box
|
{family!.is_admin && (
|
||||||
component="main"
|
<Tooltip title="Changer le code d'activation">
|
||||||
sx={{
|
<IconButton onClick={changeInvitationCode}>
|
||||||
flexGrow: 1,
|
<Icon path={mdiRefresh} size={0.75} />
|
||||||
overflow: "auto",
|
</IconButton>
|
||||||
padding: "20px",
|
</Tooltip>
|
||||||
display: "flex",
|
)}
|
||||||
flexDirection: "column",
|
</span>
|
||||||
}}
|
}
|
||||||
>
|
>
|
||||||
<Outlet />
|
<ListItemIcon>
|
||||||
|
<Icon path={mdiLockCheck} size={1} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="Code d'invitation"
|
||||||
|
secondary={family?.invitation_code}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
component="main"
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: "auto",
|
||||||
|
padding: "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Outlet />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</FamilyContextK.Provider>
|
||||||
</FamilyContextK.Provider>
|
);
|
||||||
)}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user