fix(admin): resolve 500 on missing product update and add direct image URL & paste support
Some checks failed
Deploy Canina / deploy (push) Has been cancelled
Some checks failed
Deploy Canina / deploy (push) Has been cancelled
This commit is contained in:
parent
a3291cc468
commit
9c8286c63f
@ -168,6 +168,11 @@ export class AdminService {
|
||||
}
|
||||
|
||||
async updateProduct(id: string, data: any) {
|
||||
const existing = await this.prisma.product.findUnique({ where: { id } });
|
||||
if (!existing) {
|
||||
throw new NotFoundException(`محصولی با شناسه ${id} یافت نشد.`);
|
||||
}
|
||||
|
||||
const product = await this.prisma.product.update({
|
||||
where: { id },
|
||||
data: {
|
||||
|
||||
@ -36,6 +36,17 @@ export default function MediaSelector({ isOpen, onClose, onSelect, multiple = fa
|
||||
if (!isOpen) return;
|
||||
|
||||
const handlePaste = (e: ClipboardEvent) => {
|
||||
const clipboardText = e.clipboardData?.getData('text');
|
||||
if (clipboardText && (clipboardText.startsWith('http://') || clipboardText.startsWith('https://'))) {
|
||||
e.preventDefault();
|
||||
setPasteStatus('لینک تصویر چسبانده شد!');
|
||||
onSelect(clipboardText);
|
||||
if (!multiple) onClose();
|
||||
if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
|
||||
pasteTimerRef.current = setTimeout(() => setPasteStatus(null), 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
const items = e.clipboardData?.items;
|
||||
if (!items) return;
|
||||
|
||||
|
||||
@ -692,40 +692,73 @@ export default function Products() {
|
||||
</div>
|
||||
|
||||
{/* Media Tab */}
|
||||
<div className={activeTab === 'media' ? 'block space-y-4' : 'hidden'}>
|
||||
<div className={activeTab === 'media' ? 'block space-y-6' : 'hidden'}>
|
||||
{/* Direct Image URL Input Box */}
|
||||
<div className="bg-white p-5 rounded-2xl border border-gray-200 shadow-sm space-y-3">
|
||||
<label className="text-sm font-bold text-gray-700 flex items-center justify-between">
|
||||
<span className="flex items-center gap-2">
|
||||
<ImageIcon className="w-4 h-4 text-purple-600" />
|
||||
لینک مستقیم آدرس تصویر (External / Direct URL)
|
||||
</span>
|
||||
<span className="text-[11px] text-gray-400 font-normal">امکان چسباندن (Ctrl+V) مستقیم آدرس اینترنتی تصویر</span>
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={formData.imageUrl}
|
||||
onChange={(e) => {
|
||||
setFormData({...formData, imageUrl: e.target.value});
|
||||
setMediaImageError(false);
|
||||
}}
|
||||
placeholder="https://example.com/images/product.png یا /uploads/photo.jpg"
|
||||
className="flex-1 px-4 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none font-mono text-sm"
|
||||
dir="ltr"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsMediaSelectorOpen(true)}
|
||||
className="bg-purple-100 text-purple-700 hover:bg-purple-200 px-4 py-2.5 rounded-xl text-xs font-bold transition-colors whitespace-nowrap"
|
||||
>
|
||||
گالری سرور
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Preview Container */}
|
||||
<div className="flex flex-col items-center justify-center p-8 border-2 border-dashed border-gray-200 rounded-2xl bg-white">
|
||||
{formData.imageUrl && !mediaImageError ? (
|
||||
<div className="w-full flex flex-col items-center">
|
||||
<div className="relative group">
|
||||
<img
|
||||
src={getProductImageUrl(formData.imageUrl)}
|
||||
alt=""
|
||||
alt="پیشنمایش تصویر محصول"
|
||||
onError={() => setMediaImageError(true)}
|
||||
className="max-w-xs h-48 object-contain rounded-xl shadow-md border border-gray-100"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity rounded-xl flex items-center justify-center gap-3">
|
||||
<button type="button" onClick={() => setIsMediaSelectorOpen(true)} className="bg-white text-gray-800 px-4 py-2 rounded-lg font-bold text-sm">تغییر عکس</button>
|
||||
<button type="button" onClick={() => setIsMediaSelectorOpen(true)} className="bg-white text-gray-800 px-4 py-2 rounded-lg font-bold text-sm">انتخاب از گالری</button>
|
||||
<button type="button" onClick={() => setFormData({...formData, imageUrl: ''})} className="bg-red-500 text-white px-4 py-2 rounded-lg font-bold text-sm hover:bg-red-600">حذف عکس</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 text-center" dir="ltr">
|
||||
<p className="text-xs text-gray-500 font-mono bg-gray-100 px-4 py-2 rounded-lg inline-block">
|
||||
{formData.imageUrl.split('/').pop()}
|
||||
<p className="text-xs text-gray-500 font-mono bg-gray-100 px-4 py-2 rounded-lg inline-block max-w-md truncate">
|
||||
{formData.imageUrl}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-[11px] text-gray-400 mt-2">برای تغییر عکس، روی تصویر کلیک کنید یا دکمه زیر را بزنید</p>
|
||||
<button type="button" onClick={() => setIsMediaSelectorOpen(true)} className="mt-3 bg-purple-100 text-purple-700 hover:bg-purple-200 px-6 py-2 rounded-xl font-bold transition-colors text-sm">
|
||||
انتخاب از گالری رسانه
|
||||
</button>
|
||||
<p className="text-[11px] text-gray-400 mt-2">تصویر با موفقیت بارگذاری و تایید شد.</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center text-gray-400 mb-4">
|
||||
<ImageIcon className="w-8 h-8" />
|
||||
<ImageIcon className="w-8 h-8 text-purple-400" />
|
||||
</div>
|
||||
<p className="text-gray-500 font-medium mb-4">تصویر محصول یافت نشد یا انتخاب نشده است</p>
|
||||
<p className="text-xs text-gray-400 mb-4">از گالری رسانه تصویر انتخاب کنید یا با Ctrl+V از کلیپبورد بچسبانید</p>
|
||||
<button type="button" onClick={() => setIsMediaSelectorOpen(true)} className="bg-purple-100 text-purple-700 hover:bg-purple-200 px-6 py-2 rounded-xl font-bold transition-colors">
|
||||
انتخاب از گالری رسانه
|
||||
<p className="text-gray-600 font-bold mb-2">آدرس یا فایلی برای تصویر انتخاب نشده است</p>
|
||||
<p className="text-xs text-gray-400 mb-4 text-center leading-relaxed">
|
||||
میتوانید لینک اینترنتی تصویر را در کادر بالا وارد کنید، عکس جدید آپلود نمایید<br />
|
||||
یا از کلیدهای <kbd className="px-1.5 py-0.5 bg-gray-100 rounded text-gray-700 font-mono">Ctrl+V</kbd> برای چسباندن مستقیم فایل یا لینک استفاده کنید.
|
||||
</p>
|
||||
<button type="button" onClick={() => setIsMediaSelectorOpen(true)} className="bg-purple-600 text-white hover:bg-purple-700 px-6 py-2.5 rounded-xl font-bold transition-colors shadow-sm text-sm">
|
||||
انتخاب یا آپلود در گالری
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user