From 37e3a664bfab1c88124491baf26ea84e0269b975 Mon Sep 17 00:00:00 2001 From: Wendy Yuchen Sun Date: Wed, 20 May 2026 17:16:57 +0800 Subject: [PATCH] feat: add image upload lack source error msg --- public/locales/en/upload-image-modal.json | 1 + public/locales/zh-TW/upload-image-modal.json | 1 + src/components/image-upload-modal.js | 29 ++++++++++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/public/locales/en/upload-image-modal.json b/public/locales/en/upload-image-modal.json index e0f9059..c44ed7a 100644 --- a/public/locales/en/upload-image-modal.json +++ b/public/locales/en/upload-image-modal.json @@ -12,6 +12,7 @@ "removeImage": "Remove Image", "optional": "(Optional)", "altTextRequired": "Alt text is required", + "sourceRequired": "Please enter an image URL or upload an image", "dropTitle": "Drag & drop to upload", "dropMeta": "Max size: {{maxSize}}MB Recommended: 1200 x 800 px Formats: jpg/jpeg, png", "uploadFailed": "Image upload failed", diff --git a/public/locales/zh-TW/upload-image-modal.json b/public/locales/zh-TW/upload-image-modal.json index ec99bda..4957b88 100644 --- a/public/locales/zh-TW/upload-image-modal.json +++ b/public/locales/zh-TW/upload-image-modal.json @@ -12,6 +12,7 @@ "removeImage": "移除圖片", "optional": "(選填)", "altTextRequired": "請輸入替代文字", + "sourceRequired": "請填寫圖片 URL 或上傳圖片", "dropTitle": "拖曳檔案上傳", "dropMeta": "大小限制:{{maxSize}}MB 建議尺寸:1200 x 800 px 支援格式:jpg/jpeg, png", "uploadFailed": "圖片上傳失敗", diff --git a/src/components/image-upload-modal.js b/src/components/image-upload-modal.js index 779b869..408cfdd 100644 --- a/src/components/image-upload-modal.js +++ b/src/components/image-upload-modal.js @@ -10,7 +10,7 @@ import RadioGroup from '@/components/core/radio-group'; const MAX_FILE_SIZE_MB = 10; -const ImageSource = ({ onChange }) => { +const ImageSource = ({ onChange, error, onErrorClear }) => { const [uploadFile, setUploadFile] = useState(null); const [uploadError, setUploadError] = useState(false); const [embedUrl, setEmbedUrl] = useState(''); @@ -48,6 +48,7 @@ const ImageSource = ({ onChange }) => { if (!file) return; resetSourceState(); + onErrorClear?.(); if (file.size > MAX_FILE_SIZE_MB * 1024 * 1024) { setUploadError(true); @@ -91,6 +92,7 @@ const ImageSource = ({ onChange }) => { if (!trimmed) return; resetSourceState({ resetFileInput: true }); + onErrorClear?.(); if (!isValidUrl(trimmed)) { setEmbedError(true); @@ -260,7 +262,10 @@ const ImageSource = ({ onChange }) => { id="embed-url" aria-describedby="embed-url-hint" value={embedUrl} - onChange={(val) => setEmbedUrl(val)} + onChange={(val) => { + setEmbedUrl(val); + if (error) onErrorClear?.(); + }} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -268,6 +273,7 @@ const ImageSource = ({ onChange }) => { } }} placeholder={t('embedUrlPlaceholder')} + error={error} /> @@ -281,10 +287,13 @@ const ImageSource = ({ onChange }) => { ImageSource.propTypes = { onChange: PropTypes.func.isRequired, + error: PropTypes.string, + onErrorClear: PropTypes.func, }; const ImageUploadModal = ({ isOpen, onClose, onConfirm }) => { const [imageSource, setImageSource] = useState(null); + const [sourceError, setSourceError] = useState(''); const [altText, setAltText] = useState(''); const [altTextError, setAltTextError] = useState(''); const [caption, setCaption] = useState(''); @@ -296,6 +305,7 @@ const ImageUploadModal = ({ isOpen, onClose, onConfirm }) => { const resetForm = () => { setImageSource(null); + setSourceError(''); setAltText(''); setAltTextError(''); setCaption(''); @@ -310,9 +320,11 @@ const ImageUploadModal = ({ isOpen, onClose, onConfirm }) => { }; const handleConfirm = () => { - if (!imageSource) return; // TODO: ask designer where to show image validation error - let valid = true; + if (!imageSource) { + setSourceError(t('sourceRequired')); + valid = false; + } if (!altText.trim()) { setAltTextError(t('altTextRequired')); valid = false; @@ -350,7 +362,14 @@ const ImageUploadModal = ({ isOpen, onClose, onConfirm }) => { >
{/* Image source */} - + { + setImageSource(src); + if (src) setSourceError(''); + }} + error={sourceError} + onErrorClear={() => setSourceError('')} + /> {/* Alt text */}