Update InputDialog and made Project and App name editable

This commit is contained in:
biersoeckli
2024-12-12 11:19:32 +00:00
parent 78783b288d
commit 457291923c
23 changed files with 251 additions and 130 deletions

View File

@@ -12,6 +12,7 @@ import { AppSidebar } from "./sidebar";
import { cookies } from "next/headers";
import { BreadcrumbsGenerator } from "../components/custom/breadcrumbs-generator";
import { getUserSession } from "@/server/utils/action-wrapper.utils";
import { InputDialog } from "@/components/custom/input-dialog";
const inter = Inter({
subsets: ["latin"],
@@ -56,6 +57,7 @@ export default async function RootLayout({
<Toaster />
<ConfirmDialog />
<InputDialog />
</body>
</html>
);

View File

@@ -9,11 +9,12 @@ const createAppSchema = z.object({
appName: z.string().min(1)
});
export const createApp = async (appName: string, projectId: string) =>
export const createApp = async (appName: string, projectId: string, appId?: string) =>
saveFormAction({ appName }, createAppSchema, async (validatedData) => {
await getAuthUserSession();
const returnData = await appService.save({
id: appId ?? undefined,
name: validatedData.appName,
projectId
});

View File

@@ -21,13 +21,13 @@ export default function DomainsList({ app }: {
app: AppExtendedModel
}) {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const asyncDeleteDomain = async (domainId: string) => {
const confirm = await openDialog({
title: "Delete Domain",
description: "The domain will be removed and the changes will take effect, after you deploy the app. Are you sure you want to remove this domain?",
yesButton: "Delete Domain"
okButton: "Delete Domain"
});
if (confirm) {
await Toast.fromAction(() => deleteDomain(domainId));

View File

@@ -30,13 +30,13 @@ export default function InternalHostnames({ app }: {
app: AppExtendedModel
}) {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const asyncDeleteDomain = async (portId: string) => {
const confirm = await openDialog({
title: "Delete Port",
description: "The port will be removed and the changes will take effect, after you deploy the app. Are you sure you want to remove this port?",
yesButton: "Delete Port"
okButton: "Delete Port"
});
if (confirm) {
await Toast.fromAction(() => deletePort(portId));

View File

@@ -19,7 +19,7 @@ export default function BuildsTab({
app: AppExtendedModel;
}) {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const [appBuilds, setAppBuilds] = useState<DeploymentInfoModel[] | undefined>(undefined);
const [error, setError] = useState<string | undefined>(undefined);
const [selectedDeploymentForLogs, setSelectedDeploymentForLogs] = useState<DeploymentInfoModel | undefined>(undefined);
@@ -44,7 +44,7 @@ export default function BuildsTab({
const confirm = await openDialog({
title: "Delete Build",
description: "The build will be stopped and removed. Are you sure you want to stop this build?",
yesButton: "Stop & Remove Build"
okButton: "Stop & Remove Build"
});
if (confirm) {
await Toast.fromAction(() => deleteBuild(buildName));

View File

@@ -43,13 +43,13 @@ export default function StorageList({ app }: {
loadAndMapStorageData();
}, [app.appVolumes]);
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const asyncDeleteVolume = async (volumeId: string) => {
const confirm = await openDialog({
title: "Delete Volume",
description: "The volume will be removed and the Data will be lost. The changes will take effect, after you deploy the app. Are you sure you want to remove this volume?",
yesButton: "Delete Volume"
okButton: "Delete Volume"
});
if (confirm) {
await Toast.fromAction(() => deleteVolume(volumeId));
@@ -60,7 +60,7 @@ export default function StorageList({ app }: {
const confirm = await openDialog({
title: "Download Volume Data",
description: "The volume data will be zipped and downloaded. Depending on the size of the volume this can take a while. Are you sure you want to download the volume data?",
yesButton: "Download"
okButton: "Download"
});
if (confirm) {
await Toast.fromAction(() => downloadPvcData(volumeId)).then(x => {

View File

@@ -6,18 +6,19 @@ import Link from "next/link";
import { SimpleDataTable } from "@/components/custom/simple-data-table";
import { formatDateTime } from "@/frontend/utils/format.utils";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { MoreHorizontal } from "lucide-react";
import { Edit2, Eye, MoreHorizontal, Trash } from "lucide-react";
import { Toast } from "@/frontend/utils/toast.utils";
import { App, Project } from "@prisma/client";
import { deleteApp } from "./actions";
import { useBreadcrumbs, useConfirmDialog } from "@/frontend/states/zustand.states";
import { useEffect } from "react";
import { EditAppDialog } from "./edit-app-dialog";
export default function AppTable({ app }: { app: App[] }) {
export default function AppTable({ app, projectId }: { app: App[], projectId: string }) {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
return <>
<SimpleDataTable columns={[
@@ -49,15 +50,21 @@ export default function AppTable({ app }: { app: App[] }) {
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<Link href={`/project/app/${item.id}`}>
<DropdownMenuItem>
<span>Show App Details</span>
<Eye /> <span>Show App Details</span>
</DropdownMenuItem>
</Link>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => openDialog({
title: "Delete App",
description: "Are you sure you want to delete this app? All data will be lost and this action cannot be undone.",
}).then((result) => result ? Toast.fromAction(() => deleteApp(item.id)) : undefined)}>
<span className="text-red-500">Delete App</span>
<EditAppDialog projectId={projectId} existingItem={item}>
<DropdownMenuItem>
<Edit2 /> <span>Edit App Name</span>
</DropdownMenuItem>
</EditAppDialog>
<DropdownMenuItem className="text-red-500"
onClick={() => openDialog({
title: "Delete App",
description: "Are you sure you want to delete this app? All data will be lost and this action cannot be undone.",
}).then((result) => result ? Toast.fromAction(() => deleteApp(item.id)) : undefined)}>
<Trash /> <span >Delete App</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

View File

@@ -1,39 +0,0 @@
'use client'
import { InputDialog } from "@/components/custom/input-dialog"
import { Button } from "@/components/ui/button"
import { Toast } from "@/frontend/utils/toast.utils";
import { createApp } from "./actions";
import { redirect } from "next/navigation";
import { useRouter } from "next/navigation";
import { Plus } from "lucide-react";
export function CreateAppDialog({
projectId
}: {
projectId: string;
}) {
const router = useRouter();
const createAppFunc = async (name: string | undefined) => {
if (!name) {
return true;
}
const result = await Toast.fromAction(() => createApp(name, projectId));
if (result.status === "success") {
router.push(`/project/app/${result.data.id}`);
return true;
}
return false;
};
return <InputDialog
title="Create App"
description="Name your new App."
fieldName="Name"
onResult={createAppFunc}>
<Button><Plus /> Create App</Button>
</InputDialog>
}

View File

@@ -0,0 +1,41 @@
'use client'
import { InputDialog } from "@/components/custom/input-dialog"
import { Button } from "@/components/ui/button"
import { Toast } from "@/frontend/utils/toast.utils";
import { createApp } from "./actions";
import { redirect } from "next/navigation";
import { useRouter } from "next/navigation";
import { Plus } from "lucide-react";
import { App } from "@prisma/client";
import { useInputDialog } from "@/frontend/states/zustand.states";
export function EditAppDialog({
children,
projectId,
existingItem
}: {
children?: React.ReactNode,
projectId: string;
existingItem?: App;
}) {
const router = useRouter();
const { openInputDialog } = useInputDialog();
const createAppFunc = async () => {
const name = await openInputDialog({
title: "Create App",
description: "Name your new App.",
fieldName: "Name",
inputValue: existingItem?.name ?? ''
})
if (!name) { return; }
const result = await Toast.fromAction(() => createApp(name, projectId, existingItem?.id));
if (result.status === "success" && !existingItem) {
router.push(`/project/app/${result.data.id}`);
}
};
return <div onClick={() => createAppFunc()}>{children}</div>
}

View File

@@ -6,7 +6,7 @@ import Link from "next/link";
import { getAuthUserSession, getUserSession } from "@/server/utils/action-wrapper.utils";
import projectService from "@/server/services/project.service";
import AppTable from "./apps-table";
import { CreateAppDialog } from "./create-app-dialog";
import { EditAppDialog } from "./edit-app-dialog";
import appService from "@/server/services/app.service";
import {
Breadcrumb,
@@ -18,6 +18,7 @@ import {
} from "@/components/ui/breadcrumb"
import PageTitle from "@/components/custom/page-title";
import ProjectBreadcrumbs from "./project-breadcrumbs";
import { Plus } from "lucide-react";
export default async function AppsPage({
@@ -38,9 +39,9 @@ export default async function AppsPage({
<PageTitle
title="Apps"
subtitle={`All Apps for Project "${project.name}"`}>
<CreateAppDialog projectId={projectId} />
<EditAppDialog projectId={projectId}><Button><Plus /> Create App</Button></EditAppDialog>
</PageTitle>
<AppTable app={data} />
<AppTable app={data} projectId={project.id} />
<ProjectBreadcrumbs project={project} />
</div>
)

View File

@@ -6,13 +6,15 @@ import { getAuthUserSession, saveFormAction, simpleAction } from "@/server/utils
import { z } from "zod";
const createProjectSchema = z.object({
projectName: z.string().min(1)
projectName: z.string().min(1),
projectId: z.string().optional()
});
export const createProject = async (projectName: string) =>
saveFormAction({ projectName }, createProjectSchema, async (validatedData) => {
export const createProject = async (projectName: string, projectId?: string) =>
saveFormAction({ projectName, projectId }, createProjectSchema, async (validatedData) => {
await getAuthUserSession();
await projectService.save({
id: validatedData.projectId ?? undefined,
name: validatedData.projectName
});
return new SuccessActionResult(undefined, "Project created successfully.");

View File

@@ -1,27 +0,0 @@
'use client'
import { InputDialog } from "@/components/custom/input-dialog"
import { Button } from "@/components/ui/button"
import { Toast } from "@/frontend/utils/toast.utils";
import { createProject } from "./actions";
export function CreateProjectDialog({ children }: { children?: React.ReactNode }) {
const createProj = async (name: string | undefined) => {
if (!name) {
return true;
}
const result = await Toast.fromAction(() => createProject(name));
return result.status === "success";
};
return <InputDialog
title="Create Project"
description="Name your new project."
fieldName="Name"
OKButton="Create Project"
onResult={createProj}>
{children}
</InputDialog>
}

View File

@@ -0,0 +1,27 @@
'use client'
import { InputDialog } from "@/components/custom/input-dialog"
import { Button } from "@/components/ui/button"
import { Toast } from "@/frontend/utils/toast.utils";
import { createProject } from "./actions";
import { useInputDialog } from "@/frontend/states/zustand.states";
import { Project } from "@prisma/client";
export function EditProjectDialog({ children, existingItem }: { children?: React.ReactNode, existingItem?: Project }) {
const { openInputDialog } = useInputDialog();
const createProj = async () => {
const name = await openInputDialog({
title: "Create Project",
description: "Name your new project.",
fieldName: "Name",
okButton: "Create Project",
inputValue: existingItem?.name ?? ''
})
if (!name) { return; }
await Toast.fromAction(() => createProject(name, existingItem?.id));
};
return <div onClick={() => createProj()}>{children}</div>
}

View File

@@ -6,7 +6,7 @@ import Link from "next/link";
import { getAuthUserSession, getUserSession } from "@/server/utils/action-wrapper.utils";
import projectService from "@/server/services/project.service";
import ProjectsTable from "./projects-table";
import { CreateProjectDialog } from "./create-project-dialog";
import { EditProjectDialog } from "./edit-project-dialog";
import {
Breadcrumb,
BreadcrumbItem,
@@ -28,9 +28,9 @@ export default async function ProjectPage() {
<div className="flex-1 space-y-4 pt-6">
<div className="flex gap-4">
<h2 className="text-3xl font-bold tracking-tight flex-1">Projects</h2>
<CreateProjectDialog>
<EditProjectDialog>
<Button><Plus /> Create Project</Button>
</CreateProjectDialog>
</EditProjectDialog>
</div>
<ProjectsTable data={data} />
<ProjectsBreadcrumbs />

View File

@@ -6,24 +6,25 @@ import Link from "next/link";
import { SimpleDataTable } from "@/components/custom/simple-data-table";
import { formatDateTime } from "@/frontend/utils/format.utils";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { MoreHorizontal } from "lucide-react";
import { Edit2, Eye, MoreHorizontal, Trash } from "lucide-react";
import { Toast } from "@/frontend/utils/toast.utils";
import { Project } from "@prisma/client";
import { deleteProject } from "./actions";
import { useBreadcrumbs, useConfirmDialog } from "@/frontend/states/zustand.states";
import { useEffect } from "react";
import { EditProjectDialog } from "./edit-project-dialog";
export default function ProjectsTable({ data }: { data: Project[] }) {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const asyncDeleteProject = async (domainId: string) => {
const confirm = await openDialog({
title: "Delete Project",
description: "Are you sure you want to delete this project? All data (apps, deployments, volumes, domains) will be lost and this action cannot be undone. Running apps will be stopped and removed.",
yesButton: "Delete Project"
okButton: "Delete Project"
});
if (confirm) {
await Toast.fromAction(() => deleteProject(domainId));
@@ -54,12 +55,17 @@ export default function ProjectsTable({ data }: { data: Project[] }) {
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<Link href={`/project?projectId=${item.id}`}>
<DropdownMenuItem>
<span>Show Apps of Project</span>
<Eye /> <span>Show Apps of Project</span>
</DropdownMenuItem>
</Link>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => asyncDeleteProject(item.id)}>
<span className="text-red-500">Delete Project</span>
<EditProjectDialog existingItem={item}>
<DropdownMenuItem>
<Edit2 /> <span>Edit Project Name</span>
</DropdownMenuItem>
</EditProjectDialog>
<DropdownMenuItem className="text-red-500" onClick={() => asyncDeleteProject(item.id)}>
<Trash /> <span >Delete Project</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

View File

@@ -12,7 +12,7 @@ import { useEffect } from "react";
export default async function NodeInfo({ nodeInfos }: { nodeInfos: NodeInfoModel[] }) {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const { setBreadcrumbs } = useBreadcrumbs();
useEffect(() => setBreadcrumbs([
@@ -24,8 +24,8 @@ export default async function NodeInfo({ nodeInfos }: { nodeInfos: NodeInfoModel
const confirmation = await openDialog({
title: 'Update Node Status',
description: `Do you really want to ${schedulable ? 'activate' : 'deactivate'} Node ${nodeName}? ${!schedulable ? 'This will stop all running containers on this node and moves the workload to the other nodes. Future workloads won\'t be scheduled on this node.' : ''}`,
yesButton: 'Yes',
noButton: 'cancel'
okButton: 'Yes',
cancelButton: 'cancel'
});
if (confirmation) {
Toast.fromAction(() => setNodeStatus(nodeName, schedulable));

View File

@@ -23,10 +23,10 @@ export default function QuickStackMaintenanceSettings({
</CardHeader>
<CardContent className="flex gap-4">
<Button variant="secondary" onClick={async () => {
if (await useConfirm.openDialog({
if (await useConfirm.openConfirmDialog({
title: 'Update QuickStack',
description: 'This action will restart the QuickStack service and installs the lastest version. It may take a few minutes to complete.',
yesButton: "Update QuickStack",
okButton: "Update QuickStack",
})) {
Toast.fromAction(() => updateQuickstack());
}

View File

@@ -20,7 +20,7 @@ import {
} from "@/components/ui/sidebar"
import { AppleIcon, BookOpen, Boxes, Calendar, ChartNoAxesCombined, ChevronDown, ChevronRight, ChevronUp, Dot, FolderClosed, Home, Inbox, Info, Plus, Radio, Search, Server, Settings, Settings2, User, User2 } from "lucide-react"
import Link from "next/link"
import { CreateProjectDialog } from "./projects/create-project-dialog"
import { EditProjectDialog } from "./projects/edit-project-dialog"
import projectService from "@/server/services/project.service"
import { getAuthUserSession, getUserSession } from "@/server/utils/action-wrapper.utils"
import { SidebarLogoutButton } from "./sidebar-logout-button"
@@ -123,11 +123,11 @@ export function SidebarCient({
<span>Projects</span>
</Link>
</SidebarMenuButton>
<SidebarMenuAction>
<CreateProjectDialog>
<EditProjectDialog>
<SidebarMenuAction>
<Plus />
</CreateProjectDialog>
</SidebarMenuAction>
</SidebarMenuAction>
</EditProjectDialog>
<SidebarMenu>
{projects.map((item) => (
<DropdownMenu key={item.id}>

View File

@@ -19,20 +19,20 @@ import {
} from "@/components/ui/sidebar"
import { AppleIcon, Calendar, ChartNoAxesCombined, ChevronDown, ChevronUp, FolderClosed, Home, Inbox, LogOut, Plus, Search, Server, Settings, Settings2, User, User2 } from "lucide-react"
import Link from "next/link"
import { CreateProjectDialog } from "./projects/create-project-dialog"
import { EditProjectDialog } from "./projects/edit-project-dialog"
import projectService from "@/server/services/project.service"
import { getAuthUserSession } from "@/server/utils/action-wrapper.utils"
import { useConfirmDialog } from "@/frontend/states/zustand.states";
export function SidebarLogoutButton() {
const { openDialog } = useConfirmDialog();
const { openConfirmDialog: openDialog } = useConfirmDialog();
const signOutAsync = async () => {
if (!await openDialog({
title: "Sign out",
description: "Are you sure you want to sign out?",
yesButton: "Sign out",
okButton: "Sign out",
})) {
return;
}

View File

@@ -19,7 +19,7 @@ import {
} from "@/components/ui/sidebar"
import { AppleIcon, Calendar, ChartNoAxesCombined, ChevronDown, ChevronUp, FolderClosed, Home, Inbox, Plus, Search, Server, Settings, Settings2, User, User2 } from "lucide-react"
import Link from "next/link"
import { CreateProjectDialog } from "../../app/projects/create-project-dialog"
import { EditProjectDialog } from "../../app/projects/edit-project-dialog"
import projectService from "@/server/services/project.service"
import { getAuthUserSession } from "@/server/utils/action-wrapper.utils"
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator } from "@/components/ui/breadcrumb";

View File

@@ -28,8 +28,8 @@ export function ConfirmDialog() {
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button onClick={() => closeDialog(true)}>{data.yesButton ?? 'OK'}</Button>
<Button variant="secondary" onClick={() => closeDialog(false)}>{data.noButton ?? 'Cancel'}</Button>
<Button onClick={() => closeDialog(true)}>{data.okButton ?? 'OK'}</Button>
<Button variant="secondary" onClick={() => closeDialog(false)}>{data.cancelButton ?? 'Cancel'}</Button>
</DialogFooter>
</DialogContent>
</Dialog>

View File

@@ -1,3 +1,5 @@
'use client'
import { Button } from "@/components/ui/button"
import {
Dialog,
@@ -6,13 +8,63 @@ import {
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import React from "react";
import LoadingSpinner from "../ui/loading-spinner";
import { set } from "date-fns";
import React, { useEffect } from "react";
import { Input } from "../ui/input";
import { Label } from "../ui/label";
import { useInputDialog } from "@/frontend/states/zustand.states";
export function InputDialog() {
const { isDialogOpen, data, closeDialog } = useInputDialog();
const [inputValue, setInputValue] = React.useState<string>(data?.inputValue ?? '');
useEffect(() => {
setInputValue(data?.inputValue ?? '');
}, [data]);
if (!data) {
return <></>;
}
return (
<Dialog open={isDialogOpen} onOpenChange={() => closeDialog()}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{data.title}</DialogTitle>
{data.description && <DialogDescription>
{data.description}
</DialogDescription>}
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
{data.fieldName && <Label className="text-right">
{data.fieldName}
</Label>}
<Input
value={inputValue}
onKeyUp={(key) => {
if (key.key === 'Enter' && inputValue) {
closeDialog(inputValue);
}
}}
onChange={(e) => setInputValue(e.target.value)}
className="col-span-3"
/>
</div>
</div>
<DialogFooter>
<Button onClick={() => {
if (!inputValue) return;
closeDialog(inputValue)
}}>{data.okButton ?? 'OK'}</Button>
<Button variant="secondary" onClick={() => closeDialog(undefined)}>{data.cancelButton ?? 'Cancel'}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
/*
export function InputDialog({
children,
@@ -29,7 +81,6 @@ export function InputDialog({
fieldName: string;
OKButton?: string;
CancelButton?: string;
onResult: (result: string | undefined) => boolean | Promise<boolean>;
}) {
const [value, setValue] = React.useState<string>("");
@@ -37,6 +88,17 @@ export function InputDialog({
const [isLoading, setIsLoading] = React.useState(false);
const [errorMessages, setErrorMessages] = React.useState<string>("");
const { isDialogOpen, data, closeDialog } = useInputDialog();
const [inputValue, setInputValue] = React.useState<string>(data?.inputValue ?? '');
useEffect(() => {
setInputValue(data?.inputValue ?? '');
}, [data]);
if (!data) {
return <></>;
}
const submit = async () => {
try {
if (!value) {
@@ -98,3 +160,4 @@ export function InputDialog({
</Dialog>
)
}
*/

View File

@@ -1,30 +1,30 @@
import dataAccess from "@/server/adapter/db.client";
import { create } from "zustand"
interface ZustandDialogProps {
interface ZustandConfirmDialogProps {
isDialogOpen: boolean;
data: DialogProps | null;
resolvePromise: ((result: boolean) => void) | null;
openDialog: (data: DialogProps) => Promise<boolean>;
openConfirmDialog: (data: DialogProps) => Promise<boolean>;
closeDialog: (result: boolean) => void;
}
export interface DialogProps {
title: string;
description: string;
yesButton?: string;
noButton?: string;
okButton?: string;
cancelButton?: string;
}
export interface InternDialogProps extends DialogProps {
returnFunc: (dialogResult: boolean) => boolean;
}
export const useConfirmDialog = create<ZustandDialogProps>((set) => ({
export const useConfirmDialog = create<ZustandConfirmDialogProps>((set) => ({
isDialogOpen: false,
data: null,
resolvePromise: null,
openDialog: (data) => {
openConfirmDialog: (data) => {
return new Promise((resolve) => {
set({
isDialogOpen: true,
@@ -58,4 +58,41 @@ export const useBreadcrumbs = create<ZustandBreadcrumbsProps>((set) => ({
breadcrumbs: data,
});
},
}));
}));
/* Input Dialog */
interface ZustandInputDialogProps {
isDialogOpen: boolean;
data: InputDialogProps | null;
resolvePromise: ((result?: string) => void) | null;
openInputDialog: (data: InputDialogProps) => Promise<string | undefined>;
closeDialog: (result?: string) => void;
}
export interface InputDialogProps extends DialogProps {
inputValue?: string;
inputType?: 'text' | 'number';
placeholder?: string;
fieldName?: string;
}
export const useInputDialog = create<ZustandInputDialogProps>((set) => ({
isDialogOpen: false,
data: null,
resolvePromise: null,
openInputDialog: (data) => {
return new Promise<string | undefined>((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 };
}),
}));