Extract collection edit and delete modals (Brief 2). (#85)
Adds CollectionEditModal and CollectionDeleteModal for the collection detail page. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
30bc154bec
commit
8e2c0e47a8
3 changed files with 171 additions and 125 deletions
46
components/CollectionDeleteModal.js
Normal file
46
components/CollectionDeleteModal.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { collectionDisplayName } from '../lib/collection-vocabulary.js';
|
||||
|
||||
export default function CollectionDeleteModal({
|
||||
isOpen,
|
||||
collection,
|
||||
onClose,
|
||||
onConfirm,
|
||||
}) {
|
||||
if (!isOpen || !collection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="card max-w-md w-full mx-4">
|
||||
<h2 className="text-2xl font-bold mb-4" style={{ color: 'var(--text-primary)' }}>
|
||||
Delete List
|
||||
</h2>
|
||||
<p className="mb-6" style={{ color: 'var(--text-secondary)' }}>
|
||||
Are you sure you want to delete "{collectionDisplayName(collection)}"? This action
|
||||
cannot be undone and will permanently remove all cards and data associated with this list.
|
||||
</p>
|
||||
<div className="flex space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="flex-1 py-2 px-4 rounded-xl border transition-colors"
|
||||
style={{
|
||||
borderColor: 'var(--border)',
|
||||
color: 'var(--text-secondary)',
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onConfirm}
|
||||
className="flex-1 py-2 px-4 rounded-xl font-medium transition-all duration-200 hover:shadow-md bg-red-600 text-white hover:bg-red-700"
|
||||
>
|
||||
Delete List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
110
components/CollectionEditModal.js
Normal file
110
components/CollectionEditModal.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
export default function CollectionEditModal({
|
||||
isOpen,
|
||||
editForm,
|
||||
setEditForm,
|
||||
onClose,
|
||||
onSave,
|
||||
}) {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="card max-w-md w-full mx-4">
|
||||
<h2 className="text-2xl font-bold mb-4" style={{ color: 'var(--text-primary)' }}>
|
||||
Edit List
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
|
||||
List Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input-field w-full"
|
||||
value={editForm.name}
|
||||
onChange={(e) => setEditForm({ ...editForm, name: e.target.value })}
|
||||
placeholder="Enter list name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
className="input-field w-full"
|
||||
rows="3"
|
||||
value={editForm.description}
|
||||
onChange={(e) => setEditForm({ ...editForm, description: e.target.value })}
|
||||
placeholder="Describe your list"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
|
||||
Hero Image (Optional)
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
className="input-field w-full"
|
||||
value={editForm.image}
|
||||
onChange={(e) => setEditForm({ ...editForm, image: e.target.value })}
|
||||
placeholder="Enter image URL"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center justify-between p-4 rounded-lg border"
|
||||
style={{ borderColor: 'var(--border)' }}
|
||||
>
|
||||
<div>
|
||||
<label className="text-sm font-medium" style={{ color: 'var(--text-primary)' }}>
|
||||
Public List
|
||||
</label>
|
||||
<p className="text-xs mt-1" style={{ color: 'var(--text-secondary)' }}>
|
||||
Make this collection discoverable by other users
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditForm({ ...editForm, isPublic: !editForm.isPublic })}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
|
||||
editForm.isPublic ? 'bg-green-600' : 'bg-gray-300 dark:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
|
||||
editForm.isPublic ? 'translate-x-6' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex space-x-3 mt-6">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="flex-1 py-2 px-4 rounded-xl border transition-colors"
|
||||
style={{
|
||||
borderColor: 'var(--border)',
|
||||
color: 'var(--text-secondary)',
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onSave}
|
||||
disabled={!editForm.name.trim()}
|
||||
className="flex-1 py-2 px-4 rounded-xl font-medium transition-all duration-200 hover:shadow-md disabled:opacity-50"
|
||||
style={{
|
||||
backgroundColor: 'var(--accent-ember)',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@ import ManaSymbolSettings from '../../components/ManaSymbolSettings';
|
|||
import { useAuth } from '../../lib/use-auth';
|
||||
import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
|
||||
import { downloadCollectionCardsCsv } from '../../lib/collection-cards-csv.js';
|
||||
import CollectionEditModal from '../../components/CollectionEditModal';
|
||||
import CollectionDeleteModal from '../../components/CollectionDeleteModal';
|
||||
|
||||
export default function CollectionView() {
|
||||
const router = useRouter();
|
||||
|
|
@ -832,132 +834,20 @@ export default function CollectionView() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Edit Collection Modal */}
|
||||
{showEditModal && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="card max-w-md w-full mx-4">
|
||||
<h2 className="text-2xl font-bold mb-4" style={{ color: 'var(--text-primary)' }}>
|
||||
Edit List
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
|
||||
List Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input-field w-full"
|
||||
value={editForm.name}
|
||||
onChange={(e) => setEditForm({...editForm, name: e.target.value})}
|
||||
placeholder="Enter list name"
|
||||
<CollectionEditModal
|
||||
isOpen={showEditModal}
|
||||
editForm={editForm}
|
||||
setEditForm={setEditForm}
|
||||
onClose={() => setShowEditModal(false)}
|
||||
onSave={handleEditCollection}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
className="input-field w-full"
|
||||
rows="3"
|
||||
value={editForm.description}
|
||||
onChange={(e) => setEditForm({...editForm, description: e.target.value})}
|
||||
placeholder="Describe your list"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
|
||||
Hero Image (Optional)
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
className="input-field w-full"
|
||||
value={editForm.image}
|
||||
onChange={(e) => setEditForm({...editForm, image: e.target.value})}
|
||||
placeholder="Enter image URL"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-4 rounded-lg border" style={{ borderColor: 'var(--border)' }}>
|
||||
<div>
|
||||
<label className="text-sm font-medium" style={{ color: 'var(--text-primary)' }}>
|
||||
Public List
|
||||
</label>
|
||||
<p className="text-xs mt-1" style={{ color: 'var(--text-secondary)' }}>
|
||||
Make this collection discoverable by other users
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditForm({...editForm, isPublic: !editForm.isPublic})}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
|
||||
editForm.isPublic ? 'bg-green-600' : 'bg-gray-300 dark:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
|
||||
editForm.isPublic ? 'translate-x-6' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex space-x-3 mt-6">
|
||||
<button
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="flex-1 py-2 px-4 rounded-xl border transition-colors"
|
||||
style={{
|
||||
borderColor: 'var(--border)',
|
||||
color: 'var(--text-secondary)'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleEditCollection}
|
||||
disabled={!editForm.name.trim()}
|
||||
className="flex-1 py-2 px-4 rounded-xl font-medium transition-all duration-200 hover:shadow-md disabled:opacity-50"
|
||||
style={{
|
||||
backgroundColor: 'var(--accent-ember)',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Modal */}
|
||||
{showDeleteModal && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="card max-w-md w-full mx-4">
|
||||
<h2 className="text-2xl font-bold mb-4" style={{ color: 'var(--text-primary)' }}>
|
||||
Delete List
|
||||
</h2>
|
||||
<p className="mb-6" style={{ color: 'var(--text-secondary)' }}>
|
||||
Are you sure you want to delete "{collectionDisplayName(collection)}"? This action cannot be undone and will permanently remove all cards and data associated with this list.
|
||||
</p>
|
||||
<div className="flex space-x-3">
|
||||
<button
|
||||
onClick={() => setShowDeleteModal(false)}
|
||||
className="flex-1 py-2 px-4 rounded-xl border transition-colors"
|
||||
style={{
|
||||
borderColor: 'var(--border)',
|
||||
color: 'var(--text-secondary)'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDeleteCollection}
|
||||
className="flex-1 py-2 px-4 rounded-xl font-medium transition-all duration-200 hover:shadow-md bg-red-600 text-white hover:bg-red-700"
|
||||
>
|
||||
Delete List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<CollectionDeleteModal
|
||||
isOpen={showDeleteModal}
|
||||
collection={collection}
|
||||
onClose={() => setShowDeleteModal(false)}
|
||||
onConfirm={handleDeleteCollection}
|
||||
/>
|
||||
|
||||
{/* Upload Image Modal */}
|
||||
<UploadImageModal
|
||||
|
|
|
|||
Loading…
Reference in a new issue