import '@material/mwc-dialog'; import '@material/mwc-fab'; import '@material/mwc-snackbar'; import type { TextFieldInputMode, TextFieldType } from '@material/mwc-textfield/mwc-textfield-base'; import type {Cash} from 'cash-dom/dist/cash'; import collect, {Collection} from 'collect.js'; import {Children} from 'mithril'; import {Model} from '../../Models'; import { isFormValid, showSnackbar } from '../../utils'; import type { TextArea, TextField } from '../../WebComponents'; import DataTable from '../DataTable/DataTable.jsx'; import TableBody from '../DataTable/TableBody.jsx'; import TableCell from '../DataTable/TableCell.jsx'; import TableHead from '../DataTable/TableHead.jsx'; import TableHeadCell from '../DataTable/TableHeadCell.jsx'; import TableHeadRow from '../DataTable/TableHeadRow.jsx'; import TableRow from '../DataTable/TableRow.jsx'; import { Cell, LayoutGrid, Row } from '../Grid'; import LoadingButton from '../LoadingButton.jsx'; import Mdi from '../Mdi.jsx'; import Page from '../Page.jsx'; export type ColumnT = { id?: string, title: string, type?: 'checkbox' | 'numeric' } export type FieldT = { id?: string, value?: string, type?: TextFieldType, label?: string, placeholder?: string, prefix?: string, suffix?: string, icon?: string, iconTrailing?: string, disabled?: boolean, charCounter?: boolean, outlined?: boolean, helper?: string, helperPersistent?: boolean | string, required?: boolean, minLength?: number, maxLength?: number, validationMessage?: string, pattern?: string, min?: number | string, max?: number | string, size?: number | null, step?: number | null, autoValidate?: boolean, validity?: ValidityState, willValidate?: boolean, validityTransform?: (value: string, nativeValidity: ValidityState) => Partial | null, validateOnInitialRender?: boolean, name?: string, inputMode?: TextFieldInputMode, readOnly?: boolean, autocapitalize: 'on' | 'off' | 'sentences' | 'none' | 'words' | 'characters', endAligned?: boolean, ... }; export type SectionT = FieldT[] | { id?: string, heading?: string, columns?: number, fields: FieldT[] | { [string]: FieldT } }; /** * @abstract */ export default class RecordsPage extends Page { columns: { [string]: [string] | ColumnT } | ColumnT[]; rows: Collection = collect({}); sections: { [string]: SectionT } | SectionT[]; dialogs: Children[]; recordDialogMaxWidth: string | number = '75%'; model: Model; async oninit(vnode) { // noinspection JSUnresolvedFunction vnode.state.data = (await this.model.all()).getData(); if (vnode.state.data) { for (const record of vnode.state.data) { this.rows.put(record.id, record); } m.redraw(); } } async onupdate(vnode) { const rows = $('.mdc-data-table__row[data-model-id]'); if (rows.length > 0) { rows.on( 'click', (event: PointerEvent) => { this.updateRecord($(event.target) .parent('tr') .data('model-id')); } ); } } tableColumns(): Children { return collect(this.columns) .map( (column: ColumnT | string, id: string) => ( {typeof column === 'string' ? column : column.title} ) ) .toArray(); } tableRows(): Children { if (this.rows.isEmpty()) { return ( {__('Non sono presenti dati')} ); } return this.rows.map((row: Model, index) => { const cells = []; // eslint-disable-next-line guard-for-in for (const attribute in this.columns) { cells.push(row[attribute]); } return ( {cells.map((cell: string, index_) => {cell})} ); }) .toArray(); } async updateRecord(id: number) { // noinspection JSUnresolvedFunction const instance: Model = (await this.model.find(id)).getData(); const dialog = $('mwc-dialog#add-record-dialog'); // eslint-disable-next-line sonarjs/no-duplicate-string dialog.find('text-field, text-area') .each((index, field: TextField | TextArea) => { field.value = instance[field.id]; }); dialog.find('mwc-button#delete-button') .show() .on('click', () => { const confirmDialog = $('mwc-dialog#confirm-delete-record-dialog'); const confirmButton = confirmDialog.find('mwc-button#confirm-button'); const loading: Cash = confirmButton.find('mwc-circular-progress'); confirmButton.on('click', async () => { loading.show(); await instance.delete(); this.rows.forget(instance.id); m.redraw(); await showSnackbar(__('Record eliminato!'), 4000); }); loading.hide(); confirmDialog.get(0) .show(); }); dialog.get(0) .show(); } recordDialog() { return (
); } deleteRecordDialog(): Children { return (

{__('Sei sicuro di voler eliminare questo record?')}

); } view(vnode) { return ( <>

{this.title}

{this.tableColumns()} {this.tableRows()} {this.recordDialog()} {this.deleteRecordDialog()} {this.dialogs} ); } oncreate(vnode) { super.oncreate(vnode); const fab: Cash = $('mwc-fab#add-record'); const dialog: Cash = fab.next('mwc-dialog#add-record-dialog'); const form: Cash = dialog.find('form'); fab.on('click', () => { form.find('text-field, text-area') .each((index, field) => { field.value = $(field) .data('default-value'); }); dialog.find('mwc-button[type="submit"] mwc-circular-progress') .hide(); dialog.find('mwc-button#delete-button') .hide(); dialog.get(0) .show(); }); const button = dialog.find('mwc-button[type="submit"]'); button.on('click', () => { form.trigger('submit'); }); const loading: Cash = button.find('mwc-circular-progress'); form.on('submit', async (event) => { event.preventDefault(); loading.show(); if (isFormValid(form)) { // eslint-disable-next-line new-cap const instance: Model = new this.model(); form.find('text-field, text-area') .each((index, field: TextField | TextArea) => { instance[field.id] = field.value; }); const response = await instance.save(); if (response.getModelId()) { dialog.get(0) .close(); const model = response.getModel(); this.rows.put(model.id, model); m.redraw(); await showSnackbar(__('Record salvato'), 4000); } } else { loading.hide(); await showSnackbar(__('Campi non validi. Controlla i dati inseriti')); } }); } }