7f2ab5b359
- Added page for creating forms associated with events, including template selection and validation of form dates against event dates. - Created layout component to provide context for event-related pages. - Developed event detail page with editing capabilities and form management. - Introduced event creation page with banner upload functionality and preview. - Implemented event listing page displaying active and recent events with associated forms. - Added layout for user section including header, navbar, and footer. - Created page for uploading teacher data from Excel files. - Developed QR code scanning page for attendance registration with modal confirmation. - Implemented login functionality with fake user data for testing purposes. - Added event card preview component to display event details and banner.
82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import Image from 'next/image';
|
|
import React, { useRef, useState } from 'react';
|
|
import Button from './button';
|
|
|
|
interface BannerUploaderProps {
|
|
label?: string;
|
|
onChange?: (file: File | null) => void;
|
|
defaultBanner?: string;
|
|
className?: string;
|
|
showPreview?: boolean;
|
|
}
|
|
|
|
export default function ImageUploader({
|
|
label = 'Subir imagen',
|
|
onChange,
|
|
defaultBanner,
|
|
className = '',
|
|
showPreview = true,
|
|
}: BannerUploaderProps) {
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
const [preview, setPreview] = useState<string | null>(defaultBanner || null);
|
|
|
|
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = event.target.files?.[0] || null;
|
|
if (file) {
|
|
const reader = new FileReader();
|
|
reader.onloadend = () => {
|
|
setPreview(reader.result as string);
|
|
};
|
|
reader.readAsDataURL(file);
|
|
} else {
|
|
setPreview(null);
|
|
}
|
|
onChange?.(file);
|
|
};
|
|
|
|
const handleRemoveImage = () => {
|
|
setPreview(null);
|
|
if (fileInputRef.current) {
|
|
fileInputRef.current.value = '';
|
|
}
|
|
onChange?.(null);
|
|
};
|
|
|
|
return (
|
|
<div className={className}>
|
|
{label && <label className="block mb-2 font-semibold">{label}</label>}
|
|
<div className="d-flex gap-2 align-items-start mb-2">
|
|
<input
|
|
ref={fileInputRef}
|
|
type="file"
|
|
accept="image/*"
|
|
onChange={handleFileChange}
|
|
className="form-control"
|
|
/>
|
|
{preview && (
|
|
<Button
|
|
variant="danger"
|
|
onClick={handleRemoveImage}
|
|
className="flex-shrink-0"
|
|
>
|
|
<i className="bi bi-trash"></i>
|
|
</Button>
|
|
)}
|
|
</div>
|
|
{preview && showPreview && (
|
|
<div className="d-flex justify-content-center">
|
|
<Image
|
|
src={preview}
|
|
alt="Previsualización"
|
|
className="img-fluid rounded"
|
|
width={600}
|
|
height={300}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|