siakad-itm/resources/js/components/signature-pad.tsx
Yoga Pangestu 8336504032
Some checks failed
tests / ci (pull_request) Has been cancelled
feat: add course registration management for admin and student
- Implemented CourseRegistrationShow component for admin to view registration details.
- Added course registration creation and listing for students.
- Enhanced student registration edit and create forms with improved error handling.
- Introduced new columns for course registration submissions in student view.
- Updated routes for course registration management in admin and student contexts.
- Added logging and status handling for course registration submissions.
- Improved type definitions for course registration and user roles.
2026-08-30 20:50:27 +07:00

98 lines
3.1 KiB
TypeScript

import { Eraser } from 'lucide-react';
import { useRef } from 'react';
import SignatureCanvasImport from 'react-signature-canvas';
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
// react-signature-canvas ships as a CommonJS/UMD bundle. Vite's dev-server
// pre-bundling wraps its `module.exports` (itself `{ __esModule: true,
// default: SignatureCanvas }`) as the ESM default export, so the default
// import resolves one layer too shallow. Unwrap it before use.
const SignatureCanvas = ((
SignatureCanvasImport as unknown as {
default?: typeof SignatureCanvasImport;
}
).default ?? SignatureCanvasImport) as typeof SignatureCanvasImport;
type SignaturePadProps = {
name: string;
error?: string;
};
export function SignaturePad({ name, error }: SignaturePadProps) {
const padRef = useRef<SignatureCanvasImport>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
function syncFileInput() {
const pad = padRef.current;
const input = fileInputRef.current;
if (!pad || !input || pad.isEmpty()) {
return;
}
pad.getTrimmedCanvas().toBlob((blob: Blob | null) => {
if (!blob) {
return;
}
const file = new File([blob], 'signature.png', {
type: 'image/png',
});
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
input.files = dataTransfer.files;
}, 'image/png');
}
function handleClear() {
padRef.current?.clear();
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
}
return (
<div className="grid gap-2">
<div className="flex items-center justify-between">
<Label>
Tanda Tangan <span className="text-destructive">*</span>
</Label>
<Button
type="button"
variant="outline"
size="sm"
onClick={handleClear}
>
<Eraser className="h-4 w-4" />
Hapus
</Button>
</div>
<div className="overflow-hidden rounded-md border bg-white">
<SignatureCanvas
ref={padRef}
penColor="#0f172a"
canvasProps={{
className:
'h-[180px] w-full cursor-crosshair touch-none',
}}
onEnd={syncFileInput}
/>
</div>
<input
ref={fileInputRef}
type="file"
name={name}
className="hidden"
/>
<p className="text-xs text-muted-foreground">
Gambar tanda tangan Anda pada kotak di atas menggunakan mouse
atau layar sentuh.
</p>
<InputError message={error} />
</div>
);
}