mirror of
https://github.com/biersoeckli/QuickStack.git
synced 2026-01-02 01:30:38 -06:00
added async confirm dialog
This commit is contained in:
@@ -59,7 +59,8 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"typedi": "^0.10.0",
|
||||
"vaul": "^1.1.0",
|
||||
"zod": "^3.23.8"
|
||||
"zod": "^3.23.8",
|
||||
"zustand": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.7.9",
|
||||
|
||||
@@ -6,6 +6,7 @@ import "./globals.css";
|
||||
import { NavBar } from "./nav-bar";
|
||||
import { Suspense } from "react";
|
||||
import FullLoadingSpinner from "@/components/ui/full-loading-spinnter";
|
||||
import { ConfirmDialog } from "@/components/custom/confirm-dialog";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
@@ -39,6 +40,7 @@ export default function RootLayout({
|
||||
</div>
|
||||
</main>
|
||||
<Toaster />
|
||||
<ConfirmDialog />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -8,13 +8,16 @@ import { formatDateTime } from "@/lib/format.utils";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { MoreHorizontal } from "lucide-react";
|
||||
import { Toast } from "@/lib/toast.utils";
|
||||
import { App, Project } from "@prisma/client";
|
||||
import { App } from "@prisma/client";
|
||||
import { deleteApp } from "./actions";
|
||||
import { useConfirmDialog } from "@/lib/zustand.states";
|
||||
|
||||
|
||||
|
||||
export default function AppTable({ data }: { data: App[] }) {
|
||||
|
||||
const { openDialog } = useConfirmDialog();
|
||||
|
||||
return <>
|
||||
<SimpleDataTable columns={[
|
||||
['id', 'ID', false],
|
||||
@@ -49,7 +52,10 @@ export default function AppTable({ data }: { data: App[] }) {
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => Toast.fromAction(() => deleteApp(item.id))}>
|
||||
<DropdownMenuItem onClick={() => openDialog({
|
||||
title: "Delete App",
|
||||
description: "Are you sure you want to delete this app?",
|
||||
}).then((result) => result ? Toast.fromAction(() => deleteApp(item.id)) : undefined)}>
|
||||
<span className="text-red-500">Delete App</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
||||
37
src/components/custom/confirm-dialog.tsx
Normal file
37
src/components/custom/confirm-dialog.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
'use client'
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog"
|
||||
import React from "react";
|
||||
import { useConfirmDialog } from "@/lib/zustand.states";
|
||||
|
||||
export function ConfirmDialog() {
|
||||
const { isDialogOpen, data, closeDialog } = useConfirmDialog();
|
||||
if (!data) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={isDialogOpen} onOpenChange={closeDialog}>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{data.title}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{data.description}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button onClick={() => closeDialog(true)}>{data.yesButton ?? 'OK'}</Button>
|
||||
<Button variant="secondary" onClick={() => closeDialog(false)}>{data.yesButton ?? 'Cancel'}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
57
src/lib/zustand.states.ts
Normal file
57
src/lib/zustand.states.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import dataAccess from "@/server/adapter/db.client";
|
||||
import { create } from "zustand"
|
||||
|
||||
interface ZustandDialogProps {
|
||||
isDialogOpen: boolean;
|
||||
data: DialogProps | null;
|
||||
resolvePromise: ((result: boolean) => void) | null;
|
||||
openDialog: (data: DialogProps) => Promise<boolean>;
|
||||
closeDialog: (result: boolean) => void;
|
||||
}
|
||||
|
||||
export interface DialogProps {
|
||||
title: string;
|
||||
description: string;
|
||||
yesButton?: string;
|
||||
noButton?: string;
|
||||
}
|
||||
|
||||
export interface InternDialogProps extends DialogProps {
|
||||
returnFunc: (dialogResult: boolean) => boolean;
|
||||
}
|
||||
|
||||
export const useConfirmDialog = create<ZustandDialogProps>((set) => ({
|
||||
isDialogOpen: false,
|
||||
data: null,
|
||||
resolvePromise: null,
|
||||
openDialog: (data) => {
|
||||
return new Promise((resolve) => {
|
||||
set({
|
||||
isDialogOpen: true,
|
||||
data: data,
|
||||
resolvePromise: resolve,
|
||||
});
|
||||
});
|
||||
},
|
||||
closeDialog: (result) => set((state) => {
|
||||
if (state.resolvePromise) {
|
||||
state.resolvePromise(result); // Erfülle das Promise mit true oder false
|
||||
}
|
||||
return { isDialogOpen: false, userInfo: null, resolvePromise: null };
|
||||
}),
|
||||
}));
|
||||
/*
|
||||
export async function confirmDialog(props: DialogProps): Promise<boolean> {
|
||||
|
||||
const { openDialog } = useConfirmDialog();
|
||||
return new Promise((resolve) => {
|
||||
const extendedPropd = {
|
||||
...props,
|
||||
returnFunc: (returnVal) => {
|
||||
resolve(returnVal);
|
||||
}
|
||||
} as InternDialogProps;
|
||||
openDialog(extendedPropd);
|
||||
});
|
||||
|
||||
}*/
|
||||
@@ -5,6 +5,7 @@ import { CompleteApp, RelatedAppModel } from "./index"
|
||||
export const AppVolumeModel = z.object({
|
||||
id: z.string(),
|
||||
containerMountPath: z.string(),
|
||||
size: z.number().int(),
|
||||
appId: z.string(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
|
||||
Reference in New Issue
Block a user