- Added `media-library.php` configuration file for managing media uploads and conversions. - Updated `filesystems.php` to set default visibility for AWS S3 storage. - Implemented `FileUpload` component for handling file uploads with preview and error handling. - Created `ImagePreviewModal` component for displaying image previews in a modal. - Introduced `Attachment` UI components for better file attachment handling. - Added `useFileUpload` hook to manage file upload state and logic. - Implemented utility functions for uploading files to S3 with presigned URLs. - Created API route for generating presigned URLs for file uploads.
83 lines
2.0 KiB
TypeScript
83 lines
2.0 KiB
TypeScript
import { useCallback, useRef, useState } from 'react';
|
|
import {
|
|
InputGroup,
|
|
InputGroupAddon,
|
|
InputGroupInput,
|
|
InputGroupText,
|
|
} from '@/components/ui/input-group';
|
|
|
|
type RupiahInputProps = {
|
|
name?: string;
|
|
defaultValue?: number;
|
|
placeholder?: string;
|
|
disabled?: boolean;
|
|
min?: number;
|
|
max?: number;
|
|
className?: string;
|
|
};
|
|
|
|
function formatRupiah(value: number): string {
|
|
return value.toLocaleString('id-ID');
|
|
}
|
|
|
|
function parseRupiah(value: string): number {
|
|
const cleaned = value.replace(/[^0-9]/g, '');
|
|
|
|
return cleaned === '' ? 0 : parseInt(cleaned, 10);
|
|
}
|
|
|
|
export function RupiahInput({
|
|
name,
|
|
defaultValue = 0,
|
|
placeholder = '0',
|
|
disabled = false,
|
|
min,
|
|
max,
|
|
className,
|
|
}: RupiahInputProps) {
|
|
const [displayValue, setDisplayValue] = useState(formatRupiah(defaultValue));
|
|
const lastValidRef = useRef(defaultValue);
|
|
|
|
const handleChange = useCallback(
|
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const raw = parseRupiah(e.target.value);
|
|
let clamped = raw;
|
|
|
|
if (min !== undefined && raw < min) {
|
|
clamped = min;
|
|
}
|
|
|
|
if (max !== undefined && raw > max) {
|
|
clamped = max;
|
|
}
|
|
|
|
lastValidRef.current = clamped;
|
|
setDisplayValue(formatRupiah(clamped));
|
|
},
|
|
[min, max],
|
|
);
|
|
|
|
const handleBlur = useCallback(() => {
|
|
setDisplayValue(formatRupiah(lastValidRef.current));
|
|
}, []);
|
|
|
|
return (
|
|
<InputGroup className={className}>
|
|
<InputGroupAddon>
|
|
<InputGroupText>Rp</InputGroupText>
|
|
</InputGroupAddon>
|
|
<InputGroupInput
|
|
name={name}
|
|
type="text"
|
|
inputMode="numeric"
|
|
value={displayValue}
|
|
onChange={handleChange}
|
|
onBlur={handleBlur}
|
|
placeholder={placeholder}
|
|
disabled={disabled}
|
|
autoComplete="off"
|
|
/>
|
|
</InputGroup>
|
|
);
|
|
}
|