Create families list screen
This commit is contained in:
		@@ -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();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user