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 { useAuth } from '../../lib/use-auth';
|
||||||
import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
|
import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
|
||||||
import { downloadCollectionCardsCsv } from '../../lib/collection-cards-csv.js';
|
import { downloadCollectionCardsCsv } from '../../lib/collection-cards-csv.js';
|
||||||
|
import CollectionEditModal from '../../components/CollectionEditModal';
|
||||||
|
import CollectionDeleteModal from '../../components/CollectionDeleteModal';
|
||||||
|
|
||||||
export default function CollectionView() {
|
export default function CollectionView() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -832,132 +834,20 @@ export default function CollectionView() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Edit Collection Modal */}
|
<CollectionEditModal
|
||||||
{showEditModal && (
|
isOpen={showEditModal}
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
editForm={editForm}
|
||||||
<div className="card max-w-md w-full mx-4">
|
setEditForm={setEditForm}
|
||||||
<h2 className="text-2xl font-bold mb-4" style={{ color: 'var(--text-primary)' }}>
|
onClose={() => setShowEditModal(false)}
|
||||||
Edit List
|
onSave={handleEditCollection}
|
||||||
</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
|
|
||||||
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 */}
|
<CollectionDeleteModal
|
||||||
{showDeleteModal && (
|
isOpen={showDeleteModal}
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
collection={collection}
|
||||||
<div className="card max-w-md w-full mx-4">
|
onClose={() => setShowDeleteModal(false)}
|
||||||
<h2 className="text-2xl font-bold mb-4" style={{ color: 'var(--text-primary)' }}>
|
onConfirm={handleDeleteCollection}
|
||||||
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>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Upload Image Modal */}
|
{/* Upload Image Modal */}
|
||||||
<UploadImageModal
|
<UploadImageModal
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue