Fix URL validation blocking uploaded photos in AddCardModal

This commit is contained in:
airent106 committed 2026-10-13 09:28:09 -06:00
1 parent 0c98b1babf
commit 15fbe1db88
1 file changed
+106 -8
+106 -8
View File
@@ -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">