-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #67 from consiglionazionaledellericerche/42-implem…
…entare-pagina-buoni-pasto implementata pagina e componenti per la visualizzazione della situazione buoni pasto
- Loading branch information
Showing
14 changed files
with
982 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { Table, Button } from "react-bootstrap"; | ||
import DataTable from 'react-data-table-component'; | ||
import { BlockMealTicket } from "../../types/blockMealTicket"; | ||
|
||
interface MealTicketsTableProps { | ||
data: BlockMealTicket[] ; | ||
} | ||
|
||
const MealTicketsTable: React.FC<MealTicketsTableProps> = ({ | ||
data | ||
}) => { | ||
// Stato per i dati e il caricamento | ||
const [loading, setLoading] = useState<boolean>(true); | ||
const [error, setError] = useState<string | null>(null); | ||
const [searchTerm, setSearchTerm] = useState(''); | ||
const [rowsPerPage, setRowsPerPage] = useState(10); | ||
const [currentPage, setCurrentPage] = useState(1); | ||
const [totalRows, setTotalRows] = useState(0); | ||
|
||
const columns = [ | ||
{ | ||
name: <strong>Codice</strong>, | ||
selector: (row: any) => ( | ||
<> | ||
<strong>{row.codeBlock}</strong> ({row.first}-{row.last}) | ||
</> | ||
), | ||
sortable: true, | ||
}, | ||
{ | ||
name: <strong>Consegnato il</strong>, | ||
selector: (row: any) => row.getReceivedDate, | ||
sortable: true, | ||
}, | ||
{ | ||
name: <strong>Scadenza</strong>, | ||
selector: (row: any) => row.getExpireDate, | ||
sortable: true, | ||
}, | ||
{ | ||
name: <strong>Maturati</strong>, | ||
selector: (row: any) => ( | ||
<> | ||
<h5 className="text-danger"><strong>{row.getConsumed}</strong></h5> | ||
</> | ||
), | ||
sortable: true, | ||
}, | ||
{ | ||
name: <strong>Da Maturare</strong>, | ||
selector: (row: any) => ( | ||
<> | ||
<h5 className="text-success"><strong>{row.getRemaining}</strong></h5> | ||
</> | ||
), | ||
sortable: true, | ||
}, | ||
]; | ||
|
||
const filteredData = data.filter(item => | ||
item.codeBlock?.toLowerCase().includes(searchTerm.toLowerCase()) | ||
); | ||
|
||
const paginatedData = filteredData.slice((currentPage - 1) * rowsPerPage, currentPage * rowsPerPage); | ||
|
||
const handlePageChange = (page: number) => { | ||
setCurrentPage(page); | ||
}; | ||
|
||
const handleRowsPerPageChange = (newRowsPerPage: number) => { | ||
setRowsPerPage(newRowsPerPage); | ||
setCurrentPage(1); | ||
}; | ||
|
||
const paginationComponentOptions = { | ||
rowsPerPageText: 'Elementi per pagina', | ||
rangeSeparatorText: 'di', | ||
selectAllRowsItem: true, | ||
selectAllRowsItemText: 'Tutti', | ||
}; | ||
|
||
return ( | ||
<div> | ||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}> | ||
<div> | ||
<span>Visualizza</span> | ||
<select | ||
value={rowsPerPage} | ||
onChange={(e) => handleRowsPerPageChange(Number(e.target.value))} | ||
style={{ marginLeft: '5px' }} | ||
> | ||
<option value={10}>10</option> | ||
<option value={20}>20</option> | ||
<option value={30}>30</option> | ||
</select> | ||
<span style={{ marginLeft: '5px' }}>elementi</span> | ||
</div> | ||
<input | ||
type="text" | ||
placeholder="Cerca" | ||
value={searchTerm} | ||
onChange={(e) => setSearchTerm(e.target.value)} | ||
style={{ marginRight: '5px' }} | ||
/> | ||
</div> | ||
<DataTable | ||
className="table datatable-mealTicket table-condensed center" | ||
columns={columns} | ||
data={paginatedData} | ||
pagination | ||
paginationServer | ||
paginationTotalRows={filteredData.length} | ||
paginationPerPage={rowsPerPage} | ||
paginationDefaultPage={currentPage} | ||
onChangePage={handlePageChange} | ||
paginationComponentOptions={paginationComponentOptions} | ||
highlightOnHover | ||
/> | ||
<div style={{ marginTop: '20px' }}> | ||
Vista da {(currentPage - 1) * rowsPerPage + 1} a {Math.min(currentPage * rowsPerPage, filteredData.length)} di {filteredData.length} elementi (filtrati da {totalRows} elementi totali) | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default MealTicketsTable; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Col, Container, Row } from "react-bootstrap"; | ||
import MealTicketsTable from "./mealTicketsTable"; | ||
import { MealTicketRecapShow } from "../../types/mealTicketRecapShow"; | ||
import DateUtility from "../../utils/dateUtility"; | ||
import { faLightbulb } from "@fortawesome/free-solid-svg-icons" | ||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" | ||
|
||
interface MealTicketsViewProps { | ||
mealTicketsData: MealTicketRecapShow | ||
} | ||
|
||
const MealTicketsView: React.FC<MealTicketsViewProps> = ({ | ||
mealTicketsData | ||
}) => { | ||
|
||
let fullname = <span>{mealTicketsData.person?.surname} {mealTicketsData.person?.name}</span>; | ||
let recap = mealTicketsData.recap; | ||
let messageDateRunOut = recap?.dateRunOut ? ( | ||
<> | ||
<div className="alert alert-danger"> | ||
<p>Tutti i buoni pasto consegnati sono stati maturati in data {DateUtility.formatDateLocal(recap?.dateRunOut)}.</p> | ||
<p>Sono stati maturati <strong>{recap?.remaining}</strong> buoni pasto oltre quelli consegnati.</p> | ||
<p>Contattare l'amministrazione per ricevere i nuovi blocchetti.</p></div> | ||
</>) : | ||
(<> | ||
<div className="alert alert-success"> | ||
<p>Rimangono <strong>{recap?.remaining}</strong> buoni pasto consegnati ancora da maturare.</p> | ||
</div> | ||
</>); | ||
let messageInfo = <> | ||
<div className="alert alert-info"> | ||
<p>Elenco dei blocchi consegnati a <strong>{fullname}</strong>.</p> | ||
<p>I valori <strong>Maturati / Da Maturare</strong> sono puramente indicativi e sono ottenuti calcolando i buoni pasto maturati | ||
partendo da quelli con scadenza più imminente e dal codice progressivo minore.</p> | ||
|
||
<p><FontAwesomeIcon icon={faLightbulb} /> Cliccando sui titoli delle colonne è possibile ordinare | ||
i blocchi consegnati per <em>Codice Blocco</em>, <em>Data Consegna</em>, <em>Data Scadenza</em> e <em>Maturati/Da Maturare</em> | ||
</p> | ||
</div> | ||
</> | ||
return ( | ||
<> | ||
<Container fluid> | ||
<Row> | ||
<Col sm={1} /> | ||
<Col sm={9}> | ||
<div className="page-header"> | ||
<h2>Riepilogo Buoni Pasto {fullname}</h2> | ||
<br/> | ||
</div> | ||
{messageDateRunOut} | ||
{messageInfo} | ||
{recap?.blockMealTicketReceivedDeliveryDesc && ( | ||
<MealTicketsTable data={recap.blockMealTicketReceivedDeliveryDesc} /> | ||
)} | ||
</Col> | ||
<Col sm={2} /> | ||
</Row> | ||
</Container> | ||
</> | ||
); | ||
} | ||
|
||
export default MealTicketsView |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import Modal from 'react-bootstrap/Modal'; | ||
import Button from 'react-bootstrap/Button'; | ||
import TrainingHoursModalContent from './trainingHoursModalContent'; | ||
import { secureCheck } from '../../../utils/secureCheck'; | ||
|
||
interface TrainingHoursModalProps { | ||
tmpshow: boolean; | ||
close: Function; | ||
parameters: any; | ||
showError: (message: string) => void; | ||
showSuccess: (message: string) => void; | ||
} | ||
|
||
const TrainingHoursModal: React.FC<TrainingHoursModalProps> = ({ | ||
tmpshow, | ||
close, | ||
parameters, | ||
showError, | ||
showSuccess | ||
}) => { | ||
const [show, setShow] = useState(false); | ||
const [dataTraining, setDataTraining] = useState<any>(null); | ||
const [titleModal, setTitle] = useState(""); | ||
|
||
useEffect(() => { | ||
let title = ""; | ||
if (parameters.action === 'insert' || parameters.action === 'edit') { | ||
title = `Ore formazione ${parameters.month.name} ${parameters.year}`; | ||
} else { | ||
title = `Elimina ore di formazione`; | ||
} | ||
setTitle(title); | ||
}, [parameters.action]); | ||
|
||
|
||
useEffect(() => { | ||
if (tmpshow) { | ||
// Verifica della sicurezza e caricamento dati | ||
async function getData() { | ||
setShow(true); | ||
} | ||
getData(); | ||
} else { | ||
setShow(false); | ||
} | ||
}, [tmpshow, parameters]); | ||
|
||
const handleClose = () => { | ||
setShow(false); | ||
close(); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Modal | ||
show={show} | ||
onHide={handleClose} | ||
size="xl" | ||
aria-labelledby="modal-absence-info" | ||
> | ||
<Modal.Header closeButton> | ||
<Modal.Title>{titleModal}</Modal.Title> | ||
</Modal.Header> | ||
<Modal.Body> | ||
{show && <TrainingHoursModalContent | ||
year={parameters.year} | ||
month={parameters.month} | ||
action={parameters.action} | ||
pm={parameters} | ||
handleClose={handleClose} | ||
showError={showError} | ||
showSuccess={showSuccess} | ||
/>} | ||
</Modal.Body> | ||
</Modal> | ||
</> | ||
); | ||
} | ||
|
||
export default TrainingHoursModal; |
Oops, something went wrong.