diff --git a/frontend/libs/components/promptbox/src/lib/CharactersModal.tsx b/frontend/libs/components/promptbox/src/lib/CharactersModal.tsx index df2f52d44b..569fea0ce3 100644 --- a/frontend/libs/components/promptbox/src/lib/CharactersModal.tsx +++ b/frontend/libs/components/promptbox/src/lib/CharactersModal.tsx @@ -26,6 +26,11 @@ import { useCharactersStore } from "./promptStore"; import { Input } from "@storyteller/ui-input"; import { Button } from "@storyteller/ui-button"; import { Label } from "@storyteller/ui-label"; +import { + showActionReminder, + isActionReminderOpen, + actionReminderProps, +} from "@storyteller/ui-action-reminder-modal"; interface CharactersModalProps { isOpen: boolean; @@ -147,7 +152,7 @@ const CharacterListView = ({ const [loading, setLoading] = useState(true); const [hasMore, setHasMore] = useState(false); const [cursor, setCursor] = useState(undefined); - const [deletingToken, setDeletingToken] = useState(null); + const sentinelRef = useRef(null); const loadingMoreRef = useRef(false); const storeSetCharacters = useCharactersStore((s) => s.setCharacters); @@ -246,28 +251,49 @@ const CharacterListView = ({ return () => observer.disconnect(); }, [hasMore, cursor, fetchCharacters]); - const handleDelete = async (character: Character) => { - setDeletingToken(character.token); - try { - const api = new CharactersApi(); - const res = await api.DeleteCharacter({ - characterToken: character.token, - }); + const handleDelete = (character: Character) => { + showActionReminder({ + reminderType: "default", + title: "Delete character?", + message: ( +

+ This will permanently delete {character.name}. This + action cannot be undone. +

+ ), + primaryActionText: "Delete", + primaryActionIcon: faTrashAlt, + secondaryActionText: "Cancel", + primaryActionBtnClassName: "bg-red text-white hover:bg-red/90", + onPrimaryAction: async () => { + if (actionReminderProps.value) { + actionReminderProps.value = { + ...actionReminderProps.value, + isLoading: true, + }; + } + try { + const api = new CharactersApi(); + const res = await api.DeleteCharacter({ + characterToken: character.token, + }); - if (res.success) { - setCharacters((prev) => - prev.filter((c) => c.token !== character.token), - ); - storeRemoveCharacter(character.token); - toast.success(`Character "${character.name}" deleted`); - } else { - toast.error(res.errorMessage || "Failed to delete character"); - } - } catch { - toast.error("Failed to delete character"); - } finally { - setDeletingToken(null); - } + if (res.success) { + setCharacters((prev) => + prev.filter((c) => c.token !== character.token), + ); + storeRemoveCharacter(character.token); + toast.success(`Character "${character.name}" deleted`); + } else { + toast.error(res.errorMessage || "Failed to delete character"); + } + } catch { + toast.error("Failed to delete character"); + } finally { + isActionReminderOpen.value = false; + } + }, + }); }; return ( @@ -355,7 +381,6 @@ const CharacterListView = ({ {characters.map((character) => { const isUserCreated = character.is_user_created !== false; - const isDeleting = deletingToken === character.token; return (
- {isDeleting ? ( - - ) : ( - - )} +
)}