Files
clinicpro/assets/admin/components/ImageCropModal.tsx
T

78 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useCallback, useState } from 'react';
import { createPortal } from 'react-dom';
import Cropper, { type Area } from 'react-easy-crop';
import { getCroppedImage } from '../lib/cropImage';
interface ImageCropModalProps {
src: string;
fileName: string;
onCancel: () => void;
onConfirm: (file: File) => void;
}
export default function ImageCropModal({ src, fileName, onCancel, onConfirm }: ImageCropModalProps) {
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const [area, setArea] = useState<Area | null>(null);
const [processing, setProcessing] = useState(false);
const onCropComplete = useCallback((_: Area, pixels: Area) => setArea(pixels), []);
const handleConfirm = async () => {
if (!area) return;
setProcessing(true);
try {
const file = await getCroppedImage(src, area, fileName);
onConfirm(file);
} finally {
setProcessing(false);
}
};
return createPortal(
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4" dir="rtl">
<div className="w-full max-w-md rounded-2xl bg-white dark:bg-gray-900 shadow-2xl overflow-hidden">
<div className="flex items-center justify-between px-5 py-4 border-b border-slate-100 dark:border-gray-800">
<p className="text-base font-bold text-slate-800 dark:text-slate-100">برش تصویر</p>
<button onClick={onCancel}
className="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 text-xl leading-none">×</button>
</div>
<div className="relative w-full h-72 bg-slate-100 dark:bg-gray-800">
<Cropper
image={src}
crop={crop}
zoom={zoom}
aspect={1}
cropShape="round"
showGrid={false}
onCropChange={setCrop}
onZoomChange={setZoom}
onCropComplete={onCropComplete}
/>
</div>
<div className="px-5 py-4 space-y-4">
<div className="flex items-center gap-3">
<span className="text-xs text-slate-500 dark:text-slate-400 shrink-0">بزرگ‌نمایی</span>
<input type="range" min={1} max={3} step={0.01} value={zoom}
onChange={e => setZoom(Number(e.target.value))}
className="w-full accent-indigo-600" />
</div>
<div className="flex items-center justify-end gap-3">
<button onClick={onCancel} disabled={processing}
className="px-4 py-2 rounded-xl text-sm font-medium text-slate-600 dark:text-slate-300 bg-slate-100 dark:bg-gray-800 hover:bg-slate-200 dark:hover:bg-gray-700 disabled:opacity-50">
انصراف
</button>
<button onClick={handleConfirm} disabled={processing || !area}
className="px-4 py-2 rounded-xl text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50">
{processing ? 'در حال برش...' : 'ذخیره'}
</button>
</div>
</div>
</div>
</div>,
document.body,
);
}