Add delete house

This commit is contained in:
2026-02-06 11:34:23 +07:00
parent 7b14b30320
commit 42435faa7f
11 changed files with 316 additions and 24 deletions

View File

@@ -5,7 +5,7 @@ import { formatters } from '@utils/formatters';
import { LOG_ACTION } from '@/types/enum';
import ActionBadge from './action-badge';
import ViewDetailAudit from './view-detail-dialog';
import ViewDetailAudit from './view-log-detail-dialog';
export const logColumns: ColumnDef<AuditWithUser>[] = [
{

View File

@@ -0,0 +1,155 @@
import { m } from '@/paraglide/messages';
import { deleteHouse } from '@/service/house.api';
import { housesQueries } from '@/service/queries';
import { ReturnError } from '@/types/common';
import useHasPermission from '@hooks/use-has-permission';
import usePreventAutoFocus from '@hooks/use-prevent-auto-focus';
import { ShieldWarningIcon, TrashIcon } from '@phosphor-icons/react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Button } from '@ui/button';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@ui/dialog';
import { Label } from '@ui/label';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@ui/table';
import { Tooltip, TooltipContent, TooltipTrigger } from '@ui/tooltip';
import parse from 'html-react-parser';
import { useState } from 'react';
import { toast } from 'sonner';
import RoleBadge from '../avatar/role-badge';
type DeleteHouseProps = {
data: OrganizationWithMembers;
};
const DeleteHouseAction = ({ data }: DeleteHouseProps) => {
const [_open, _setOpen] = useState(false);
const prevent = usePreventAutoFocus();
const { hasPermission, isLoading } = useHasPermission('house', 'delete');
const queryClient = useQueryClient();
const { mutate: deleteHouseMutation } = useMutation({
mutationFn: deleteHouse,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [...housesQueries.all, 'list'],
});
_setOpen(false);
toast.success(m.houses_page_message_delete_house_success(), {
richColors: true,
});
},
onError: (error: ReturnError) => {
console.error(error);
const code = error.code as Parameters<
typeof m.backend_message
>[0]['code'];
toast.error(m.backend_message({ code }), {
richColors: true,
});
},
});
const onConfirm = () => {
deleteHouseMutation({ data });
};
if (isLoading) return null;
if (hasPermission) {
return (
<Dialog open={_open} onOpenChange={_setOpen}>
<Tooltip>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
className="rounded-full cursor-pointer text-red-500 hover:bg-red-100 hover:text-red-600"
>
<TrashIcon size={16} />
<span className="sr-only">{m.ui_delete_btn()}</span>
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent className="bg-red-500 [&_svg]:bg-red-500 [&_svg]:fill-red-500 text-white">
<Label>{m.ui_delete_btn()}</Label>
</TooltipContent>
</Tooltip>
<DialogContent
className="max-w-100 xl:max-w-xl"
showCloseButton={false}
{...prevent}
onPointerDownOutside={(e) => e.preventDefault()}
onEscapeKeyDown={(e) => e.preventDefault()}
>
<DialogHeader>
<DialogTitle className="flex items-center gap-3 text-lg font-bold text-red-500">
<div className="rounded-full bg-red-100 p-3">
<ShieldWarningIcon size={30} />
</div>
{m.houses_page_ui_dialog_alert_delete_title({ name: data.name })}
</DialogTitle>
<DialogDescription className="text-red-500">
{parse(m.houses_page_ui_dialog_alert_delete_description())}
</DialogDescription>
</DialogHeader>
<div className="overflow-hidden rounded-md border">
<Table className="bg-white">
<TableHeader>
<TableRow>
<TableHead className="px-2 h-7 bg-primary text-white text-xs w-1/2">
{m.houses_page_ui_view_table_header_email()}
</TableHead>
<TableHead className="px-2 h-7 bg-primary text-white text-xs w-1/2">
{m.houses_page_ui_view_table_header_role()}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.members.map((member) => (
<TableRow key={member.user.email}>
<TableCell>{member.user.email}</TableCell>
<TableCell>
<RoleBadge type={member.role} />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<DialogFooter className="bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4">
<DialogClose asChild>
<Button variant="outline" type="button">
{m.ui_cancel_btn()}
</Button>
</DialogClose>
<Button variant="destructive" type="button" onClick={onConfirm}>
{m.ui_confirm_btn()}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
return null;
};
export default DeleteHouseAction;

View File

@@ -1,8 +1,9 @@
import { m } from '@paraglide/messages';
import { ColumnDef } from '@tanstack/react-table';
import { formatters } from '@utils/formatters';
import DeleteHouseAction from './delete-house-dialog';
import EditHouseAction from './edit-house-dialog';
import ViewDetailHouse from './view-detail-dialog';
import ViewDetailHouse from './view-house-detail-dialog';
export const houseColumns: ColumnDef<OrganizationWithMembers>[] = [
{
@@ -42,6 +43,7 @@ export const houseColumns: ColumnDef<OrganizationWithMembers>[] = [
<div className="flex justify-end gap-2">
<ViewDetailHouse data={row.original} />
<EditHouseAction data={row.original} />
<DeleteHouseAction data={row.original} />
</div>
);
},

View File

@@ -17,7 +17,14 @@ import {
} from '@ui/dialog';
import { UserWithRole } from 'better-auth/plugins';
import { toast } from 'sonner';
import DisplayBreakLineMessage from '../DisplayBreakLineMessage';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '../ui/table';
import { useBanContext } from './ban-user-dialog';
type BanConfirmProps = {
@@ -74,20 +81,49 @@ const BanUserConfirm = ({ data }: BanConfirmProps) => {
{m.users_page_ui_dialog_alert_ban_title()}
</DialogDescription>
</DialogHeader>
<DisplayBreakLineMessage>
{m.users_page_ui_dialog_alert_description({
name: data.name,
email: data.email,
})}
{m.users_page_ui_dialog_alert_description_2({
reason: submitData.banReason,
exp: m.exp_time({
time: submitData.banExp.toString() as Parameters<
typeof m.exp_time
>[0]['time'],
}),
})}
</DisplayBreakLineMessage>
<div className="overflow-hidden rounded-md border">
<Table className="bg-white">
<TableHeader>
<TableRow className="bg-primary">
<TableHead className="px-2 h-7 text-white text-xs" colSpan={2}>
{m.users_page_ui_dialog_alert_description_title()}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-bold">
{m.users_page_ui_table_header_name()}:
</TableCell>
<TableCell>{data.name}</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-bold">
{m.users_page_ui_table_header_email()}:
</TableCell>
<TableCell>{data.email}</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-bold">
{m.users_page_ui_form_ban_reason()}:
</TableCell>
<TableCell>{submitData.banReason}</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-bold">
{m.users_page_ui_form_ban_exp()}:
</TableCell>
<TableCell>
{m.exp_time({
time: submitData.banExp.toString() as Parameters<
typeof m.exp_time
>[0]['time'],
})}
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
<DialogFooter className="bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4">
<DialogClose asChild>
<Button variant="outline" type="button">