Fix URL validation blocking uploaded photos in AddCardModal
This commit is contained in:
1 parent
0c98b1babf
commit
15fbe1db88
1 file changed
+106
-8
@@ -89,7 +89,7 @@ export const AddCardModal: React.FC<AddCardModalProps> = ({ isOpen, onClose, onA
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4 text-xs">
|
||||
<form onSubmit={handleSubmit} noValidate className="space-y-4 text-xs">
|
||||
{/* Card Type */}
|
||||
<div>
|
||||
<label className="block text-neutral-400 mb-1">Card Type</label>
|
||||
@@ -159,15 +159,30 @@ export const AddCardModal: React.FC<AddCardModalProps> = ({ isOpen, onClose, onA
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="url"
|
||||
type="text"
|
||||
value={imageUrl}
|
||||
onChange={(e) => setImageUrl(e.target.value)}
|
||||
placeholder="Or paste an image URL (https://...)"
|
||||
placeholder="Or paste an image URL (https://... or /uploads/...)"
|
||||
className="w-full bg-neutral-800 border border-neutral-700 rounded px-2.5 py-1.5 text-neutral-100 focus:outline-none focus:border-amber-500 text-[11px]"
|
||||
/>
|
||||
{imageUrl && (
|
||||
<div className="w-16 h-16 rounded border border-neutral-700 overflow-hidden relative mt-1">
|
||||
<img src={imageUrl} alt="Preview" className="w-full h-full object-cover" />
|
||||
<div className="flex items-center gap-2.5 mt-1 bg-neutral-900/80 p-2 rounded-lg border border-neutral-800">
|
||||
<div className="w-12 h-12 rounded border border-neutral-700 overflow-hidden relative shrink-0">
|
||||
<img src={imageUrl} alt="Preview" className="w-full h-full object-cover" />
|
||||
</div>
|
||||
<div className="flex flex-col text-[11px] overflow-hidden min-w-0">
|
||||
<span className="text-emerald-400 font-medium flex items-center gap-1">
|
||||
<span>✓ Photo Ready</span>
|
||||
</span>
|
||||
<span className="truncate text-neutral-400 font-mono text-[10px]">{imageUrl}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setImageUrl('')}
|
||||
className="text-neutral-400 hover:text-red-400 text-left underline text-[10px] mt-0.5"
|
||||
>
|
||||
Clear photo
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -246,13 +261,50 @@ export const EditCardModal: React.FC<EditCardModalProps> = ({
|
||||
const [title, setTitle] = useState(card.title || '');
|
||||
const [content, setContent] = useState(card.content || '');
|
||||
const [color, setColor] = useState(card.color || '#FFF9A6');
|
||||
const [imageUrl, setImageUrl] = useState(card.imageUrl || '');
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
const handleEditFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (ev) => {
|
||||
if (typeof ev.target?.result === 'string') {
|
||||
setImageUrl(ev.target.result);
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
setIsUploading(true);
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
fetch('/api/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
setIsUploading(false);
|
||||
if (data.success && data.url) {
|
||||
setImageUrl(data.url);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('Upload error:', err);
|
||||
setIsUploading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
onSave({
|
||||
...card,
|
||||
title: title.trim() || undefined,
|
||||
content: content.trim(),
|
||||
color
|
||||
color,
|
||||
imageUrl: card.type === 'polaroid' ? (imageUrl.trim() || undefined) : card.imageUrl,
|
||||
photoCaption: card.type === 'polaroid' ? (title.trim() || content.trim()) : undefined
|
||||
});
|
||||
onClose();
|
||||
};
|
||||
@@ -281,15 +333,61 @@ export const EditCardModal: React.FC<EditCardModalProps> = ({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-neutral-400 mb-1">Content</label>
|
||||
<label className="block text-neutral-400 mb-1">
|
||||
{card.type === 'polaroid' ? 'Back / Note Text' : 'Content'}
|
||||
</label>
|
||||
<textarea
|
||||
rows={4}
|
||||
rows={3}
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
className="w-full bg-neutral-800 border border-neutral-700 rounded px-2.5 py-1.5 text-neutral-100 focus:outline-none focus:border-amber-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Photo management for Polaroid */}
|
||||
{card.type === 'polaroid' && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-center text-neutral-400">
|
||||
<span>Photo / Snapshot</span>
|
||||
{isUploading && (
|
||||
<span className="text-[10px] text-amber-400 font-mono animate-pulse">
|
||||
Uploading...
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<label className="flex-1 flex items-center justify-center gap-1.5 py-1.5 px-3 bg-neutral-800 border border-neutral-700 hover:border-amber-500 rounded cursor-pointer text-amber-300 font-medium transition text-center">
|
||||
<span>📸 {isUploading ? 'Uploading...' : 'Replace Photo'}</span>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleEditFileUpload}
|
||||
className="hidden"
|
||||
disabled={isUploading}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={imageUrl}
|
||||
onChange={(e) => setImageUrl(e.target.value)}
|
||||
placeholder="Or paste an image URL (https://... or /uploads/...)"
|
||||
className="w-full bg-neutral-800 border border-neutral-700 rounded px-2.5 py-1.5 text-neutral-100 focus:outline-none focus:border-amber-500 text-[11px]"
|
||||
/>
|
||||
{imageUrl && (
|
||||
<div className="flex items-center gap-2.5 mt-1 bg-neutral-900/80 p-2 rounded-lg border border-neutral-800">
|
||||
<div className="w-12 h-12 rounded border border-neutral-700 overflow-hidden relative shrink-0">
|
||||
<img src={imageUrl} alt="Preview" className="w-full h-full object-cover" />
|
||||
</div>
|
||||
<div className="flex flex-col text-[11px] overflow-hidden min-w-0">
|
||||
<span className="text-emerald-400 font-medium">✓ Photo Attached</span>
|
||||
<span className="truncate text-neutral-400 font-mono text-[10px]">{imageUrl}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="block text-neutral-400 mb-1">Paper Tint</label>
|
||||
<div className="flex gap-2">
|
||||
|
||||
Reference in new issue
Block a user