Create families list screen
This commit is contained in:
parent
947a3ad274
commit
09f1584d18
@ -1,6 +1,15 @@
|
|||||||
import { APIClient } from "./ApiClient";
|
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 {
|
export enum JoinFamilyResult {
|
||||||
TooManyRequests,
|
TooManyRequests,
|
||||||
@ -50,10 +59,29 @@ export class FamilyApi {
|
|||||||
/**
|
/**
|
||||||
* Get the list of families
|
* Get the list of families
|
||||||
*/
|
*/
|
||||||
static async GetList():Promise<Family[]> {
|
static async GetList(): Promise<Family[]> {
|
||||||
return (await APIClient.exec({
|
return (
|
||||||
method: "GET",
|
await APIClient.exec({
|
||||||
uri: "/family/list",
|
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`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,11 +1,23 @@
|
|||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import ConfirmationNumberIcon from "@mui/icons-material/ConfirmationNumber";
|
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 React from "react";
|
||||||
import { Family, FamilyApi } from "../api/FamilyApi";
|
import { Family, FamilyApi } from "../api/FamilyApi";
|
||||||
import { CreateFamilyDialog } from "../dialogs/CreateFamilyDialog";
|
import { CreateFamilyDialog } from "../dialogs/CreateFamilyDialog";
|
||||||
import { JoinFamilyDialog } from "../dialogs/JoinFamilyDialog";
|
import { JoinFamilyDialog } from "../dialogs/JoinFamilyDialog";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
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 {
|
export function FamiliesListRoute(): React.ReactElement {
|
||||||
const loadKey = React.useRef(1);
|
const loadKey = React.useRef(1);
|
||||||
@ -21,6 +33,7 @@ export function FamiliesListRoute(): React.ReactElement {
|
|||||||
|
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
loadKey.current += 1;
|
loadKey.current += 1;
|
||||||
|
setFamilies(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRequestCreateFamily = async () => {
|
const onRequestCreateFamily = async () => {
|
||||||
@ -45,9 +58,10 @@ export function FamiliesListRoute(): React.ReactElement {
|
|||||||
onRequestJoinFamily={onRequestJoinFamily}
|
onRequestJoinFamily={onRequestJoinFamily}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<HasFamilysWidget
|
<HasFamiliesWidget
|
||||||
onRequestCreateFamily={onRequestCreateFamily}
|
onRequestCreateFamily={onRequestCreateFamily}
|
||||||
onRequestJoinFamily={onRequestJoinFamily}
|
onRequestJoinFamily={onRequestJoinFamily}
|
||||||
|
onRequestRefresh={reload}
|
||||||
families={families!}
|
families={families!}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -125,14 +139,21 @@ function NoFamilyButton(p: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function HasFamilysWidget(p: {
|
function HasFamiliesWidget(p: {
|
||||||
families: Family[];
|
families: Family[];
|
||||||
onRequestCreateFamily: () => void;
|
onRequestCreateFamily: () => void;
|
||||||
onRequestJoinFamily: () => void;
|
onRequestJoinFamily: () => void;
|
||||||
|
onRequestRefresh: () => void;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<div style={{ width: "100%", maxWidth: "800px", margin: "20px auto" }}>
|
<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>
|
<Typography variant="h4">Mes familles</Typography>
|
||||||
<div>
|
<div>
|
||||||
<IconButton aria-label="create" onClick={p.onRequestCreateFamily}>
|
<IconButton aria-label="create" onClick={p.onRequestCreateFamily}>
|
||||||
@ -147,7 +168,86 @@ function HasFamilysWidget(p: {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
TODO list of families
|
|
||||||
|
{/* Display user memberships */}
|
||||||
|
{p.families.map((f) => (
|
||||||
|
<FamilyCard key={f.family_id} f={f} onFamilyLeft={p.onRequestRefresh} />
|
||||||
|
))}
|
||||||
</div>
|
</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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -36,21 +36,6 @@ export function AsyncWidget(p: {
|
|||||||
load();
|
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)
|
if (state === State.Error)
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -74,6 +59,21 @@ export function AsyncWidget(p: {
|
|||||||
<Button onClick={load}>Réessayer</Button>
|
<Button onClick={load}>Réessayer</Button>
|
||||||
</div>
|
</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();
|
return p.build();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user