feat(clinic): add image deletion functionality with confirmation dialog

This commit is contained in:
hamed
2026-06-19 01:03:45 +03:30
parent ccfb3391f2
commit b3883a6e90
2 changed files with 39 additions and 3 deletions
+4 -2
View File
@@ -52,11 +52,12 @@ export default function BlogFormPage() {
const { data, isLoading } = useQuery({
queryKey: ['blog', uuid],
queryFn: () => api.get<ApiResponse<Blog>>(`/api/v1/blog/${uuid}`),
queryFn: () => api.get<ApiResponse<{ data: Blog }>>(`/api/v1/blog/${uuid}`),
enabled: isEdit,
});
const blog = data?.data;
// detail endpoint is double-nested: success(['data' => $blog->toArray()])
const blog = data?.data?.data;
const { register, handleSubmit, control, watch, setValue, formState: { errors, isSubmitting } } = useForm<FormData>({
resolver: zodResolver(schema),
@@ -178,6 +179,7 @@ export default function BlogFormPage() {
field.onChange(editor.getData())
}
config={{
licenseKey: 'GPL',
language: 'fa',
toolbar: [
'heading', '|',
+35 -1
View File
@@ -479,6 +479,7 @@ export default function ClinicDetailPage() {
const [addrFormOpen, setAddrFormOpen] = useState(false);
const [editingClinicAddr, setEditingClinicAddr] = useState<ClinicAddress | null>(null);
const [deleteAddrConfirm, setDeleteAddrConfirm] = useState<ClinicAddress | null>(null);
const [deleteImageConfirm, setDeleteImageConfirm] = useState<string | null>(null);
const emptyAddrForm = { name: '', address: '', telephone: '', province_id: null as number | null, city_id: null as number | null, latitude: null as number | null, longitude: null as number | null };
const [addrForm, setAddrForm] = useState(emptyAddrForm);
@@ -636,6 +637,16 @@ export default function ClinicDetailPage() {
finally { setGalleryUploading(false); }
};
const handleGalleryRemove = async (url: string) => {
if (!clinic) return;
try {
const remaining = (clinic.images_clinic ?? []).filter(img => img?.url && img.url !== url);
await api.patch(`/api/v1/clinic/${uuid}`, { image_clinic: remaining });
toast.success('تصویر حذف شد');
qc.invalidateQueries({ queryKey: ['clinic-detail', uuid] });
} catch (e: any) { toast.error(e?.message ?? 'خطا در حذف تصویر'); }
};
const hue = HUES_LIST[(uuid?.charCodeAt(0) ?? 0) % HUES_LIST.length];
const logo = clinic?.logo ?? clinic?.clinic_logo;
// شهر و استان از آدرس DoctorAddress (منبع واقعی) نه از Clinic entity
@@ -915,8 +926,17 @@ export default function ClinicDetailPage() {
) : (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(110px, 1fr))', gap: 8 }}>
{clinic.images_clinic.filter(img => img?.url).map((img, i) => (
<div key={i} style={{ borderRadius: 8, overflow: 'hidden', aspectRatio: '1', background: 'var(--surface-2, var(--bg))' }}>
<div key={i} style={{ position: 'relative', borderRadius: 8, overflow: 'hidden', aspectRatio: '1', background: 'var(--surface-2, var(--bg))' }}>
<img src={img.url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
<button
type="button"
className="mini-btn danger"
title="حذف تصویر"
onClick={() => setDeleteImageConfirm(img.url)}
style={{ position: 'absolute', top: 6, left: 6 }}
>
<TrashIcon style={{ width: 14, height: 14 }} />
</button>
</div>
))}
</div>
@@ -1161,6 +1181,20 @@ export default function ClinicDetailPage() {
onCancel={() => setDeleteAddrConfirm(null)}
/>
{/* Delete Gallery Image Confirm */}
<ConfirmDialog
open={deleteImageConfirm !== null}
title="حذف تصویر"
message="آیا از حذف این تصویر از گالری اطمینان دارید؟"
confirmLabel="حذف"
danger
onConfirm={() => {
if (deleteImageConfirm) handleGalleryRemove(deleteImageConfirm);
setDeleteImageConfirm(null);
}}
onCancel={() => setDeleteImageConfirm(null)}
/>
{/* Edit modal — portal to escape Leaflet transform context */}
{editOpen && createPortal(
<EditModal