2023-07-08 12:45:36 +02:00
|
|
|
import {
|
|
|
|
mdiAccountMultiple,
|
|
|
|
mdiCog,
|
2023-07-08 16:31:47 +02:00
|
|
|
mdiContentCopy,
|
2023-07-08 12:45:36 +02:00
|
|
|
mdiCrowd,
|
|
|
|
mdiFamilyTree,
|
|
|
|
mdiHumanMaleFemale,
|
2023-07-08 16:02:18 +02:00
|
|
|
mdiLockCheck,
|
2023-08-17 12:50:16 +02:00
|
|
|
mdiPlus,
|
2023-08-10 12:10:09 +02:00
|
|
|
mdiRefresh,
|
2023-07-08 12:45:36 +02:00
|
|
|
} from "@mdi/js";
|
|
|
|
import Icon from "@mdi/react";
|
|
|
|
import HomeIcon from "@mui/icons-material/Home";
|
|
|
|
import {
|
|
|
|
Box,
|
|
|
|
Divider,
|
2023-07-08 16:31:47 +02:00
|
|
|
IconButton,
|
2023-07-08 12:45:36 +02:00
|
|
|
List,
|
2023-07-08 16:31:47 +02:00
|
|
|
ListItem,
|
2023-07-08 12:45:36 +02:00
|
|
|
ListItemButton,
|
|
|
|
ListItemIcon,
|
2023-08-17 12:50:16 +02:00
|
|
|
ListItemSecondaryAction,
|
2023-07-08 12:45:36 +02:00
|
|
|
ListItemText,
|
|
|
|
ListSubheader,
|
2023-07-08 16:02:18 +02:00
|
|
|
Tooltip,
|
2023-07-08 12:45:36 +02:00
|
|
|
} from "@mui/material";
|
2023-07-08 11:59:55 +02:00
|
|
|
import React from "react";
|
2023-07-08 12:45:36 +02:00
|
|
|
import { Outlet, useLocation, useParams } from "react-router-dom";
|
|
|
|
import { Family, FamilyApi } from "../api/FamilyApi";
|
2023-08-10 12:10:09 +02:00
|
|
|
import { MemberApi, MembersList } from "../api/MemberApi";
|
|
|
|
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
|
|
|
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
|
|
|
|
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
2023-07-08 11:59:55 +02:00
|
|
|
import { AsyncWidget } from "./AsyncWidget";
|
2023-07-08 12:45:36 +02:00
|
|
|
import { RouterLink } from "./RouterLink";
|
2023-08-16 14:29:22 +02:00
|
|
|
import { CoupleApi, CouplesList } from "../api/CoupleApi";
|
2023-07-08 11:59:55 +02:00
|
|
|
|
|
|
|
interface FamilyContext {
|
|
|
|
family: Family;
|
2023-08-09 08:55:37 +02:00
|
|
|
members: MembersList;
|
2023-08-16 14:29:22 +02:00
|
|
|
couples: CouplesList;
|
2023-08-08 15:21:05 +02:00
|
|
|
familyId: number;
|
2023-07-08 11:59:55 +02:00
|
|
|
reloadFamilyInfo: () => void;
|
2023-08-09 08:55:37 +02:00
|
|
|
reloadMembersList: () => Promise<void>;
|
2023-08-16 12:17:04 +02:00
|
|
|
reloadCouplesList: () => Promise<void>;
|
2023-07-08 11:59:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const FamilyContextK = React.createContext<FamilyContext | null>(null);
|
|
|
|
|
|
|
|
export function BaseFamilyRoute(): React.ReactElement {
|
|
|
|
const { familyId } = useParams();
|
2023-07-08 16:02:18 +02:00
|
|
|
const snackbar = useSnackbar();
|
2023-07-08 16:31:47 +02:00
|
|
|
const alert = useAlert();
|
|
|
|
const confirm = useConfirm();
|
2023-07-08 11:59:55 +02:00
|
|
|
|
|
|
|
const [family, setFamily] = React.useState<null | Family>(null);
|
2023-08-09 08:55:37 +02:00
|
|
|
const [members, setMembers] = React.useState<null | MembersList>(null);
|
2023-08-16 14:29:22 +02:00
|
|
|
const [couples, setCouples] = React.useState<null | CouplesList>(null);
|
2023-07-08 11:59:55 +02:00
|
|
|
|
|
|
|
const loadKey = React.useRef(1);
|
|
|
|
|
2023-08-09 08:55:37 +02:00
|
|
|
const loadPromise = React.useRef<() => void>();
|
|
|
|
|
2023-07-08 11:59:55 +02:00
|
|
|
const load = async () => {
|
2023-08-09 08:55:37 +02:00
|
|
|
const familyID = Number(familyId);
|
|
|
|
setFamily(await FamilyApi.GetSingle(familyID));
|
|
|
|
setMembers(await MemberApi.GetEntireList(familyID));
|
2023-08-16 14:29:22 +02:00
|
|
|
setCouples(await CoupleApi.GetEntireList(familyID));
|
2023-07-08 11:59:55 +02:00
|
|
|
};
|
|
|
|
|
2023-08-09 08:55:37 +02:00
|
|
|
const onReload = async () => {
|
2023-07-08 11:59:55 +02:00
|
|
|
loadKey.current += 1;
|
|
|
|
setFamily(null);
|
2023-08-09 08:55:37 +02:00
|
|
|
setMembers(null);
|
2023-08-16 14:29:22 +02:00
|
|
|
setCouples(null);
|
2023-08-09 08:55:37 +02:00
|
|
|
|
|
|
|
return new Promise<void>((res, _rej) => {
|
|
|
|
loadPromise.current = () => res();
|
|
|
|
});
|
2023-07-08 11:59:55 +02:00
|
|
|
};
|
|
|
|
|
2023-07-08 16:02:18 +02:00
|
|
|
const copyInvitationCode = async () => {
|
|
|
|
navigator.clipboard.writeText(family!.invitation_code);
|
|
|
|
snackbar("Le code d'invitation a été copié dans le presse papier !");
|
|
|
|
};
|
|
|
|
|
2023-07-08 16:31:47 +02:00
|
|
|
const changeInvitationCode = async () => {
|
|
|
|
try {
|
|
|
|
if (
|
2023-07-09 17:35:12 +02:00
|
|
|
!(await confirm(
|
2023-07-08 16:31:47 +02:00
|
|
|
"Voulez-vous vraiment générer un nouveau code d'invitation pour cette famille ? Cette action aura pour effet d'invalider l'ancien code !"
|
|
|
|
))
|
|
|
|
)
|
|
|
|
return;
|
|
|
|
|
|
|
|
await FamilyApi.RenewInvitationCode(family!.family_id);
|
|
|
|
|
|
|
|
snackbar("Le code d'invitation a été changé avec succès !");
|
|
|
|
|
|
|
|
onReload();
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
2023-07-09 17:35:12 +02:00
|
|
|
alert("Echec du renouvellement du code d'invitation !");
|
2023-07-08 16:31:47 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-07-08 11:59:55 +02:00
|
|
|
return (
|
|
|
|
<AsyncWidget
|
2023-08-09 08:55:37 +02:00
|
|
|
ready={family !== null && members !== null}
|
2023-07-08 16:31:47 +02:00
|
|
|
loadKey={`${familyId}-${loadKey.current}`}
|
2023-07-08 11:59:55 +02:00
|
|
|
load={load}
|
|
|
|
errMsg="Échec du chargement des informations de la famille !"
|
2023-08-09 08:55:37 +02:00
|
|
|
build={() => {
|
|
|
|
if (loadPromise.current != null) {
|
|
|
|
loadPromise.current?.();
|
|
|
|
loadPromise.current = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<FamilyContextK.Provider
|
|
|
|
value={{
|
|
|
|
family: family!,
|
|
|
|
members: members!,
|
2023-08-16 14:29:22 +02:00
|
|
|
couples: couples!,
|
2023-08-09 08:55:37 +02:00
|
|
|
familyId: family!.family_id,
|
|
|
|
reloadFamilyInfo: onReload,
|
|
|
|
reloadMembersList: onReload,
|
2023-08-16 12:17:04 +02:00
|
|
|
reloadCouplesList: onReload,
|
2023-07-08 16:02:18 +02:00
|
|
|
}}
|
|
|
|
>
|
2023-08-09 08:55:37 +02:00
|
|
|
<Box
|
2023-07-08 16:02:18 +02:00
|
|
|
sx={{
|
2023-08-09 08:55:37 +02:00
|
|
|
display: "flex",
|
|
|
|
flex: "2",
|
2023-07-08 16:02:18 +02:00
|
|
|
}}
|
|
|
|
>
|
2023-08-09 08:55:37 +02:00
|
|
|
<List
|
|
|
|
component="nav"
|
|
|
|
sx={{
|
|
|
|
minWidth: "280px",
|
|
|
|
backgroundColor: "background.paper",
|
|
|
|
}}
|
2023-07-08 16:31:47 +02:00
|
|
|
>
|
2023-08-09 08:55:37 +02:00
|
|
|
<FamilyLink icon={<HomeIcon />} label="Accueil" uri="" />
|
|
|
|
|
|
|
|
<FamilyLink
|
|
|
|
icon={<Icon path={mdiCrowd} size={1} />}
|
|
|
|
label="Membres"
|
|
|
|
uri="members"
|
2023-08-17 12:50:16 +02:00
|
|
|
secondaryAction={
|
|
|
|
<Tooltip title="Créer une nouvelle fiche de membre">
|
|
|
|
<RouterLink to={family!.URL("member/create")}>
|
|
|
|
<IconButton>
|
|
|
|
<Icon path={mdiPlus} size={0.75} />
|
|
|
|
</IconButton>
|
|
|
|
</RouterLink>
|
|
|
|
</Tooltip>
|
|
|
|
}
|
2023-07-08 16:31:47 +02:00
|
|
|
/>
|
2023-07-08 12:45:36 +02:00
|
|
|
|
2023-08-09 08:55:37 +02:00
|
|
|
<FamilyLink
|
|
|
|
icon={<Icon path={mdiHumanMaleFemale} size={1} />}
|
|
|
|
label="Couples"
|
|
|
|
uri="couples"
|
2023-08-17 12:50:16 +02:00
|
|
|
secondaryAction={
|
|
|
|
<Tooltip title="Créer une nouvelle fiche de couple">
|
|
|
|
<RouterLink to={family!.URL("couple/create")}>
|
|
|
|
<IconButton>
|
|
|
|
<Icon path={mdiPlus} size={0.75} />
|
|
|
|
</IconButton>
|
|
|
|
</RouterLink>
|
|
|
|
</Tooltip>
|
|
|
|
}
|
2023-08-09 08:55:37 +02:00
|
|
|
/>
|
|
|
|
|
|
|
|
<FamilyLink
|
|
|
|
icon={<Icon path={mdiFamilyTree} size={1} />}
|
|
|
|
label="Arbre"
|
|
|
|
uri="tree"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<Divider sx={{ my: 1 }} />
|
|
|
|
<ListSubheader component="div">Administration</ListSubheader>
|
|
|
|
|
|
|
|
<FamilyLink
|
|
|
|
icon={<Icon path={mdiAccountMultiple} size={1} />}
|
|
|
|
label="Utilisateurs"
|
|
|
|
uri="users"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<FamilyLink
|
|
|
|
icon={<Icon path={mdiCog} size={1} />}
|
|
|
|
label="Paramètres"
|
|
|
|
uri="settings"
|
|
|
|
/>
|
|
|
|
|
|
|
|
{/* Invitation code */}
|
|
|
|
|
|
|
|
<ListItem
|
|
|
|
dense
|
|
|
|
secondaryAction={
|
|
|
|
<span>
|
|
|
|
<Tooltip title="Copier le code d'invitation dans le presse papier">
|
|
|
|
<IconButton onClick={copyInvitationCode}>
|
|
|
|
<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>
|
|
|
|
</Tooltip>
|
|
|
|
)}
|
|
|
|
</span>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<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>
|
2023-07-08 12:45:36 +02:00
|
|
|
</Box>
|
2023-08-09 08:55:37 +02:00
|
|
|
</FamilyContextK.Provider>
|
|
|
|
);
|
|
|
|
}}
|
2023-07-08 11:59:55 +02:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function useFamily(): FamilyContext {
|
|
|
|
return React.useContext(FamilyContextK)!;
|
|
|
|
}
|
2023-07-08 12:45:36 +02:00
|
|
|
|
|
|
|
function FamilyLink(p: {
|
|
|
|
icon: React.ReactElement;
|
|
|
|
uri: string;
|
|
|
|
label: string;
|
2023-08-17 12:50:16 +02:00
|
|
|
secondaryAction?: React.ReactElement;
|
2023-07-08 12:45:36 +02:00
|
|
|
}): React.ReactElement {
|
|
|
|
const family = useFamily();
|
|
|
|
const location = useLocation();
|
|
|
|
const link = family.family.URL(p.uri);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<RouterLink to={link}>
|
|
|
|
<ListItemButton selected={link === location.pathname}>
|
|
|
|
<ListItemIcon>{p.icon}</ListItemIcon>
|
|
|
|
<ListItemText primary={p.label} />
|
2023-08-17 12:50:16 +02:00
|
|
|
{p.secondaryAction && (
|
|
|
|
<ListItemSecondaryAction>{p.secondaryAction}</ListItemSecondaryAction>
|
|
|
|
)}
|
2023-07-08 12:45:36 +02:00
|
|
|
</ListItemButton>
|
|
|
|
</RouterLink>
|
|
|
|
);
|
|
|
|
}
|