diff --git a/pickleglass_web/app/personalize/page.tsx b/pickleglass_web/app/personalize/page.tsx index c24398b6..0f91209d 100644 --- a/pickleglass_web/app/personalize/page.tsx +++ b/pickleglass_web/app/personalize/page.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react' import { ChevronDown, Plus, Copy } from 'lucide-react' import { getPresets, updatePreset, createPreset, PromptPreset } from '@/utils/api' +import Modal from '@/components/Modal' export default function PersonalizePage() { const [allPresets, setAllPresets] = useState([]); @@ -13,6 +14,13 @@ export default function PersonalizePage() { const [saving, setSaving] = useState(false); const [isDirty, setIsDirty] = useState(false); + // Modal state management + const [isModalOpen, setIsModalOpen] = useState(false); + const [modalPreset, setModalPreset] = useState(null); + const [modalContent, setModalContent] = useState(''); + const [modalTitle, setModalTitle] = useState(''); + const [modalIsDirty, setModalIsDirty] = useState(false); + useEffect(() => { const fetchData = async () => { try { @@ -147,6 +155,113 @@ export default function PersonalizePage() { } }; + const openModalWithPreset = (preset: PromptPreset) => { + setModalPreset(preset); + setModalContent(preset.prompt); + setModalTitle(preset.title); + setModalIsDirty(false); + setIsModalOpen(true); + }; + + const closeModal = () => { + if (modalIsDirty) { + const shouldClose = window.confirm( + 'You have unsaved changes in the modal editor. Are you sure you want to close without saving?' + ); + if (!shouldClose) { + return; + } + } + setIsModalOpen(false); + setModalPreset(null); + setModalContent(''); + setModalTitle(''); + setModalIsDirty(false); + }; + + const handleModalContentChange = (newContent: string) => { + setModalContent(newContent); + setModalIsDirty( + newContent !== modalPreset?.prompt || modalTitle !== modalPreset?.title + ); + }; + + const handleModalTitleChange = (newTitle: string) => { + setModalTitle(newTitle); + setModalIsDirty( + newTitle !== modalPreset?.title || modalContent !== modalPreset?.prompt + ); + }; + + const saveModalChanges = async () => { + if (!modalPreset || !modalIsDirty) return; + + if (modalPreset.is_default === 1) { + alert('Default presets cannot be modified.'); + return; + } + + if (!modalTitle.trim()) { + alert('Preset title cannot be empty.'); + return; + } + + try { + setSaving(true); + await updatePreset(modalPreset.id, { + title: modalTitle.trim(), + prompt: modalContent, + }); + + // Create the updated preset object + const updatedPreset = { ...modalPreset, title: modalTitle.trim(), prompt: modalContent }; + + // Update the preset in the main list + setAllPresets(prev => prev.map(p => + p.id === modalPreset.id ? updatedPreset : p + )); + + // Update selected preset if it's the same one + if (selectedPreset?.id === modalPreset.id) { + setSelectedPreset(updatedPreset); + setEditorContent(modalContent); + setIsDirty(false); + } + + // Update modal preset state to reflect the saved changes + setModalPreset(updatedPreset); + + // Reset modal states and close + setModalIsDirty(false); + setIsModalOpen(false); + } catch (error) { + console.error('Failed to save modal changes:', error); + + // Enhanced error handling with specific error types + let errorMessage = 'Failed to save preset. Please try again.'; + + if (error instanceof Error) { + // Check for specific error types + if (error.message.includes('network') || error.message.includes('fetch')) { + errorMessage = 'Network error. Please check your connection and try again.'; + } else if (error.message.includes('401') || error.message.includes('unauthorized')) { + errorMessage = 'Authentication error. Please log in again.'; + } else if (error.message.includes('403') || error.message.includes('forbidden')) { + errorMessage = 'You do not have permission to edit this preset.'; + } else if (error.message.includes('404')) { + errorMessage = 'Preset not found. It may have been deleted.'; + } else if (error.message.includes('500')) { + errorMessage = 'Server error. Please try again later.'; + } + } + + alert(errorMessage); + + } finally { + setSaving(false); + } + }; + if (loading) { return (
@@ -201,8 +316,8 @@ export default function PersonalizePage() {
-
-
+
+
-
-
- {selectedPreset?.is_default === 1 && ( -
-
-
-

- This is a default preset and cannot be edited. - Use the "Duplicate" button above to create an editable copy, or create a new preset. -

-
+ + + {/* Preset Editor Modal */} + + + + + } + className="w-[95%] sm:w-[90%] md:w-[85%] lg:w-[80%] max-w-4xl" + > +
+
+ {modalIsDirty && ( + + Unsaved changes + + )} + {modalPreset?.is_default === 1 && ( + + Read-only (Default preset) + + )} +
+ +
+
+ handleModalTitleChange(e.target.value)} + className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm" + placeholder="Enter preset title..." + readOnly={modalPreset?.is_default === 1} + /> +
+ +
+