Refactor: Replace window.confirm with custom dialog component

This commit is contained in:
2025-05-28 09:57:46 +08:00
parent aa83f10657
commit 13295bd24d
3 changed files with 123 additions and 46 deletions

View File

@@ -46,6 +46,7 @@ import { Input } from "./ui/input";
import { SetAPIsTemplate } from "./setAPIsTemplate"; import { SetAPIsTemplate } from "./setAPIsTemplate";
import { isVailedJSON } from "@/utils/isVailedJSON"; import { isVailedJSON } from "@/utils/isVailedJSON";
import { toast } from 'sonner'; import { toast } from 'sonner';
import { ConfirmationDialog } from "./ui/confirmation-dialog";
interface APITemplateDropdownProps { interface APITemplateDropdownProps {
label: string; label: string;
@@ -151,6 +152,8 @@ function APIsDropdownList({
const { toast } = useToast(); const { toast } = useToast();
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [editingTemplate, setEditingTemplate] = useState<TemplateAPI | null>(null); const [editingTemplate, setEditingTemplate] = useState<TemplateAPI | null>(null);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [templateToDelete, setTemplateToDelete] = useState<TemplateAPI | null>(null);
let API = templateAPIs; let API = templateAPIs;
let setAPI = setTemplateAPIs; let setAPI = setTemplateAPIs;
@@ -186,8 +189,13 @@ function APIsDropdownList({
}; };
const handleDelete = (template: TemplateAPI) => { const handleDelete = (template: TemplateAPI) => {
if (window.confirm(`Are you sure you want to delete "${template.name}"?`)) { setTemplateToDelete(template);
const newAPI = API.filter(t => t.name !== template.name); setDeleteDialogOpen(true);
};
const confirmDelete = () => {
if (templateToDelete) {
const newAPI = API.filter(t => t.name !== templateToDelete.name);
setAPI(newAPI); setAPI(newAPI);
toast({ toast({
title: "Success", title: "Success",
@@ -271,6 +279,16 @@ function APIsDropdownList({
onClose={() => setEditingTemplate(null)} onClose={() => setEditingTemplate(null)}
/> />
)} )}
<ConfirmationDialog
isOpen={deleteDialogOpen}
onClose={() => {
setDeleteDialogOpen(false);
setTemplateToDelete(null);
}}
onConfirm={confirmDelete}
title="Delete Template"
description={`Are you sure you want to delete "${templateToDelete?.name}"?`}
/>
</div> </div>
); );
} }
@@ -460,6 +478,8 @@ function ChatTemplateDropdownList() {
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [editingTemplate, setEditingTemplate] = useState<TemplateChatStore | null>(null); const [editingTemplate, setEditingTemplate] = useState<TemplateChatStore | null>(null);
const { toast } = useToast(); const { toast } = useToast();
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
const [templateToApply, setTemplateToApply] = useState<TemplateChatStore | null>(null);
const handleEdit = (template: TemplateChatStore) => { const handleEdit = (template: TemplateChatStore) => {
setEditingTemplate(template); setEditingTemplate(template);
@@ -479,16 +499,32 @@ function ChatTemplateDropdownList() {
}; };
const handleDelete = (template: TemplateChatStore) => { const handleDelete = (template: TemplateChatStore) => {
if (window.confirm(`Are you sure you want to delete "${template.name}"?`)) { setTemplateToApply(template);
const newTemplates = templates.filter(t => t.name !== template.name); setConfirmDialogOpen(true);
setTemplates(newTemplates); };
toast({
title: "Success", const handleTemplateSelect = (template: TemplateChatStore) => {
description: "Template deleted successfully", if (chatStore.history.length > 0 || chatStore.systemMessageContent) {
}); setTemplateToApply(template);
setConfirmDialogOpen(true);
} else {
applyTemplate(template);
} }
}; };
const applyTemplate = (template: TemplateChatStore) => {
setChatStore({
...newChatStore({
...chatStore,
...{
use_this_history: template.history ?? chatStore.history,
},
...template,
}),
});
setOpen(false);
};
return ( return (
<div className="flex items-center space-x-4 mx-3"> <div className="flex items-center space-x-4 mx-3">
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
@@ -512,30 +548,7 @@ function ChatTemplateDropdownList() {
<CommandItem <CommandItem
key={index} key={index}
value={t.name} value={t.name}
onSelect={() => { onSelect={() => handleTemplateSelect(t)}
if (
chatStore.history.length > 0 ||
chatStore.systemMessageContent
) {
const confirm = window.confirm(
"This will replace the current chat history. Are you sure? "
);
if (!confirm) {
setOpen(false);
return;
}
}
setChatStore({
...newChatStore({
...chatStore,
...{
use_this_history: t.history ?? chatStore.history,
},
...t,
}),
});
setOpen(false);
}}
> >
<div className="flex items-center justify-between w-full"> <div className="flex items-center justify-between w-full">
<span>{t.name}</span> <span>{t.name}</span>
@@ -576,6 +589,16 @@ function ChatTemplateDropdownList() {
onClose={() => setEditingTemplate(null)} onClose={() => setEditingTemplate(null)}
/> />
)} )}
<ConfirmationDialog
isOpen={confirmDialogOpen}
onClose={() => {
setConfirmDialogOpen(false);
setTemplateToApply(null);
}}
onConfirm={() => templateToApply && applyTemplate(templateToApply)}
title="Replace Chat History"
description="This will replace the current chat history. Are you sure?"
/>
</div> </div>
); );
} }

View File

@@ -14,6 +14,7 @@ import {
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { AppChatStoreContext, AppContext } from "../pages/App"; import { AppChatStoreContext, AppContext } from "../pages/App";
import { ConfirmationDialog } from "./ui/confirmation-dialog";
interface EditMessageProps { interface EditMessageProps {
chat: ChatStoreMessage; chat: ChatStoreMessage;
@@ -22,9 +23,19 @@ interface EditMessageProps {
} }
export function EditMessage(props: EditMessageProps) { export function EditMessage(props: EditMessageProps) {
const { chatStore, setChatStore } = useContext(AppChatStoreContext); const { chatStore, setChatStore } = useContext(AppChatStoreContext);
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const { showEdit, setShowEdit, chat } = props; const { showEdit, setShowEdit, chat } = props;
const handleSwitchMessageType = () => {
if (typeof chat.content === "string") {
chat.content = [];
} else {
chat.content = "";
}
setChatStore({ ...chatStore });
};
return ( return (
<Dialog open={showEdit} onOpenChange={setShowEdit}> <Dialog open={showEdit} onOpenChange={setShowEdit}>
{/* <DialogTrigger> {/* <DialogTrigger>
@@ -46,19 +57,7 @@ export function EditMessage(props: EditMessageProps) {
<Button <Button
variant="destructive" variant="destructive"
className="w-full" className="w-full"
onClick={() => { onClick={() => setShowConfirmDialog(true)}
const confirm = window.confirm(
"Change message type will clear the content, are you sure?"
);
if (!confirm) return;
if (typeof chat.content === "string") {
chat.content = [];
} else {
chat.content = "";
}
setChatStore({ ...chatStore });
}}
> >
Switch to{" "} Switch to{" "}
{typeof chat.content === "string" {typeof chat.content === "string"
@@ -68,6 +67,13 @@ export function EditMessage(props: EditMessageProps) {
)} )}
<Button onClick={() => setShowEdit(false)}>Close</Button> <Button onClick={() => setShowEdit(false)}>Close</Button>
</DialogContent> </DialogContent>
<ConfirmationDialog
isOpen={showConfirmDialog}
onClose={() => setShowConfirmDialog(false)}
onConfirm={handleSwitchMessageType}
title="Switch Message Type"
description="Change message type will clear the content, are you sure?"
/>
</Dialog> </Dialog>
); );
} }

View File

@@ -0,0 +1,48 @@
import React from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
DialogDescription,
} from "./dialog";
import { Button } from "./button";
interface ConfirmationDialogProps {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
title: string;
description: string;
}
export function ConfirmationDialog({
isOpen,
onClose,
onConfirm,
title,
description
}: ConfirmationDialogProps) {
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent>
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={onClose}>
Cancel
</Button>
<Button variant="destructive" onClick={() => {
onConfirm();
onClose();
}}>
Confirm
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}