feat(clinic): add image deletion functionality with confirmation dialog
This commit is contained in:
@@ -52,11 +52,12 @@ export default function BlogFormPage() {
|
|||||||
|
|
||||||
const { data, isLoading } = useQuery({
|
const { data, isLoading } = useQuery({
|
||||||
queryKey: ['blog', uuid],
|
queryKey: ['blog', uuid],
|
||||||
queryFn: () => api.get<ApiResponse<Blog>>(`/api/v1/blog/${uuid}`),
|
queryFn: () => api.get<ApiResponse<{ data: Blog }>>(`/api/v1/blog/${uuid}`),
|
||||||
enabled: isEdit,
|
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>({
|
const { register, handleSubmit, control, watch, setValue, formState: { errors, isSubmitting } } = useForm<FormData>({
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
@@ -178,6 +179,7 @@ export default function BlogFormPage() {
|
|||||||
field.onChange(editor.getData())
|
field.onChange(editor.getData())
|
||||||
}
|
}
|
||||||
config={{
|
config={{
|
||||||
|
licenseKey: 'GPL',
|
||||||
language: 'fa',
|
language: 'fa',
|
||||||
toolbar: [
|
toolbar: [
|
||||||
'heading', '|',
|
'heading', '|',
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ export default function ClinicDetailPage() {
|
|||||||
const [addrFormOpen, setAddrFormOpen] = useState(false);
|
const [addrFormOpen, setAddrFormOpen] = useState(false);
|
||||||
const [editingClinicAddr, setEditingClinicAddr] = useState<ClinicAddress | null>(null);
|
const [editingClinicAddr, setEditingClinicAddr] = useState<ClinicAddress | null>(null);
|
||||||
const [deleteAddrConfirm, setDeleteAddrConfirm] = 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 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);
|
const [addrForm, setAddrForm] = useState(emptyAddrForm);
|
||||||
@@ -636,6 +637,16 @@ export default function ClinicDetailPage() {
|
|||||||
finally { setGalleryUploading(false); }
|
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 hue = HUES_LIST[(uuid?.charCodeAt(0) ?? 0) % HUES_LIST.length];
|
||||||
const logo = clinic?.logo ?? clinic?.clinic_logo;
|
const logo = clinic?.logo ?? clinic?.clinic_logo;
|
||||||
// شهر و استان از آدرس DoctorAddress (منبع واقعی) نه از Clinic entity
|
// شهر و استان از آدرس DoctorAddress (منبع واقعی) نه از Clinic entity
|
||||||
@@ -915,8 +926,17 @@ export default function ClinicDetailPage() {
|
|||||||
) : (
|
) : (
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(110px, 1fr))', gap: 8 }}>
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(110px, 1fr))', gap: 8 }}>
|
||||||
{clinic.images_clinic.filter(img => img?.url).map((img, i) => (
|
{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' }} />
|
<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>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -1161,6 +1181,20 @@ export default function ClinicDetailPage() {
|
|||||||
onCancel={() => setDeleteAddrConfirm(null)}
|
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 */}
|
{/* Edit modal — portal to escape Leaflet transform context */}
|
||||||
{editOpen && createPortal(
|
{editOpen && createPortal(
|
||||||
<EditModal
|
<EditModal
|
||||||
|
|||||||
Reference in New Issue
Block a user