Create families list screen

This commit is contained in:
Pierre HUBERT 2023-07-07 18:41:00 +02:00
parent 947a3ad274
commit 09f1584d18
3 changed files with 156 additions and 28 deletions

View File

@ -1,6 +1,15 @@
import { APIClient } from "./ApiClient";
export interface Family {}
export interface Family {
user_id: number;
family_id: number;
name: string;
time_create: number;
is_admin: boolean;
invitation_code: string;
count_members: number;
count_admins: number;
}
export enum JoinFamilyResult {
TooManyRequests,
@ -50,10 +59,29 @@ export class FamilyApi {
/**
* Get the list of families
*/
static async GetList():Promise<Family[]> {
return (await APIClient.exec({
static async GetList(): Promise<Family[]> {
return (
await APIClient.exec({
method: "GET",
uri: "/family/list",
})
).data;
}
})).data
}}
/**
* Check if the current user user can leave a family
*/
static CanLeaveFamily(f: Family): boolean {
return !f.is_admin || f.count_admins > 1;
}
/**
* Attempt to leave a family
*/
static async LeaveFamily(id: number): Promise<void> {
await APIClient.exec({
method: "POST",
uri: `/family/${id}/leave`,
});
}
}

View File

@ -1,11 +1,23 @@
import AddIcon from "@mui/icons-material/Add";
import ConfirmationNumberIcon from "@mui/icons-material/ConfirmationNumber";
import { Button, IconButton, Tooltip, Typography } from "@mui/material";
import {
Button,
Card,
CardActionArea,
CardActions,
CardContent,
IconButton,
Tooltip,
Typography,
} from "@mui/material";
import React from "react";
import { Family, FamilyApi } from "../api/FamilyApi";
import { CreateFamilyDialog } from "../dialogs/CreateFamilyDialog";
import { JoinFamilyDialog } from "../dialogs/JoinFamilyDialog";
import { AsyncWidget } from "../widgets/AsyncWidget";
import { TimeWidget } from "../widgets/TimeWidget";
import { useConfirm } from "../widgets/ConfirmDialogProvider";
import { useAlert } from "../widgets/AlertDialogProvider";
export function FamiliesListRoute(): React.ReactElement {
const loadKey = React.useRef(1);
@ -21,6 +33,7 @@ export function FamiliesListRoute(): React.ReactElement {
const reload = () => {
loadKey.current += 1;
setFamilies(null);
};
const onRequestCreateFamily = async () => {
@ -45,9 +58,10 @@ export function FamiliesListRoute(): React.ReactElement {
onRequestJoinFamily={onRequestJoinFamily}
/>
) : (
<HasFamilysWidget
<HasFamiliesWidget
onRequestCreateFamily={onRequestCreateFamily}
onRequestJoinFamily={onRequestJoinFamily}
onRequestRefresh={reload}
families={families!}
/>
)}
@ -125,14 +139,21 @@ function NoFamilyButton(p: {
);
}
function HasFamilysWidget(p: {
function HasFamiliesWidget(p: {
families: Family[];
onRequestCreateFamily: () => void;
onRequestJoinFamily: () => void;
onRequestRefresh: () => void;
}): React.ReactElement {
return (
<div style={{ width: "100%", maxWidth: "800px", margin: "20px auto" }}>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginBottom: "10px",
}}
>
<Typography variant="h4">Mes familles</Typography>
<div>
<IconButton aria-label="create" onClick={p.onRequestCreateFamily}>
@ -147,7 +168,86 @@ function HasFamilysWidget(p: {
</IconButton>
</div>
</div>
TODO list of families
{/* Display user memberships */}
{p.families.map((f) => (
<FamilyCard key={f.family_id} f={f} onFamilyLeft={p.onRequestRefresh} />
))}
</div>
);
}
function FamilyCard(p: {
f: Family;
onFamilyLeft: () => void;
}): React.ReactElement {
const canLeave = FamilyApi.CanLeaveFamily(p.f);
const confirm = useConfirm();
const alert = useAlert();
const leaveFamily = async () => {
try {
if (
!canLeave ||
!(await confirm.confirm(
"Voulez-vous vraiment quitter la famille " + p.f.name + " ?"
))
)
return;
await FamilyApi.LeaveFamily(p.f.family_id);
p.onFamilyLeft();
alert.alert(
`La famille ${p.f.name} a été retirée de votre liste de familles !`
);
} catch (e) {
console.error(e);
alert.alert("Echec du retrait de la famille !");
}
};
return (
<Card style={{ margin: "5px" }}>
<CardActionArea>
<CardContent>
<Typography gutterBottom variant="h5" component="div">
{p.f.name}
</Typography>
<Typography variant="body2" color="text.secondary">
{p.f.count_members === 1
? "1 membre"
: p.f.count_members + " membres"}{" "}
<br />
{p.f.count_admins === 1
? "1 administrateur"
: p.f.count_admins + " administrateurs"}
<br />
Famille créée il y a <TimeWidget time={p.f.time_create} />
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Tooltip
title={
canLeave
? "Quitter la famille"
: "Vous ne pouvez pas quitter cette famille, pour la retirer de cette liste vous devez la supprimer."
}
>
<span style={{ marginLeft: "auto" }}>
<Button
size="small"
color="primary"
disabled={!canLeave}
onClick={leaveFamily}
>
Quitter
</Button>
</span>
</Tooltip>
</CardActions>
</Card>
);
}

View File

@ -36,21 +36,6 @@ export function AsyncWidget(p: {
load();
});
if (state === State.Loading || p.ready === false)
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
flex: "1",
}}
>
<CircularProgress />
</div>
);
if (state === State.Error)
return (
<div
@ -74,6 +59,21 @@ export function AsyncWidget(p: {
<Button onClick={load}>Réessayer</Button>
</div>
);
console.log(p, counter.current);
if (state === State.Loading || p.ready === false)
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
flex: "1",
}}
>
<CircularProgress />
</div>
);
return p.build();
}