Manage Absences - Copy this React, Tailwind Component to your project
Import React, { useState, useEffect } from "react"; import { Table, Button, Offcanvas, Form, InputGroup, FormControl, Dropdown, } from "react bootstrap"; import Swal from "sweetalert2"; import config from "../config/config"; const ManageAbsences = () => { const [absences, setAbsences] = useState([]); const [employees, setEmployees] = useState([]); const [filteredAbsences, setFilteredAbsences] = useState([]); const [searchTerm, setSearchTerm] = useState(""); const [showCanvas, setShowCanvas] = useState(false); const [editingAbsence, setEditingAbsence] = useState(null); // For create or update const [absenceData, setAbsenceData] = useState({ rut_employee: "", from_date_absence: "", to_date_absence: "", type_absence: "", justification_status: "", reason: "", }); useEffect(() => { fetchAbsences(); fetchEmployees(); }, []); const fetchAbsences = () => { fetch(`${config.apiUrl}/ausencias`) .then((res) => res.json()) .then((data) => setAbsences(data)) .catch(() => Swal.fire("Error", "No se pudo cargar las ausencias.", "error")); }; const fetchEmployees = () => { fetch(`${config.apiUrl}/lista empleados`) .then((res) => res.json()) .then((data) => setEmployees(data)) .catch(() => Swal.fire("Error", "No se pudo cargar la lista de empleados.", "error") ); }; const handleSearch = (e) => { const value = e.target.value.trim(); setSearchTerm(value); if (value) { const isRut = /^[0 9]+$/.test(value); const filtered = absences.filter((absence) => isRut ? absence.rut_employee.includes(value) : employees.some( (emp) => emp.rut === absence.rut_employee && `${emp.nombre} ${emp.apellido}` .toLowerCase() .includes(value.toLowerCase()) ) ); setFilteredAbsences(filtered); } else { setFilteredAbsences(absences); } }; const resetSearch = () => { setSearchTerm(""); setFilteredAbsences(absences); }; const handleCreateOrUpdate = () => { const method = editingAbsence ? "PUT" : "POST"; const url = editingAbsence ? `${config.apiUrl}/actualizar ausencia/${editingAbsence.id_absence}` : `${config.apiUrl}/crear ausencia`; fetch(url, { method, headers: { "Content Type": "application/json" }, body: JSON.stringify(absenceData), }) .then((res) => res.json()) .then((data) => { if (data.success) { Swal.fire("Éxito", data.message, "success"); fetchAbsences(); setShowCanvas(false); setEditingAbsence(null); setAbsenceData({ rut_employee: "", from_date_absence: "", to_date_absence: "", type_absence: "", justification_status: "", reason: "", }); } else { Swal.fire("Error", data.message, "error"); } }) .catch(() => Swal.fire( "Error", "No se pudo procesar la solicitud. Inténtalo nuevamente.", "error" ) ); }; const handleEdit = (absence) => { setEditingAbsence(absence); setAbsenceData({ ...absence }); setShowCanvas(true); }; const handleDelete = (id_absence) => { Swal.fire({ title: "¿Estás seguro?", text: "Esta acción eliminará la ausencia permanentemente.", icon: "warning", showCancelButton: true, confirmButtonText: "Sí, eliminar", cancelButtonText: "Cancelar", }).then((result) => { if (result.isConfirmed) { fetch(`${config.apiUrl}/eliminar ausencia/${id_absence}`, { method: "DELETE", }) .then((res) => res.json()) .then((data) => { if (data.success) { Swal.fire("Eliminado", data.message, "success"); fetchAbsences(); } else { Swal.fire("Error", data.message, "error"); } }) .catch(() => Swal.fire("Error", "Hubo un problema al eliminar la ausencia.", "error") ); } }); }; return ( <> <div style={{ display: "flex", justifyContent: "space between", alignItems: "center", }} > <h2>Gestión de Ausencias</h2> <InputGroup style={{ width: "300px", position: "relative" }}> <FormControl placeholder="Buscar por nombre o RUT" value={searchTerm} onChange={handleSearch} /> <Button variant="outline secondary" onClick={resetSearch}> Quitar Filtro </Button> </InputGroup> </div> <Table striped bordered hover> <thead> <tr> <th>RUT</th> <th>Nombre</th> <th>Desde</th> <th>Hasta</th> <th>Tipo</th> <th>Justificación</th> <th>Razón</th> <th>Acciones</th> </tr> </thead> <tbody> {filteredAbsences.map((absence) => { const employee = employees.find( (emp) => emp.rut === absence.rut_employee ); return ( <tr key={absence.id_absence}> <td>{absence.rut_employee}</td> <td>{employee ? `${employee.nombre} ${employee.apellido}` : ""}</td> <td>{absence.from_date_absence}</td> <td>{absence.to_date_absence}</td> <td>{absence.type_absence}</td> <td>{absence.justification_status}</td> <td>{absence.reason}</td> <td> <Button variant="outline info" onClick={() => handleEdit(absence)} style={{ marginRight: "5px" }} > Editar </Button> <Button variant="outline danger" onClick={() => handleDelete(absence.id_absence)} > Eliminar </Button> </td> </tr> ); })} </tbody> </Table> <Button variant="primary" onClick={() => { setEditingAbsence(null); setAbsenceData({ rut_employee: "", from_date_absence: "", to_date_absence: "", type_absence: "", justification_status: "", reason: "", }); setShowCanvas(true); }} > Crear Ausencia </Button> <Offcanvas show={showCanvas} onHide={() => setShowCanvas(false)} placement="end"> <Offcanvas.Header closeButton> <Offcanvas.Title> {editingAbsence ? "Actualizar Ausencia" : "Crear Ausencia"} </Offcanvas.Title> </Offcanvas.Header> <Offcanvas.Body> <Form> <Form.Group> <Form.Label>Empleado</Form.Label> <Form.Control as="select" value={absenceData.rut_employee} onChange={(e) => setAbsenceData({ ...absenceData, rut_employee: e.target.value }) } > <option value="">Selecciona un empleado</option> {employees.map((emp) => ( <option key={emp.rut} value={emp.rut}> {`${emp.nombre} ${emp.apellido}`} {emp.rut} </option> ))} </Form.Control> </Form.Group> <Form.Group> <Form.Label>Desde</Form.Label> <Form.Control type="date" value={absenceData.from_date_absence} onChange={(e) => setAbsenceData({ ...absenceData, from_date_absence: e.target.value }) } /> </Form.Group> <Form.Group> <Form.Label>Hasta</Form.Label> <Form.Control type="date" value={absenceData.to_date_absence} onChange={(e) => setAbsenceData({ ...absenceData, to_date_absence: e.target.value }) } /> </Form.Group> <Form.Group> <Form.Label>Tipo de Ausencia</Form.Label> <Form.Control type="text" value={absenceData.type_absence} onChange={(e) => setAbsenceData({ ...absenceData, type_absence: e.target.value }) } /> </Form.Group> <Form.Group> <Form.Label>Justificación</Form.Label> <Form.Control type="text" value={absenceData.justification_status} onChange={(e) => setAbsenceData({ ...absenceData, justification_status: e.target.value, }) } /> </Form.Group> <Form.Group> <Form.Label>Razón</Form.Label> <Form.Control as="textarea" rows={3} value={absenceData.reason} onChange={(e) => setAbsenceData({ ...absenceData, reason: e.target.value }) } /> </Form.Group> </Form> <div className="mt 3"> <Button variant="primary" onClick={handleCreateOrUpdate}> {editingAbsence ? "Actualizar" : "Crear"} </Button> </div> </Offcanvas.Body> </Offcanvas> </> ); }; export default ManageAbsences; Como mejorarías este componente? Ya no quiero usar react bootstrap, solamente tailwind para los estilos. #07143d,#d1d5db,#1f2937 usa esos colores, y crea un componente bonito.
