link-stack/packages/bridge-ui/components/Detail.tsx

192 lines
5.8 KiB
TypeScript
Raw Permalink Normal View History

2024-03-16 19:39:20 +01:00
"use client";
2024-04-25 12:31:03 +02:00
import { FC, useState } from "react";
2024-04-30 11:39:16 +02:00
import { Grid, Box } from "@mui/material";
2024-03-16 19:39:20 +01:00
import { useRouter } from "next/navigation";
2024-06-05 08:52:41 +02:00
import {
DisplayTextField,
Button,
Dialog,
colors,
typography,
} from "@link-stack/ui";
2024-04-30 11:39:16 +02:00
import { Selectable } from "kysely";
2024-06-05 08:52:41 +02:00
import { type Database } from "@link-stack/bridge-common";
import { QRCode } from "./QRCode";
2024-04-30 11:39:16 +02:00
import { generateDeleteAction } from "../lib/actions";
import { serviceConfig } from "../config/config";
import { FieldDescription } from "../lib/service";
2024-05-09 07:42:44 +02:00
import { getBasePath } from "../lib/frontendUtils";
2024-03-16 19:39:20 +01:00
2024-04-30 11:39:16 +02:00
type DetailProps = {
service: string;
row: Selectable<keyof Database>;
};
2024-03-16 19:39:20 +01:00
2024-04-30 11:39:16 +02:00
export const Detail: FC<DetailProps> = ({ service, row }) => {
const {
[service]: { entity, table, displayName, displayFields: fields },
} = serviceConfig;
const id = row.id as string;
2024-05-16 18:22:10 +02:00
const token = row.token as string;
2024-04-30 11:39:16 +02:00
const deleteAction = generateDeleteAction({ entity, table });
2024-03-16 19:39:20 +01:00
const router = useRouter();
2024-04-25 12:31:03 +02:00
const { almostBlack } = colors;
const { bodyLarge } = typography;
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
2025-11-09 11:12:04 +01:00
const [showRelinkConfirmation, setShowRelinkConfirmation] = useState(false);
const [isRelinking, setIsRelinking] = useState(false);
2024-04-25 12:31:03 +02:00
const continueDeleteAction = async () => {
await deleteAction?.(id);
setShowDeleteConfirmation(false);
2024-05-09 07:42:44 +02:00
router.push(`${getBasePath()}${entity}`);
2024-04-25 12:31:03 +02:00
};
2024-03-16 19:39:20 +01:00
2025-11-09 11:12:04 +01:00
const continueRelinkAction = async () => {
setIsRelinking(true);
try {
const response = await fetch(`/link/api/${entity}/bots/${token}/relink`, {
method: "POST",
});
if (response.ok) {
setShowRelinkConfirmation(false);
router.refresh();
}
} catch (error) {
console.error("Relink failed:", error);
} finally {
setIsRelinking(false);
}
};
2024-03-16 19:39:20 +01:00
return (
2024-04-25 12:31:03 +02:00
<>
<Dialog
open
2024-04-30 11:39:16 +02:00
title={`${displayName} Detail`}
2024-05-09 07:42:44 +02:00
onClose={() => router.push(`${getBasePath()}${entity}`)}
2024-04-25 12:31:03 +02:00
buttons={
<Grid container justifyContent="space-between">
<Grid item container xs="auto" spacing={2}>
2024-04-30 11:39:16 +02:00
<Grid item>
<Button
text="Delete"
kind="destructive"
onClick={() => setShowDeleteConfirmation(true)}
/>
</Grid>
2025-11-09 11:12:04 +01:00
{service === "whatsapp" && (
<Grid item>
<Button
text="Relink"
kind="secondary"
onClick={() => setShowRelinkConfirmation(true)}
/>
</Grid>
)}
2024-04-25 12:31:03 +02:00
<Grid item>
<Button
text="Edit"
kind="secondary"
2024-05-09 07:42:44 +02:00
href={`${getBasePath()}${entity}/${id}/edit`}
2024-04-25 12:31:03 +02:00
/>
</Grid>
</Grid>
2024-04-24 21:44:05 +02:00
<Grid item>
2024-05-09 07:42:44 +02:00
<Button
text="Done"
kind="primary"
href={`${getBasePath()}${entity}`}
/>
2024-04-24 21:44:05 +02:00
</Grid>
2024-04-25 12:31:03 +02:00
</Grid>
}
>
2024-04-30 11:39:16 +02:00
<Grid container direction="row" rowSpacing={3} columnSpacing={2}>
{fields.map((field: FieldDescription) => (
<Grid item xs={field.size ?? 6} key={field.name}>
{field.kind === "qrcode" && (
<QRCode
name={field.name}
label={field.label}
2024-06-05 15:12:48 +02:00
getValue={field.getQRCode}
2024-05-16 18:22:10 +02:00
refreshInterval={field.refreshInterval}
token={token}
verified={row.verified as boolean}
helperText={field.helperText}
/>
)}
{(!field.kind || field.kind === "text") && (
<DisplayTextField
name={field.name}
label={field.label}
lines={field.lines ?? 1}
value={row[field.name] as string}
copyable={field.copyable ?? false}
/>
)}
2024-04-30 11:39:16 +02:00
</Grid>
))}
</Grid>
2024-04-25 12:31:03 +02:00
</Dialog>
<Dialog
open={showDeleteConfirmation}
size="xs"
title="Really delete?"
buttons={
<Grid container justifyContent="space-between">
2024-04-24 21:44:05 +02:00
<Grid item>
<Button
2024-04-25 12:31:03 +02:00
text="Cancel"
2024-04-24 21:44:05 +02:00
kind="secondary"
2024-04-25 12:31:03 +02:00
onClick={() => setShowDeleteConfirmation(false)}
/>
</Grid>
<Grid item>
<Button
text="Delete"
kind="destructive"
onClick={continueDeleteAction}
2024-04-24 21:44:05 +02:00
/>
</Grid>
</Grid>
2024-04-25 12:31:03 +02:00
}
>
<Box sx={{ ...bodyLarge, color: almostBlack }}>
Are you sure you want to delete this record?
</Box>
</Dialog>
2025-11-09 11:12:04 +01:00
<Dialog
open={showRelinkConfirmation}
size="xs"
title="Relink WhatsApp Connection?"
buttons={
<Grid container justifyContent="space-between">
<Grid item>
<Button
text="Cancel"
kind="secondary"
onClick={() => setShowRelinkConfirmation(false)}
disabled={isRelinking}
/>
</Grid>
<Grid item>
<Button
text={isRelinking ? "Relinking..." : "Relink"}
kind="primary"
onClick={continueRelinkAction}
disabled={isRelinking}
/>
</Grid>
</Grid>
}
>
<Box sx={{ ...bodyLarge, color: almostBlack }}>
This will disconnect the current WhatsApp link and generate a new QR code. You will need to scan the new QR code to reconnect. Continue?
</Box>
</Dialog>
2024-04-25 12:31:03 +02:00
</>
2024-03-16 19:39:20 +01:00
);
};