@ifto/mantine-kit 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +475 -2
- package/dist/component/atom/AppMain/App.module.js +7 -0
- package/dist/component/atom/AppMain/App.module.js.map +1 -0
- package/dist/component/atom/AppMain/AppMain.d.ts +7 -0
- package/dist/component/atom/AppMain/AppMain.js +14 -0
- package/dist/component/atom/AppMain/AppMain.js.map +1 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.d.ts +6 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.js +24 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.js.map +1 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.d.ts +13 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.js +30 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.js.map +1 -0
- package/dist/component/atom/DateField/DateField.d.ts +7 -0
- package/dist/component/atom/DateField/DateField.js +21 -0
- package/dist/component/atom/DateField/DateField.js.map +1 -0
- package/dist/component/atom/EditValueButton/EditValueButton.d.ts +6 -0
- package/dist/component/atom/EditValueButton/EditValueButton.js +24 -0
- package/dist/component/atom/EditValueButton/EditValueButton.js.map +1 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.d.ts +8 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.js +21 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.js.map +1 -0
- package/dist/component/atom/Surface/Surface.d.ts +20 -0
- package/dist/component/atom/Surface/Surface.js +15 -0
- package/dist/component/atom/Surface/Surface.js.map +1 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.d.ts +12 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.js +38 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.js.map +1 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.d.ts +25 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.js +49 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.js.map +1 -0
- package/dist/component/molecule/PaperCard/PaperCard.d.ts +7 -0
- package/dist/component/molecule/PaperCard/PaperCard.js +17 -0
- package/dist/component/molecule/PaperCard/PaperCard.js.map +1 -0
- package/dist/component/molecule/PrintSection/PrintSection.d.ts +14 -0
- package/dist/component/molecule/PrintSection/PrintSection.js +29 -0
- package/dist/component/molecule/PrintSection/PrintSection.js.map +1 -0
- package/dist/component/molecule/SelectField/SelectField.d.ts +32 -0
- package/dist/component/molecule/SelectField/SelectField.js +38 -0
- package/dist/component/molecule/SelectField/SelectField.js.map +1 -0
- package/dist/component/molecule/StatsCard/Stats.module.js +15 -0
- package/dist/component/molecule/StatsCard/Stats.module.js.map +1 -0
- package/dist/component/molecule/StatsCard/StatsCard.d.ts +18 -0
- package/dist/component/molecule/StatsCard/StatsCard.js +60 -0
- package/dist/component/molecule/StatsCard/StatsCard.js.map +1 -0
- package/dist/component/organism/DataForm/DataForm.d.ts +26 -0
- package/dist/component/organism/DataForm/DataForm.js +83 -0
- package/dist/component/organism/DataForm/DataForm.js.map +1 -0
- package/dist/component/organism/DataTabList/DataTabList.d.ts +24 -0
- package/dist/component/organism/DataTabList/DataTabList.js +37 -0
- package/dist/component/organism/DataTabList/DataTabList.js.map +1 -0
- package/dist/component/organism/DataTabList/DataTabList.module.js +13 -0
- package/dist/component/organism/DataTabList/DataTabList.module.js.map +1 -0
- package/dist/component/organism/EChart/EChart.d.ts +47 -0
- package/dist/component/organism/EChart/EChart.js +37 -0
- package/dist/component/organism/EChart/EChart.js.map +1 -0
- package/dist/component/organism/EChart/buildEChartOption.d.ts +40 -0
- package/dist/component/organism/EChart/buildEChartOption.js +57 -0
- package/dist/component/organism/EChart/buildEChartOption.js.map +1 -0
- package/dist/component/organism/EChart/chart/BarChart.d.ts +22 -0
- package/dist/component/organism/EChart/chart/BarChart.js +34 -0
- package/dist/component/organism/EChart/chart/BarChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/CartesianChart.d.ts +48 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js +63 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartHeader.d.ts +36 -0
- package/dist/component/organism/EChart/chart/ChartHeader.js +105 -0
- package/dist/component/organism/EChart/chart/ChartHeader.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartSeries.d.ts +50 -0
- package/dist/component/organism/EChart/chart/ChartSeries.js +23 -0
- package/dist/component/organism/EChart/chart/ChartSeries.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartTexts.d.ts +12 -0
- package/dist/component/organism/EChart/chart/ChartTexts.js +21 -0
- package/dist/component/organism/EChart/chart/ChartTexts.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartType.d.ts +50 -0
- package/dist/component/organism/EChart/chart/ChartType.js +1 -0
- package/dist/component/organism/EChart/chart/ChartTypeId.d.ts +2 -0
- package/dist/component/organism/EChart/chart/ChartTypeId.js +1 -0
- package/dist/component/organism/EChart/chart/ChartTypes.d.ts +15 -0
- package/dist/component/organism/EChart/chart/ChartTypes.js +24 -0
- package/dist/component/organism/EChart/chart/ChartTypes.js.map +1 -0
- package/dist/component/organism/EChart/chart/DonutChart.d.ts +32 -0
- package/dist/component/organism/EChart/chart/DonutChart.js +111 -0
- package/dist/component/organism/EChart/chart/DonutChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/LineChart.d.ts +11 -0
- package/dist/component/organism/EChart/chart/LineChart.js +20 -0
- package/dist/component/organism/EChart/chart/LineChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.d.ts +15 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js +30 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/UnitPanels.d.ts +63 -0
- package/dist/component/organism/EChart/chart/UnitPanels.js +127 -0
- package/dist/component/organism/EChart/chart/UnitPanels.js.map +1 -0
- package/dist/component/organism/EChart/echartDefaults.d.ts +32 -0
- package/dist/component/organism/EChart/echartDefaults.js +47 -0
- package/dist/component/organism/EChart/echartDefaults.js.map +1 -0
- package/dist/component/organism/EChart/useEChart.d.ts +35 -0
- package/dist/component/organism/EChart/useEChart.js +112 -0
- package/dist/component/organism/EChart/useEChart.js.map +1 -0
- package/dist/component/organism/Navbar/NavItem.d.ts +16 -0
- package/dist/component/organism/Navbar/NavItem.js +1 -0
- package/dist/component/organism/Navbar/Navbar.d.ts +20 -0
- package/dist/component/organism/Navbar/Navbar.js +64 -0
- package/dist/component/organism/Navbar/Navbar.js.map +1 -0
- package/dist/component/organism/Navbar/Navbar.module.js +19 -0
- package/dist/component/organism/Navbar/Navbar.module.js.map +1 -0
- package/dist/component/organism/PageHeader/PageHeader.d.ts +14 -0
- package/dist/component/organism/PageHeader/PageHeader.js +55 -0
- package/dist/component/organism/PageHeader/PageHeader.js.map +1 -0
- package/dist/component/organism/StatsGrid/StatsGrid.d.ts +12 -0
- package/dist/component/organism/StatsGrid/StatsGrid.js +46 -0
- package/dist/component/organism/StatsGrid/StatsGrid.js.map +1 -0
- package/dist/component/organism/StatsGrid/StatsGrid.module.js +17 -0
- package/dist/component/organism/StatsGrid/StatsGrid.module.js.map +1 -0
- package/dist/component/organism/Table/RowActions.d.ts +23 -0
- package/dist/component/organism/Table/RowActions.js +121 -0
- package/dist/component/organism/Table/RowActions.js.map +1 -0
- package/dist/component/organism/Table/Table.d.ts +51 -0
- package/dist/component/organism/Table/Table.js +110 -0
- package/dist/component/organism/Table/Table.js.map +1 -0
- package/dist/component/organism/ViewTable/ColumnComparator.d.ts +11 -0
- package/dist/component/organism/ViewTable/ColumnComparator.js +25 -0
- package/dist/component/organism/ViewTable/ColumnComparator.js.map +1 -0
- package/dist/component/organism/ViewTable/ViewTable.d.ts +53 -0
- package/dist/component/organism/ViewTable/ViewTable.js +115 -0
- package/dist/component/organism/ViewTable/ViewTable.js.map +1 -0
- package/dist/component/organism/ViewTable/useRowKey.d.ts +8 -0
- package/dist/component/organism/ViewTable/useRowKey.js +24 -0
- package/dist/component/organism/ViewTable/useRowKey.js.map +1 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.d.ts +19 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.js +41 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.js.map +1 -0
- package/dist/component/template/EditFormPage/EditFormPage.d.ts +19 -0
- package/dist/component/template/EditFormPage/EditFormPage.js +42 -0
- package/dist/component/template/EditFormPage/EditFormPage.js.map +1 -0
- package/dist/component/template/FormPage/FormPage.d.ts +25 -0
- package/dist/component/template/FormPage/FormPage.js +130 -0
- package/dist/component/template/FormPage/FormPage.js.map +1 -0
- package/dist/component/template/FormPage/FormType.d.ts +6 -0
- package/dist/component/template/FormPage/FormType.js +12 -0
- package/dist/component/template/FormPage/FormType.js.map +1 -0
- package/dist/component/template/Layout/Layout.d.ts +21 -0
- package/dist/component/template/Layout/Layout.js +121 -0
- package/dist/component/template/Layout/Layout.js.map +1 -0
- package/dist/component/template/Layout/Layout.module.js +19 -0
- package/dist/component/template/Layout/Layout.module.js.map +1 -0
- package/dist/component/template/ListPage/ListPage.d.ts +32 -0
- package/dist/component/template/ListPage/ListPage.js +47 -0
- package/dist/component/template/ListPage/ListPage.js.map +1 -0
- package/dist/component/template/PrintPage/PrintPage.d.ts +25 -0
- package/dist/component/template/PrintPage/PrintPage.js +115 -0
- package/dist/component/template/PrintPage/PrintPage.js.map +1 -0
- package/dist/component/template/ViewPage/ViewPage.d.ts +11 -0
- package/dist/component/template/ViewPage/ViewPage.js +49 -0
- package/dist/component/template/ViewPage/ViewPage.js.map +1 -0
- package/dist/data/ListDataSource.d.ts +12 -0
- package/dist/data/ListDataSource.js +1 -0
- package/dist/data/SaveDataSource.d.ts +16 -0
- package/dist/data/SaveDataSource.js +1 -0
- package/dist/export/ExportCellText.d.ts +18 -0
- package/dist/export/ExportCellText.js +60 -0
- package/dist/export/ExportCellText.js.map +1 -0
- package/dist/export/ExportDocument.d.ts +127 -0
- package/dist/export/ExportDocument.js +59 -0
- package/dist/export/ExportDocument.js.map +1 -0
- package/dist/export/ExportDownload.d.ts +9 -0
- package/dist/export/ExportDownload.js +19 -0
- package/dist/export/ExportDownload.js.map +1 -0
- package/dist/export/ExportFileName.d.ts +11 -0
- package/dist/export/ExportFileName.js +24 -0
- package/dist/export/ExportFileName.js.map +1 -0
- package/dist/export/ExportFormat.d.ts +30 -0
- package/dist/export/ExportFormat.js +1 -0
- package/dist/export/ExportFormats.d.ts +12 -0
- package/dist/export/ExportFormats.js +16 -0
- package/dist/export/ExportFormats.js.map +1 -0
- package/dist/export/ExportTexts.d.ts +14 -0
- package/dist/export/ExportTexts.js +23 -0
- package/dist/export/ExportTexts.js.map +1 -0
- package/dist/export/csv/CsvFormat.d.ts +41 -0
- package/dist/export/csv/CsvFormat.js +91 -0
- package/dist/export/csv/CsvFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxFormat.d.ts +35 -0
- package/dist/export/xlsx/XlsxFormat.js +66 -0
- package/dist/export/xlsx/XlsxFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxNumberFormat.d.ts +8 -0
- package/dist/export/xlsx/XlsxNumberFormat.js +15 -0
- package/dist/export/xlsx/XlsxNumberFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxSheetName.d.ts +12 -0
- package/dist/export/xlsx/XlsxSheetName.js +62 -0
- package/dist/export/xlsx/XlsxSheetName.js.map +1 -0
- package/dist/export/xlsx/XlsxSheetWriter.d.ts +67 -0
- package/dist/export/xlsx/XlsxSheetWriter.js +215 -0
- package/dist/export/xlsx/XlsxSheetWriter.js.map +1 -0
- package/dist/export/xlsx/XlsxStyle.d.ts +51 -0
- package/dist/export/xlsx/XlsxStyle.js +87 -0
- package/dist/export/xlsx/XlsxStyle.js.map +1 -0
- package/dist/hook/useIsMobile.d.ts +5 -0
- package/dist/hook/useIsMobile.js +16 -0
- package/dist/hook/useIsMobile.js.map +1 -0
- package/dist/hook/useKeyedService.d.ts +22 -0
- package/dist/hook/useKeyedService.js +38 -0
- package/dist/hook/useKeyedService.js.map +1 -0
- package/dist/hook/useLightColorSchemeOnPrint.d.ts +9 -0
- package/dist/hook/useLightColorSchemeOnPrint.js +36 -0
- package/dist/hook/useLightColorSchemeOnPrint.js.map +1 -0
- package/dist/hook/useService.d.ts +27 -0
- package/dist/hook/useService.js +23 -0
- package/dist/hook/useService.js.map +1 -0
- package/dist/http/ApiError.d.ts +13 -0
- package/dist/http/ApiError.js +22 -0
- package/dist/http/ApiError.js.map +1 -0
- package/dist/http/AxiosHttpClient.d.ts +21 -0
- package/dist/http/AxiosHttpClient.js +67 -0
- package/dist/http/AxiosHttpClient.js.map +1 -0
- package/dist/http/AxiosHttpClientConfig.d.ts +37 -0
- package/dist/http/AxiosHttpClientConfig.js +19 -0
- package/dist/http/AxiosHttpClientConfig.js.map +1 -0
- package/dist/i18n/KitLocale.d.ts +4 -0
- package/dist/i18n/KitLocale.js +7 -0
- package/dist/i18n/KitLocale.js.map +1 -0
- package/dist/i18n/KitMessages.d.ts +146 -0
- package/dist/i18n/KitMessages.js +1 -0
- package/dist/i18n/messages/enUS.d.ts +3 -0
- package/dist/i18n/messages/enUS.js +112 -0
- package/dist/i18n/messages/enUS.js.map +1 -0
- package/dist/i18n/messages/ptBR.d.ts +3 -0
- package/dist/i18n/messages/ptBR.js +97 -0
- package/dist/i18n/messages/ptBR.js.map +1 -0
- package/dist/i18n/resolveMessages.d.ts +13 -0
- package/dist/i18n/resolveMessages.js +29 -0
- package/dist/i18n/resolveMessages.js.map +1 -0
- package/dist/model/Identifiable.d.ts +7 -0
- package/dist/model/Identifiable.js +1 -0
- package/dist/provider/KitConfig.d.ts +26 -0
- package/dist/provider/KitConfig.js +1 -0
- package/dist/provider/KitContext.d.ts +9 -0
- package/dist/provider/KitContext.js +27 -0
- package/dist/provider/KitContext.js.map +1 -0
- package/dist/provider/KitProvider.d.ts +7 -0
- package/dist/provider/KitProvider.js +31 -0
- package/dist/provider/KitProvider.js.map +1 -0
- package/dist/provider/useKit.d.ts +15 -0
- package/dist/provider/useKit.js +28 -0
- package/dist/provider/useKit.js.map +1 -0
- package/dist/router/FormRouteSegments.d.ts +16 -0
- package/dist/router/FormRouteSegments.js +19 -0
- package/dist/router/FormRouteSegments.js.map +1 -0
- package/dist/router/RouterAdapter.d.ts +24 -0
- package/dist/router/RouterAdapter.js +1 -0
- package/dist/router/anchorRouter.d.ts +7 -0
- package/dist/router/anchorRouter.js +23 -0
- package/dist/router/anchorRouter.js.map +1 -0
- package/dist/styles/print.css +93 -0
- package/dist/styles.css +188 -0
- package/dist/util/ArrayUtil.d.ts +39 -0
- package/dist/util/ArrayUtil.js +48 -0
- package/dist/util/ArrayUtil.js.map +1 -0
- package/dist/util/ColorUtil.d.ts +7 -0
- package/dist/util/ColorUtil.js +16 -0
- package/dist/util/ColorUtil.js.map +1 -0
- package/dist/util/CompareUtil.d.ts +19 -0
- package/dist/util/CompareUtil.js +51 -0
- package/dist/util/CompareUtil.js.map +1 -0
- package/dist/util/DateUtil.d.ts +38 -0
- package/dist/util/DateUtil.js +55 -0
- package/dist/util/DateUtil.js.map +1 -0
- package/dist/util/DownloadUtil.d.ts +6 -0
- package/dist/util/DownloadUtil.js +25 -0
- package/dist/util/DownloadUtil.js.map +1 -0
- package/dist/util/EnumUtil.d.ts +19 -0
- package/dist/util/EnumUtil.js +32 -0
- package/dist/util/EnumUtil.js.map +1 -0
- package/dist/util/FormUtil.d.ts +8 -0
- package/dist/util/FormUtil.js +14 -0
- package/dist/util/FormUtil.js.map +1 -0
- package/dist/util/HtmlUtil.d.ts +8 -0
- package/dist/util/HtmlUtil.js +23 -0
- package/dist/util/HtmlUtil.js.map +1 -0
- package/dist/util/Notifications.d.ts +30 -0
- package/dist/util/Notifications.js +59 -0
- package/dist/util/Notifications.js.map +1 -0
- package/dist/util/NumberUtil.d.ts +19 -0
- package/dist/util/NumberUtil.js +33 -0
- package/dist/util/NumberUtil.js.map +1 -0
- package/dist/util/ObjectUtil.d.ts +22 -0
- package/dist/util/ObjectUtil.js +34 -0
- package/dist/util/ObjectUtil.js.map +1 -0
- package/dist/util/SearchParamsUtil.d.ts +23 -0
- package/dist/util/SearchParamsUtil.js +29 -0
- package/dist/util/SearchParamsUtil.js.map +1 -0
- package/dist/util/TransformData.d.ts +14 -0
- package/dist/util/TransformData.js +31 -0
- package/dist/util/TransformData.js.map +1 -0
- package/dist/util/ValidationUtil.d.ts +9 -0
- package/dist/util/ValidationUtil.js +16 -0
- package/dist/util/ValidationUtil.js.map +1 -0
- package/dist/util/parseActionsPageParams.d.ts +14 -0
- package/dist/util/parseActionsPageParams.js +29 -0
- package/dist/util/parseActionsPageParams.js.map +1 -0
- package/package.json +158 -5
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useKitConfig } from "../../../provider/useKit.js";
|
|
3
|
+
import { columnComparator } from "./ColumnComparator.js";
|
|
4
|
+
import { useRowKey } from "./useRowKey.js";
|
|
5
|
+
import { useEffect, useMemo, useState } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { DataTable } from "mantine-datatable";
|
|
8
|
+
// src/component/organism/ViewTable/ViewTable.tsx
|
|
9
|
+
/** Options of records per page. The largest one lets long tables (and end-to-end tests) show every row in one page. */
|
|
10
|
+
var PAGE_SIZES = [
|
|
11
|
+
10,
|
|
12
|
+
20,
|
|
13
|
+
50,
|
|
14
|
+
200
|
|
15
|
+
];
|
|
16
|
+
/** Default sort when neither `defaultSortStatus` nor `compare` is given. */
|
|
17
|
+
var DEFAULT_SORT_STATUS = {
|
|
18
|
+
columnAccessor: "id",
|
|
19
|
+
direction: "asc"
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Sort used while the `compare` function applies, when `defaultSortStatus` is not given: it matches no column, so no
|
|
23
|
+
* header shows the sort indicator, and the first click on any column sorts it in ascending order.
|
|
24
|
+
*/
|
|
25
|
+
var NO_COLUMN_SORT_STATUS = {
|
|
26
|
+
columnAccessor: "",
|
|
27
|
+
direction: "asc"
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* The ViewTable component is a wrapper for the Mantine DataTable component.
|
|
31
|
+
* @template M - Model that extends from {@link Identifiable}
|
|
32
|
+
* @param data the data to be displayed in this ViewTable
|
|
33
|
+
* @param {DataTableColumn<M>[]} columns - The columns to be displayed in this ViewTable
|
|
34
|
+
* @param loading Indicates if the data to be displayed is being loaded yet or not
|
|
35
|
+
* @param pagination Indicates whether to show pagination or not.
|
|
36
|
+
* @param getPaginationControlProps extra attributes for the pagination control buttons
|
|
37
|
+
* @param compare comparison function of the initial order, replaced by the sort of the column chosen in the header
|
|
38
|
+
* @param rest remaining props, passed to the DataTable
|
|
39
|
+
* @return the table with the data, sortable and (optionally) paginated
|
|
40
|
+
*/
|
|
41
|
+
var ViewTable = ({ data, columns, loading, pagination = true, showIdColumn = true, defaultSortStatus, compare, getPaginationControlProps, ...rest }) => {
|
|
42
|
+
const { locale, messages } = useKitConfig();
|
|
43
|
+
const [page, setPage] = useState(1);
|
|
44
|
+
const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);
|
|
45
|
+
const [sortStatus, setSortStatus] = useState(defaultSortStatus ?? (compare ? NO_COLUMN_SORT_STATUS : DEFAULT_SORT_STATUS));
|
|
46
|
+
const [compareActive, setCompareActive] = useState(compare !== void 0);
|
|
47
|
+
const sortedData = useMemo(() => {
|
|
48
|
+
const comparator = compareActive && compare ? compare : columnComparator(sortStatus, locale);
|
|
49
|
+
return [...data].sort(comparator);
|
|
50
|
+
}, [
|
|
51
|
+
data,
|
|
52
|
+
sortStatus,
|
|
53
|
+
compareActive,
|
|
54
|
+
compare,
|
|
55
|
+
locale
|
|
56
|
+
]);
|
|
57
|
+
const records = useMemo(() => {
|
|
58
|
+
if (!pagination) return sortedData;
|
|
59
|
+
const from = (page - 1) * pageSize;
|
|
60
|
+
return sortedData.slice(from, from + pageSize);
|
|
61
|
+
}, [
|
|
62
|
+
sortedData,
|
|
63
|
+
pagination,
|
|
64
|
+
page,
|
|
65
|
+
pageSize
|
|
66
|
+
]);
|
|
67
|
+
const rowKey = useRowKey();
|
|
68
|
+
function changeSortStatus(status) {
|
|
69
|
+
setCompareActive(false);
|
|
70
|
+
setSortStatus(status);
|
|
71
|
+
}
|
|
72
|
+
const effectiveColumns = [{
|
|
73
|
+
title: "ID",
|
|
74
|
+
accessor: "id",
|
|
75
|
+
hidden: !showIdColumn,
|
|
76
|
+
sortable: true,
|
|
77
|
+
render: (item) => /* @__PURE__ */ jsx("span", { children: item.id })
|
|
78
|
+
}, ...columns];
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
setPage(1);
|
|
81
|
+
}, [pageSize]);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const totalPages = Math.ceil(data.length / pageSize);
|
|
84
|
+
setPage((currentPage) => totalPages && currentPage > totalPages ? totalPages : currentPage);
|
|
85
|
+
}, [data.length, pageSize]);
|
|
86
|
+
const paginationProps = pagination ? {
|
|
87
|
+
page,
|
|
88
|
+
onPageChange: (p) => setPage(p),
|
|
89
|
+
totalRecords: data.length,
|
|
90
|
+
recordsPerPage: pageSize,
|
|
91
|
+
recordsPerPageOptions: PAGE_SIZES,
|
|
92
|
+
onRecordsPerPageChange: setPageSize,
|
|
93
|
+
recordsPerPageLabel: messages.table.recordsPerPage,
|
|
94
|
+
paginationText: messages.table.pagination,
|
|
95
|
+
getPaginationControlProps
|
|
96
|
+
} : {};
|
|
97
|
+
return /* @__PURE__ */ jsx(DataTable, {
|
|
98
|
+
minHeight: 200,
|
|
99
|
+
verticalSpacing: "sm",
|
|
100
|
+
striped: true,
|
|
101
|
+
columns: effectiveColumns,
|
|
102
|
+
records,
|
|
103
|
+
idAccessor: rowKey,
|
|
104
|
+
noRecordsText: messages.table.noRecords,
|
|
105
|
+
fetching: loading,
|
|
106
|
+
sortStatus,
|
|
107
|
+
onSortStatusChange: changeSortStatus,
|
|
108
|
+
customRowAttributes: (record) => ({ "data-testid": `row-${record.id}` }),
|
|
109
|
+
...paginationProps,
|
|
110
|
+
...rest
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
export { ViewTable as default };
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=ViewTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewTable.js","names":[],"sources":["../../../../src/component/organism/ViewTable/ViewTable.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\nimport {\n DataTable,\n DataTableColumn,\n DataTablePaginationProps,\n DataTableProps,\n DataTableSortStatus\n} from 'mantine-datatable';\n\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useKitConfig } from '../../../provider/useKit';\nimport { columnComparator, Comparator } from './ColumnComparator';\nimport { useRowKey } from './useRowKey';\n\n/** Options of records per page. The largest one lets long tables (and end-to-end tests) show every row in one page. */\nconst PAGE_SIZES = [10, 20, 50, 200];\n\n/** Default sort when neither `defaultSortStatus` nor `compare` is given. */\nconst DEFAULT_SORT_STATUS = { columnAccessor: 'id', direction: 'asc' } as const;\n\n/**\n * Sort used while the `compare` function applies, when `defaultSortStatus` is not given: it matches no column, so no\n * header shows the sort indicator, and the first click on any column sorts it in ascending order.\n */\nconst NO_COLUMN_SORT_STATUS = { columnAccessor: '', direction: 'asc' } as const;\n\n/** Function that defines extra attributes (e.g. aria-label) for each pagination control button. */\ntype PaginationControlPropsGetter = Extract<DataTablePaginationProps, { page: number }>['getPaginationControlProps'];\n\n/**\n * Props of the {@link DataTable} passed straight through by the ViewTable.\n * Only the props actually used by the callers are accepted: using `Partial<DataTableProps<M>>` makes TypeScript combine\n * the variants of the `DataTableProps` union with the ones of `paginationProps`, which exhausts the memory of `tsc`.\n */\ntype DataTablePassThroughProps<M extends Identifiable> = Pick<\n DataTableProps<M>,\n | 'onRowClick'\n | 'rowStyle'\n | 'noRecordsText'\n | 'highlightOnHover'\n | 'highlightOnHoverColor'\n | 'className'\n | 'minHeight'\n | 'withColumnBorders'\n | 'verticalSpacing'\n | 'horizontalSpacing'\n>;\n\n/**\n * TableProps is a generic type for the ViewTable component props.\n */\ntype TableProps<M extends Identifiable> = {\n data: M[];\n columns: DataTableColumn<M>[];\n loading?: boolean;\n pagination?: boolean;\n /** Shows the ID column, automatically added to the given columns. */\n showIdColumn?: boolean;\n /**\n * Initial sort of the table. Default: by `id`, ascending.\n * Give another value when the natural order of the data should not be by `id` (e.g. when the backend already\n * returns the data in an order to keep). Along with `compare`, it only tells which header shows the sort indicator\n * in the initial order.\n */\n defaultSortStatus?: DataTableSortStatus<M>;\n /**\n * Comparison function that defines the initial order, instead of the column of `defaultSortStatus`. It allows\n * sorting by more than one criterion (e.g. city and, in the same city, year descending). After the user clicks the\n * header of a column, the sort of the column applies.\n */\n compare?: Comparator<M>;\n /** Extra attributes for the pagination control buttons. It only has effect when `pagination` is true. */\n getPaginationControlProps?: PaginationControlPropsGetter;\n} & DataTablePassThroughProps<M>;\n\n/**\n * The ViewTable component is a wrapper for the Mantine DataTable component.\n * @template M - Model that extends from {@link Identifiable}\n * @param data the data to be displayed in this ViewTable\n * @param {DataTableColumn<M>[]} columns - The columns to be displayed in this ViewTable\n * @param loading Indicates if the data to be displayed is being loaded yet or not\n * @param pagination Indicates whether to show pagination or not.\n * @param getPaginationControlProps extra attributes for the pagination control buttons\n * @param compare comparison function of the initial order, replaced by the sort of the column chosen in the header\n * @param rest remaining props, passed to the DataTable\n * @return the table with the data, sortable and (optionally) paginated\n */\nconst ViewTable = <M extends Identifiable>({\n data,\n columns,\n loading,\n pagination = true,\n showIdColumn = true,\n defaultSortStatus,\n compare,\n getPaginationControlProps,\n ...rest\n}: TableProps<M>) => {\n const { locale, messages } = useKitConfig();\n const [page, setPage] = useState(1);\n const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);\n const [sortStatus, setSortStatus] = useState<DataTableSortStatus<M>>(\n defaultSortStatus ?? (compare ? NO_COLUMN_SORT_STATUS : DEFAULT_SORT_STATUS)\n );\n // The `compare` function applies until the user chooses a column in the header.\n const [compareActive, setCompareActive] = useState(compare !== undefined);\n\n /*\n * Sorts all records before cutting the page, so each page (including in descending order) shows its part of the\n * whole set. The copy keeps the order of the given array. It is separate from the page cut, so not everything is\n * sorted again on every change of page or page size.\n */\n const sortedData = useMemo(() => {\n const comparator = compareActive && compare ? compare : columnComparator(sortStatus, locale);\n\n return [...data].sort(comparator);\n }, [data, sortStatus, compareActive, compare, locale]);\n\n // Without pagination, shows all records (e.g. a printed report), not only the ones of the first page.\n const records = useMemo(() => {\n if (!pagination) return sortedData;\n\n const from = (page - 1) * pageSize;\n return sortedData.slice(from, from + pageSize);\n }, [sortedData, pagination, page, pageSize]);\n const rowKey = useRowKey<M>();\n\n function changeSortStatus(status: DataTableSortStatus<M>): void {\n setCompareActive(false);\n setSortStatus(status);\n }\n\n const effectiveColumns: DataTableColumn<M>[] = [\n {\n title: 'ID',\n accessor: 'id',\n hidden: !showIdColumn,\n sortable: true,\n render: item => <span>{item.id}</span>\n },\n ...columns\n ];\n\n useEffect(() => {\n setPage(1);\n }, [pageSize]);\n\n /* If the data shrinks, goes back to the last existing page. The functional update avoids using an outdated `page`\n when the effect above has just gone back to page 1. */\n useEffect(() => {\n const totalPages = Math.ceil(data.length / pageSize);\n setPage(currentPage => (totalPages && currentPage > totalPages ? totalPages : currentPage));\n }, [data.length, pageSize]);\n\n /* Typed only with the pagination props (and not as Partial<DataTableProps>) to not exhaust the memory of tsc.\n See the comment of DataTablePassThroughProps. */\n const paginationProps: DataTablePaginationProps = pagination\n ? {\n page,\n onPageChange: p => setPage(p),\n totalRecords: data.length,\n recordsPerPage: pageSize,\n recordsPerPageOptions: PAGE_SIZES,\n onRecordsPerPageChange: setPageSize,\n recordsPerPageLabel: messages.table.recordsPerPage,\n paginationText: messages.table.pagination,\n getPaginationControlProps\n }\n : {};\n\n // This DataTable is the one of https://www.npmjs.com/package/mantine-datatable (there are other libraries with this name).\n return (\n <DataTable\n minHeight={200}\n verticalSpacing=\"sm\"\n striped\n columns={effectiveColumns}\n records={records}\n idAccessor={rowKey}\n noRecordsText={messages.table.noRecords}\n fetching={loading}\n sortStatus={sortStatus}\n onSortStatusChange={changeSortStatus}\n customRowAttributes={record => ({ 'data-testid': `row-${record.id}` })}\n {...paginationProps}\n {...rest}\n />\n );\n};\n\nexport default ViewTable;\n"],"mappings":";;;;;;;;;AAkBA,IAAM,aAAa;CAAC;CAAI;CAAI;CAAI;AAAG;;AAGnC,IAAM,sBAAsB;CAAE,gBAAgB;CAAM,WAAW;AAAM;;;;;AAMrE,IAAM,wBAAwB;CAAE,gBAAgB;CAAI,WAAW;AAAM;;;;;;;;;;;;;AA+DrE,IAAM,aAAqC,EACvC,MACA,SACA,SACA,aAAa,MACb,eAAe,MACf,mBACA,SACA,2BACA,GAAG,WACc;CACjB,MAAM,EAAE,QAAQ,aAAa,aAAa;CAC1C,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC;CAClC,MAAM,CAAC,UAAU,eAAe,SAAS,WAAW,EAAE;CACtD,MAAM,CAAC,YAAY,iBAAiB,SAChC,sBAAsB,UAAU,wBAAwB,oBAC5D;CAEA,MAAM,CAAC,eAAe,oBAAoB,SAAS,YAAY,KAAA,CAAS;CAOxE,MAAM,aAAa,cAAc;EAC7B,MAAM,aAAa,iBAAiB,UAAU,UAAU,iBAAiB,YAAY,MAAM;EAE3F,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,UAAU;CACpC,GAAG;EAAC;EAAM;EAAY;EAAe;EAAS;CAAM,CAAC;CAGrD,MAAM,UAAU,cAAc;EAC1B,IAAI,CAAC,YAAY,OAAO;EAExB,MAAM,QAAQ,OAAO,KAAK;EAC1B,OAAO,WAAW,MAAM,MAAM,OAAO,QAAQ;CACjD,GAAG;EAAC;EAAY;EAAY;EAAM;CAAQ,CAAC;CAC3C,MAAM,SAAS,UAAa;CAE5B,SAAS,iBAAiB,QAAsC;EAC5D,iBAAiB,KAAK;EACtB,cAAc,MAAM;CACxB;CAEA,MAAM,mBAAyC,CAC3C;EACI,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;EACT,UAAU;EACV,SAAQ,SAAQ,oBAAC,QAAD,EAAA,UAAO,KAAK,GAAS,CAAA;CACzC,GACA,GAAG,OACP;CAEA,gBAAgB;EACZ,QAAQ,CAAC;CACb,GAAG,CAAC,QAAQ,CAAC;CAIb,gBAAgB;EACZ,MAAM,aAAa,KAAK,KAAK,KAAK,SAAS,QAAQ;EACnD,SAAQ,gBAAgB,cAAc,cAAc,aAAa,aAAa,WAAY;CAC9F,GAAG,CAAC,KAAK,QAAQ,QAAQ,CAAC;CAI1B,MAAM,kBAA4C,aAC5C;EACI;EACA,eAAc,MAAK,QAAQ,CAAC;EAC5B,cAAc,KAAK;EACnB,gBAAgB;EAChB,uBAAuB;EACvB,wBAAwB;EACxB,qBAAqB,SAAS,MAAM;EACpC,gBAAgB,SAAS,MAAM;EAC/B;CACJ,IACA,CAAC;CAGP,OACI,oBAAC,WAAD;EACI,WAAW;EACX,iBAAgB;EAChB,SAAA;EACA,SAAS;EACA;EACT,YAAY;EACZ,eAAe,SAAS,MAAM;EAC9B,UAAU;EACE;EACZ,oBAAoB;EACpB,sBAAqB,YAAW,EAAE,eAAe,OAAO,OAAO,KAAK;EACpE,GAAI;EACJ,GAAI;CACP,CAAA;AAET"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Key } from 'react';
|
|
2
|
+
import { Identifiable } from '../../../model/Identifiable';
|
|
3
|
+
/**
|
|
4
|
+
* Returns the function that gives each record of a table a unique and stable key, without changing the record: its id
|
|
5
|
+
* or, for a record not saved yet (without id), a key kept per object while the table is mounted.
|
|
6
|
+
* @return a function that returns the key of a record, to use as the `idAccessor` of mantine-datatable
|
|
7
|
+
*/
|
|
8
|
+
export declare function useRowKey<M extends Identifiable>(): (record: M) => Key;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useRef } from "react";
|
|
3
|
+
// src/component/organism/ViewTable/useRowKey.ts
|
|
4
|
+
/**
|
|
5
|
+
* Returns the function that gives each record of a table a unique and stable key, without changing the record: its id
|
|
6
|
+
* or, for a record not saved yet (without id), a key kept per object while the table is mounted.
|
|
7
|
+
* @return a function that returns the key of a record, to use as the `idAccessor` of mantine-datatable
|
|
8
|
+
*/
|
|
9
|
+
function useRowKey() {
|
|
10
|
+
const generatedKeys = useRef(/* @__PURE__ */ new WeakMap());
|
|
11
|
+
const nextKey = useRef(0);
|
|
12
|
+
return useCallback((record) => {
|
|
13
|
+
if (record.id !== null && record.id !== void 0 && record.id !== "") return record.id;
|
|
14
|
+
let key = generatedKeys.current.get(record);
|
|
15
|
+
if (key === void 0) {
|
|
16
|
+
key = `unsaved-${nextKey.current++}`;
|
|
17
|
+
generatedKeys.current.set(record, key);
|
|
18
|
+
}
|
|
19
|
+
return key;
|
|
20
|
+
}, []);
|
|
21
|
+
}
|
|
22
|
+
export { useRowKey };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=useRowKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRowKey.js","names":[],"sources":["../../../../src/component/organism/ViewTable/useRowKey.ts"],"sourcesContent":["import { Key, useCallback, useRef } from 'react';\n\nimport { Identifiable } from '../../../model/Identifiable';\n\n/**\n * Returns the function that gives each record of a table a unique and stable key, without changing the record: its id\n * or, for a record not saved yet (without id), a key kept per object while the table is mounted.\n * @return a function that returns the key of a record, to use as the `idAccessor` of mantine-datatable\n */\nexport function useRowKey<M extends Identifiable>(): (record: M) => Key {\n // Keys of the records without id, by object: they disappear with the object, without keeping it in memory.\n const generatedKeys = useRef(new WeakMap<M, string>());\n const nextKey = useRef(0);\n\n return useCallback((record: M) => {\n if (record.id !== null && record.id !== undefined && record.id !== '') return record.id;\n\n let key = generatedKeys.current.get(record);\n if (key === undefined) {\n key = `unsaved-${nextKey.current++}`;\n generatedKeys.current.set(record, key);\n }\n\n return key;\n }, []);\n}\n"],"mappings":";;;;;;;;AASA,SAAgB,YAAwD;CAEpE,MAAM,gBAAgB,uBAAO,IAAI,QAAmB,CAAC;CACrD,MAAM,UAAU,OAAO,CAAC;CAExB,OAAO,aAAa,WAAc;EAC9B,IAAI,OAAO,OAAO,QAAQ,OAAO,OAAO,KAAA,KAAa,OAAO,OAAO,IAAI,OAAO,OAAO;EAErF,IAAI,MAAM,cAAc,QAAQ,IAAI,MAAM;EAC1C,IAAI,QAAQ,KAAA,GAAW;GACnB,MAAM,WAAW,QAAQ;GACzB,cAAc,QAAQ,IAAI,QAAQ,GAAG;EACzC;EAEA,OAAO;CACX,GAAG,CAAC,CAAC;AACT"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import type { UseFormReturnType } from '@mantine/form';
|
|
3
|
+
import { Identifiable } from '../../../model/Identifiable';
|
|
4
|
+
import { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';
|
|
5
|
+
interface CreateFormPageProps<T extends Identifiable, D extends object> {
|
|
6
|
+
/** Name of the record (e.g. "Region"). */
|
|
7
|
+
title: string;
|
|
8
|
+
breadcrumbItems: BreadcrumbItem[];
|
|
9
|
+
/** Sends the data of the new record (e.g. to the API). */
|
|
10
|
+
fetchMethod: (data: D) => Promise<T>;
|
|
11
|
+
form: UseFormReturnType<D>;
|
|
12
|
+
backRoute: string;
|
|
13
|
+
isSubmitDisabled?: boolean;
|
|
14
|
+
/** Question shown in a confirmation dialog before saving; absent to save right away. */
|
|
15
|
+
confirmationMessage?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Form page to create a record, which sends the data with `fetchMethod`. */
|
|
18
|
+
declare function CreateFormPage<T extends Identifiable, D extends object>(props: React.PropsWithChildren<CreateFormPageProps<T, D>>): ReactElement;
|
|
19
|
+
export default CreateFormPage;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useDocumentTitle, useKitMessages } from "../../../provider/useKit.js";
|
|
3
|
+
import DataForm from "../../organism/DataForm/DataForm.js";
|
|
4
|
+
import PageHeader from "../../organism/PageHeader/PageHeader.js";
|
|
5
|
+
import "react";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Stack } from "@mantine/core";
|
|
8
|
+
// src/component/template/CreateFormPage/CreateFormPage.tsx
|
|
9
|
+
/** Form page to create a record, which sends the data with `fetchMethod`. */
|
|
10
|
+
function CreateFormPage(props) {
|
|
11
|
+
const { title, breadcrumbItems, fetchMethod, form, backRoute, isSubmitDisabled, children, confirmationMessage } = props;
|
|
12
|
+
const messages = useKitMessages();
|
|
13
|
+
const pageTitle = `${messages.form.action.create} ${title}`;
|
|
14
|
+
const documentTitle = useDocumentTitle(pageTitle);
|
|
15
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("title", { children: documentTitle }), /* @__PURE__ */ jsxs(Stack, {
|
|
16
|
+
gap: "lg",
|
|
17
|
+
children: [/* @__PURE__ */ jsx(PageHeader, {
|
|
18
|
+
title: pageTitle,
|
|
19
|
+
breadcrumbItems: [...breadcrumbItems, {
|
|
20
|
+
title: pageTitle,
|
|
21
|
+
href: "#"
|
|
22
|
+
}]
|
|
23
|
+
}), /* @__PURE__ */ jsx(DataForm, {
|
|
24
|
+
form,
|
|
25
|
+
fetchMethod,
|
|
26
|
+
title,
|
|
27
|
+
backRoute,
|
|
28
|
+
submit: {
|
|
29
|
+
title: messages.common.save,
|
|
30
|
+
successMsg: messages.form.createSuccess,
|
|
31
|
+
errorMsg: messages.form.createError,
|
|
32
|
+
disabled: isSubmitDisabled,
|
|
33
|
+
confirmationMessage
|
|
34
|
+
},
|
|
35
|
+
children
|
|
36
|
+
})]
|
|
37
|
+
})] });
|
|
38
|
+
}
|
|
39
|
+
export { CreateFormPage as default };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=CreateFormPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreateFormPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/CreateFormPage/CreateFormPage.tsx"],"sourcesContent":["import React, { ReactElement } from 'react';\n\nimport { Stack } from '@mantine/core';\nimport type { UseFormReturnType } from '@mantine/form';\n\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useDocumentTitle, useKitMessages } from '../../../provider/useKit';\nimport { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';\nimport DataForm from '../../organism/DataForm/DataForm';\nimport PageHeader from '../../organism/PageHeader/PageHeader';\n\ninterface CreateFormPageProps<T extends Identifiable, D extends object> {\n /** Name of the record (e.g. \"Region\"). */\n title: string;\n breadcrumbItems: BreadcrumbItem[];\n\n /** Sends the data of the new record (e.g. to the API). */\n fetchMethod: (data: D) => Promise<T>;\n form: UseFormReturnType<D>;\n backRoute: string;\n isSubmitDisabled?: boolean;\n\n /** Question shown in a confirmation dialog before saving; absent to save right away. */\n confirmationMessage?: string;\n}\n\n/** Form page to create a record, which sends the data with `fetchMethod`. */\nfunction CreateFormPage<T extends Identifiable, D extends object>(\n props: React.PropsWithChildren<CreateFormPageProps<T, D>>\n): ReactElement {\n const { title, breadcrumbItems, fetchMethod, form, backRoute, isSubmitDisabled, children, confirmationMessage } =\n props;\n const messages = useKitMessages();\n const pageTitle = `${messages.form.action.create} ${title}`;\n const documentTitle = useDocumentTitle(pageTitle);\n\n return (\n <>\n <title>{documentTitle}</title>\n <Stack gap=\"lg\">\n <PageHeader title={pageTitle} breadcrumbItems={[...breadcrumbItems, { title: pageTitle, href: '#' }]} />\n\n <DataForm\n form={form}\n fetchMethod={fetchMethod}\n title={title}\n backRoute={backRoute}\n submit={{\n title: messages.common.save,\n successMsg: messages.form.createSuccess,\n errorMsg: messages.form.createError,\n disabled: isSubmitDisabled,\n confirmationMessage\n }}\n >\n {children}\n </DataForm>\n </Stack>\n </>\n );\n}\n\nexport default CreateFormPage;\n"],"mappings":";;;;;;;;;AA2BA,SAAS,eACL,OACY;CACZ,MAAM,EAAE,OAAO,iBAAiB,aAAa,MAAM,WAAW,kBAAkB,UAAU,wBACtF;CACJ,MAAM,WAAW,eAAe;CAChC,MAAM,YAAY,GAAG,SAAS,KAAK,OAAO,OAAO,GAAG;CACpD,MAAM,gBAAgB,iBAAiB,SAAS;CAEhD,OACI,qBAAAA,UAAA,EAAA,UAAA,CACI,oBAAC,SAAD,EAAA,UAAQ,cAAqB,CAAA,GAC7B,qBAAC,OAAD;EAAO,KAAI;EAAX,UAAA,CACI,oBAAC,YAAD;GAAY,OAAO;GAAW,iBAAiB,CAAC,GAAG,iBAAiB;IAAE,OAAO;IAAW,MAAM;GAAI,CAAC;EAAI,CAAA,GAEvG,oBAAC,UAAD;GACU;GACO;GACN;GACI;GACX,QAAQ;IACJ,OAAO,SAAS,OAAO;IACvB,YAAY,SAAS,KAAK;IAC1B,UAAU,SAAS,KAAK;IACxB,UAAU;IACV;GACJ;GAEC;EACK,CAAA,CACP;CACT,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import type { UseFormReturnType } from '@mantine/form';
|
|
3
|
+
import { Identifiable } from '../../../model/Identifiable';
|
|
4
|
+
import { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';
|
|
5
|
+
interface EditFormPageProps<T extends Identifiable, D extends object> {
|
|
6
|
+
/** Name of the record (e.g. "Region"). */
|
|
7
|
+
title: string;
|
|
8
|
+
breadcrumbItems: BreadcrumbItem[];
|
|
9
|
+
/** Sends the changed data of the record (e.g. to the API). */
|
|
10
|
+
fetchMethod: (data: D) => Promise<T>;
|
|
11
|
+
form: UseFormReturnType<D>;
|
|
12
|
+
backRoute: string;
|
|
13
|
+
isSubmitDisabled?: boolean;
|
|
14
|
+
/** Question shown in a confirmation dialog before saving; absent to save right away. */
|
|
15
|
+
confirmationMessage?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Form page to update a record, which sends the data with `fetchMethod`. */
|
|
18
|
+
declare function EditFormPage<T extends Identifiable, D extends object>(props: React.PropsWithChildren<EditFormPageProps<T, D>>): ReactElement;
|
|
19
|
+
export default EditFormPage;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useDocumentTitle, useKitMessages } from "../../../provider/useKit.js";
|
|
3
|
+
import DataForm from "../../organism/DataForm/DataForm.js";
|
|
4
|
+
import PageHeader from "../../organism/PageHeader/PageHeader.js";
|
|
5
|
+
import "react";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Stack } from "@mantine/core";
|
|
8
|
+
// src/component/template/EditFormPage/EditFormPage.tsx
|
|
9
|
+
/** Form page to update a record, which sends the data with `fetchMethod`. */
|
|
10
|
+
function EditFormPage(props) {
|
|
11
|
+
const { title, breadcrumbItems, fetchMethod, form, backRoute, isSubmitDisabled, children, confirmationMessage } = props;
|
|
12
|
+
const messages = useKitMessages();
|
|
13
|
+
const action = messages.form.action.edit;
|
|
14
|
+
const pageTitle = `${action} ${title}`;
|
|
15
|
+
const documentTitle = useDocumentTitle(pageTitle);
|
|
16
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("title", { children: documentTitle }), /* @__PURE__ */ jsxs(Stack, {
|
|
17
|
+
gap: "lg",
|
|
18
|
+
children: [/* @__PURE__ */ jsx(PageHeader, {
|
|
19
|
+
title: pageTitle,
|
|
20
|
+
breadcrumbItems: [...breadcrumbItems, {
|
|
21
|
+
title: pageTitle,
|
|
22
|
+
href: "#"
|
|
23
|
+
}]
|
|
24
|
+
}), /* @__PURE__ */ jsx(DataForm, {
|
|
25
|
+
form,
|
|
26
|
+
fetchMethod,
|
|
27
|
+
title,
|
|
28
|
+
backRoute,
|
|
29
|
+
submit: {
|
|
30
|
+
title: action,
|
|
31
|
+
successMsg: messages.form.updateSuccess,
|
|
32
|
+
errorMsg: messages.form.updateError,
|
|
33
|
+
disabled: isSubmitDisabled,
|
|
34
|
+
confirmationMessage
|
|
35
|
+
},
|
|
36
|
+
children
|
|
37
|
+
})]
|
|
38
|
+
})] });
|
|
39
|
+
}
|
|
40
|
+
export { EditFormPage as default };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=EditFormPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditFormPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/EditFormPage/EditFormPage.tsx"],"sourcesContent":["import React, { ReactElement } from 'react';\n\nimport { Stack } from '@mantine/core';\nimport type { UseFormReturnType } from '@mantine/form';\n\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useDocumentTitle, useKitMessages } from '../../../provider/useKit';\nimport { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';\nimport DataForm from '../../organism/DataForm/DataForm';\nimport PageHeader from '../../organism/PageHeader/PageHeader';\n\ninterface EditFormPageProps<T extends Identifiable, D extends object> {\n /** Name of the record (e.g. \"Region\"). */\n title: string;\n breadcrumbItems: BreadcrumbItem[];\n\n /** Sends the changed data of the record (e.g. to the API). */\n fetchMethod: (data: D) => Promise<T>;\n form: UseFormReturnType<D>;\n backRoute: string;\n isSubmitDisabled?: boolean;\n\n /** Question shown in a confirmation dialog before saving; absent to save right away. */\n confirmationMessage?: string;\n}\n\n/** Form page to update a record, which sends the data with `fetchMethod`. */\nfunction EditFormPage<T extends Identifiable, D extends object>(\n props: React.PropsWithChildren<EditFormPageProps<T, D>>\n): ReactElement {\n const { title, breadcrumbItems, fetchMethod, form, backRoute, isSubmitDisabled, children, confirmationMessage } =\n props;\n const messages = useKitMessages();\n const action = messages.form.action.edit;\n const pageTitle = `${action} ${title}`;\n const documentTitle = useDocumentTitle(pageTitle);\n\n return (\n <>\n <title>{documentTitle}</title>\n <Stack gap=\"lg\">\n <PageHeader title={pageTitle} breadcrumbItems={[...breadcrumbItems, { title: pageTitle, href: '#' }]} />\n\n <DataForm\n form={form}\n fetchMethod={fetchMethod}\n title={title}\n backRoute={backRoute}\n submit={{\n title: action,\n successMsg: messages.form.updateSuccess,\n errorMsg: messages.form.updateError,\n disabled: isSubmitDisabled,\n confirmationMessage\n }}\n >\n {children}\n </DataForm>\n </Stack>\n </>\n );\n}\n\nexport default EditFormPage;\n"],"mappings":";;;;;;;;;AA2BA,SAAS,aACL,OACY;CACZ,MAAM,EAAE,OAAO,iBAAiB,aAAa,MAAM,WAAW,kBAAkB,UAAU,wBACtF;CACJ,MAAM,WAAW,eAAe;CAChC,MAAM,SAAS,SAAS,KAAK,OAAO;CACpC,MAAM,YAAY,GAAG,OAAO,GAAG;CAC/B,MAAM,gBAAgB,iBAAiB,SAAS;CAEhD,OACI,qBAAAA,UAAA,EAAA,UAAA,CACI,oBAAC,SAAD,EAAA,UAAQ,cAAqB,CAAA,GAC7B,qBAAC,OAAD;EAAO,KAAI;EAAX,UAAA,CACI,oBAAC,YAAD;GAAY,OAAO;GAAW,iBAAiB,CAAC,GAAG,iBAAiB;IAAE,OAAO;IAAW,MAAM;GAAI,CAAC;EAAI,CAAA,GAEvG,oBAAC,UAAD;GACU;GACO;GACN;GACI;GACX,QAAQ;IACJ,OAAO;IACP,YAAY,SAAS,KAAK;IAC1B,UAAU,SAAS,KAAK;IACxB,UAAU;IACV;GACJ;GAEC;EACK,CAAA,CACP;CACT,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import type { UseFormReturnType } from '@mantine/form';
|
|
3
|
+
import { SaveDataSource } from '../../../data/SaveDataSource';
|
|
4
|
+
import { Identifiable } from '../../../model/Identifiable';
|
|
5
|
+
import { FormType } from './FormType';
|
|
6
|
+
interface FormPageProps<T extends Identifiable, D extends object, S extends SaveDataSource<T, D>> {
|
|
7
|
+
/** Destination of the data (e.g. a service that accesses an API). */
|
|
8
|
+
service: S;
|
|
9
|
+
/** Name of the record (e.g. "Region"), shown after the action verb in the title. */
|
|
10
|
+
title: string;
|
|
11
|
+
formType: FormType;
|
|
12
|
+
form: UseFormReturnType<D & Identifiable>;
|
|
13
|
+
/** Page opened after saving and by the back button; absent for the first segment of the current path. */
|
|
14
|
+
backRoute?: string;
|
|
15
|
+
/** Shows a loading overlay over the form (e.g. while the record is fetched). */
|
|
16
|
+
isLoading?: boolean;
|
|
17
|
+
/** Whether the form takes the whole width, instead of half of it on large screens. */
|
|
18
|
+
isFullWidth?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* CRUD form page to create, edit or view a record (according to `formType`), which saves the data in `service` and
|
|
22
|
+
* goes back to the list page.
|
|
23
|
+
*/
|
|
24
|
+
declare function FormPage<T extends Identifiable, D extends object, S extends SaveDataSource<T, D>>(props: React.PropsWithChildren<FormPageProps<T, D, S>>): ReactElement;
|
|
25
|
+
export default FormPage;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useDocumentTitle, useKitConfig } from "../../../provider/useKit.js";
|
|
3
|
+
import { formatValues } from "../../../util/TransformData.js";
|
|
4
|
+
import { showErrorNotification, showSuccessNotification } from "../../../util/Notifications.js";
|
|
5
|
+
import PaperCard from "../../molecule/PaperCard/PaperCard.js";
|
|
6
|
+
import PageHeader from "../../organism/PageHeader/PageHeader.js";
|
|
7
|
+
import { FormType } from "./FormType.js";
|
|
8
|
+
import { useState } from "react";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { Alert, Box, Button, Grid, Group, LoadingOverlay, Stack, Text } from "@mantine/core";
|
|
11
|
+
import { IconArrowBack, IconDeviceFloppy, IconInfoCircle } from "@tabler/icons-react";
|
|
12
|
+
// src/component/template/FormPage/FormPage.tsx
|
|
13
|
+
/** Action of each form type, the key of its verb in the texts. */
|
|
14
|
+
var FORM_ACTIONS = {
|
|
15
|
+
[FormType.Create]: "create",
|
|
16
|
+
[FormType.Edit]: "edit",
|
|
17
|
+
[FormType.View]: "view"
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* CRUD form page to create, edit or view a record (according to `formType`), which saves the data in `service` and
|
|
21
|
+
* goes back to the list page.
|
|
22
|
+
*/
|
|
23
|
+
function FormPage(props) {
|
|
24
|
+
const { title, formType, service, form, backRoute, isLoading, isFullWidth, children } = props;
|
|
25
|
+
const { router, messages } = useKitConfig();
|
|
26
|
+
const { Link } = router;
|
|
27
|
+
const navigate = router.useNavigate();
|
|
28
|
+
const pathname = router.usePathname();
|
|
29
|
+
/**
|
|
30
|
+
* Checks whether a field of the validation schema is missing in the form.
|
|
31
|
+
* @param fieldName name of the field to find
|
|
32
|
+
*/
|
|
33
|
+
function isFormFieldMissing(fieldName) {
|
|
34
|
+
return !form.getInputNode(fieldName);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Shows the errors of the fields that are in the validation schema given to `useForm`, but not in the form.
|
|
38
|
+
* Without it, these errors are not shown to the user (not even in the console), so neither the user nor the
|
|
39
|
+
* developer can understand why the form is not submitted.
|
|
40
|
+
*/
|
|
41
|
+
function showErrorsForMissingFormFields() {
|
|
42
|
+
const errors = Object.entries(form.errors).map(([fieldName, errorMsg]) => ({
|
|
43
|
+
fieldName,
|
|
44
|
+
errorMsg
|
|
45
|
+
})).filter(({ fieldName }) => isFormFieldMissing(fieldName)).map(({ fieldName, errorMsg }) => /* @__PURE__ */ jsx("li", { children: errorMsg }, fieldName));
|
|
46
|
+
const icon = /* @__PURE__ */ jsx(IconInfoCircle, {});
|
|
47
|
+
return errors.length > 0 && /* @__PURE__ */ jsx(Alert, {
|
|
48
|
+
color: "red",
|
|
49
|
+
icon,
|
|
50
|
+
children: /* @__PURE__ */ jsx("ul", { children: errors })
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const { id } = form.values;
|
|
54
|
+
const [loading, setLoading] = useState(false);
|
|
55
|
+
const effectiveBackRoute = backRoute || `/${pathname.split("/").at(1)}`;
|
|
56
|
+
const canShowSubmitButton = formType === FormType.Create || formType === FormType.Edit;
|
|
57
|
+
const formTypeTitle = messages.form.action[FORM_ACTIONS[formType] ?? "custom"];
|
|
58
|
+
const documentTitle = useDocumentTitle(`${formTypeTitle} ${title}`);
|
|
59
|
+
const handleSubmit = async (data) => {
|
|
60
|
+
setLoading(true);
|
|
61
|
+
try {
|
|
62
|
+
const effectiveData = formatValues(data);
|
|
63
|
+
await service.save(id, effectiveData);
|
|
64
|
+
showSuccessNotification(messages.form.saveSuccess(formTypeTitle), messages.common.success);
|
|
65
|
+
if (effectiveBackRoute) navigate(effectiveBackRoute);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
showErrorNotification(e, messages.form.saveError(formTypeTitle), messages.common.error);
|
|
68
|
+
} finally {
|
|
69
|
+
setLoading(false);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("title", { children: documentTitle }), /* @__PURE__ */ jsxs(Stack, {
|
|
73
|
+
gap: "lg",
|
|
74
|
+
children: [/* @__PURE__ */ jsx(PageHeader, {
|
|
75
|
+
title: `${formTypeTitle} ${title}`,
|
|
76
|
+
breadcrumbItems: [{
|
|
77
|
+
title,
|
|
78
|
+
href: effectiveBackRoute
|
|
79
|
+
}, {
|
|
80
|
+
title: `${formTypeTitle} ${title}`,
|
|
81
|
+
href: "#"
|
|
82
|
+
}]
|
|
83
|
+
}), /* @__PURE__ */ jsx(Grid, { children: /* @__PURE__ */ jsx(Grid.Col, {
|
|
84
|
+
span: {
|
|
85
|
+
base: 12,
|
|
86
|
+
lg: isFullWidth ? 12 : 6
|
|
87
|
+
},
|
|
88
|
+
children: /* @__PURE__ */ jsx(PaperCard, { children: /* @__PURE__ */ jsxs(Box, {
|
|
89
|
+
component: "form",
|
|
90
|
+
onSubmit: form.onSubmit(handleSubmit),
|
|
91
|
+
pos: "relative",
|
|
92
|
+
children: [/* @__PURE__ */ jsx(LoadingOverlay, {
|
|
93
|
+
visible: isLoading,
|
|
94
|
+
zIndex: 1e3,
|
|
95
|
+
overlayProps: {
|
|
96
|
+
radius: "sm",
|
|
97
|
+
blur: 2
|
|
98
|
+
}
|
|
99
|
+
}), /* @__PURE__ */ jsxs(Stack, { children: [
|
|
100
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
101
|
+
size: "lg",
|
|
102
|
+
fw: 600,
|
|
103
|
+
children: [
|
|
104
|
+
formTypeTitle,
|
|
105
|
+
" ",
|
|
106
|
+
title
|
|
107
|
+
]
|
|
108
|
+
}),
|
|
109
|
+
children,
|
|
110
|
+
showErrorsForMissingFormFields(),
|
|
111
|
+
/* @__PURE__ */ jsxs(Group, { children: [/* @__PURE__ */ jsx(Button, {
|
|
112
|
+
leftSection: /* @__PURE__ */ jsx(IconArrowBack, { size: 16 }),
|
|
113
|
+
component: Link,
|
|
114
|
+
href: effectiveBackRoute,
|
|
115
|
+
variant: "default",
|
|
116
|
+
children: messages.common.back
|
|
117
|
+
}), canShowSubmitButton && /* @__PURE__ */ jsx(Button, {
|
|
118
|
+
type: "submit",
|
|
119
|
+
leftSection: /* @__PURE__ */ jsx(IconDeviceFloppy, { size: 16 }),
|
|
120
|
+
loading,
|
|
121
|
+
children: formTypeTitle
|
|
122
|
+
})] })
|
|
123
|
+
] })]
|
|
124
|
+
}) })
|
|
125
|
+
}) })]
|
|
126
|
+
})] });
|
|
127
|
+
}
|
|
128
|
+
export { FormPage as default };
|
|
129
|
+
|
|
130
|
+
//# sourceMappingURL=FormPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/FormPage/FormPage.tsx"],"sourcesContent":["import React, { ReactElement, useState } from 'react';\n\nimport { Alert, Box, Button, Grid, Group, LoadingOverlay, Stack, Text } from '@mantine/core';\nimport type { UseFormReturnType } from '@mantine/form';\nimport { IconArrowBack, IconDeviceFloppy, IconInfoCircle } from '@tabler/icons-react';\n\nimport { SaveDataSource } from '../../../data/SaveDataSource';\nimport { FormAction } from '../../../i18n/KitMessages';\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useDocumentTitle, useKitConfig } from '../../../provider/useKit';\nimport { formatValues } from '../../../util/TransformData';\nimport { showErrorNotification, showSuccessNotification } from '../../../util/Notifications';\nimport PaperCard from '../../molecule/PaperCard/PaperCard';\nimport PageHeader from '../../organism/PageHeader/PageHeader';\nimport { FormType } from './FormType';\n\ninterface FormPageProps<T extends Identifiable, D extends object, S extends SaveDataSource<T, D>> {\n /** Destination of the data (e.g. a service that accesses an API). */\n service: S;\n\n /** Name of the record (e.g. \"Region\"), shown after the action verb in the title. */\n title: string;\n formType: FormType;\n form: UseFormReturnType<D & Identifiable>;\n\n /** Page opened after saving and by the back button; absent for the first segment of the current path. */\n backRoute?: string;\n\n /** Shows a loading overlay over the form (e.g. while the record is fetched). */\n isLoading?: boolean;\n\n /** Whether the form takes the whole width, instead of half of it on large screens. */\n isFullWidth?: boolean;\n}\n\n/** Action of each form type, the key of its verb in the texts. */\nconst FORM_ACTIONS: Record<FormType, FormAction> = {\n [FormType.Create]: 'create',\n [FormType.Edit]: 'edit',\n [FormType.View]: 'view'\n};\n\n/**\n * CRUD form page to create, edit or view a record (according to `formType`), which saves the data in `service` and\n * goes back to the list page.\n */\nfunction FormPage<T extends Identifiable, D extends object, S extends SaveDataSource<T, D>>(\n props: React.PropsWithChildren<FormPageProps<T, D, S>>\n): ReactElement {\n const { title, formType, service, form, backRoute, isLoading, isFullWidth, children } = props;\n const { router, messages } = useKitConfig();\n const { Link } = router;\n const navigate = router.useNavigate();\n const pathname = router.usePathname();\n\n /**\n * Checks whether a field of the validation schema is missing in the form.\n * @param fieldName name of the field to find\n */\n function isFormFieldMissing(fieldName: string): boolean {\n return !form.getInputNode(fieldName);\n }\n\n /**\n * Shows the errors of the fields that are in the validation schema given to `useForm`, but not in the form.\n * Without it, these errors are not shown to the user (not even in the console), so neither the user nor the\n * developer can understand why the form is not submitted.\n */\n function showErrorsForMissingFormFields(): ReactElement | false {\n const errors = Object.entries(form.errors)\n .map(([fieldName, errorMsg]) => ({ fieldName, errorMsg }))\n .filter(({ fieldName }) => isFormFieldMissing(fieldName))\n .map(({ fieldName, errorMsg }) => <li key={fieldName}>{errorMsg}</li>);\n\n const icon = <IconInfoCircle />;\n return (\n errors.length > 0 && (\n <Alert color=\"red\" icon={icon}>\n <ul>{errors}</ul>\n </Alert>\n )\n );\n }\n\n const { id } = form.values;\n\n const [loading, setLoading] = useState(false);\n const effectiveBackRoute = backRoute || `/${pathname.split('/').at(1)}`;\n\n const canShowSubmitButton = formType === FormType.Create || formType === FormType.Edit;\n const formTypeTitle = messages.form.action[FORM_ACTIONS[formType] ?? 'custom'];\n const documentTitle = useDocumentTitle(`${formTypeTitle} ${title}`);\n\n const handleSubmit = async (data: D) => {\n setLoading(true);\n try {\n const effectiveData = formatValues(data) as D;\n await service.save(id, effectiveData);\n showSuccessNotification(messages.form.saveSuccess(formTypeTitle), messages.common.success);\n\n if (effectiveBackRoute) navigate(effectiveBackRoute);\n } catch (e) {\n showErrorNotification(e, messages.form.saveError(formTypeTitle), messages.common.error);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <>\n <title>{documentTitle}</title>\n <Stack gap=\"lg\">\n <PageHeader\n title={`${formTypeTitle} ${title}`}\n breadcrumbItems={[\n { title, href: effectiveBackRoute },\n { title: `${formTypeTitle} ${title}`, href: '#' }\n ]}\n />\n <Grid>\n <Grid.Col span={{ base: 12, lg: isFullWidth ? 12 : 6 }}>\n <PaperCard>\n <Box component=\"form\" onSubmit={form.onSubmit(handleSubmit)} pos=\"relative\">\n <LoadingOverlay\n visible={isLoading}\n zIndex={1000}\n overlayProps={{ radius: 'sm', blur: 2 }}\n />\n\n <Stack>\n <Text size=\"lg\" fw={600}>\n {formTypeTitle} {title}\n </Text>\n\n {children}\n {showErrorsForMissingFormFields()}\n\n <Group>\n <Button\n leftSection={<IconArrowBack size={16} />}\n component={Link}\n href={effectiveBackRoute}\n variant=\"default\"\n >\n {messages.common.back}\n </Button>\n {canShowSubmitButton && (\n <Button\n type=\"submit\"\n leftSection={<IconDeviceFloppy size={16} />}\n loading={loading}\n >\n {formTypeTitle}\n </Button>\n )}\n </Group>\n </Stack>\n </Box>\n </PaperCard>\n </Grid.Col>\n </Grid>\n </Stack>\n </>\n );\n}\n\nexport default FormPage;\n"],"mappings":";;;;;;;;;;;;;AAoCA,IAAM,eAA6C;EAC9C,SAAS,SAAS;EAClB,SAAS,OAAO;EAChB,SAAS,OAAO;AACrB;;;;;AAMA,SAAS,SACL,OACY;CACZ,MAAM,EAAE,OAAO,UAAU,SAAS,MAAM,WAAW,WAAW,aAAa,aAAa;CACxF,MAAM,EAAE,QAAQ,aAAa,aAAa;CAC1C,MAAM,EAAE,SAAS;CACjB,MAAM,WAAW,OAAO,YAAY;CACpC,MAAM,WAAW,OAAO,YAAY;;;;;CAMpC,SAAS,mBAAmB,WAA4B;EACpD,OAAO,CAAC,KAAK,aAAa,SAAS;CACvC;;;;;;CAOA,SAAS,iCAAuD;EAC5D,MAAM,SAAS,OAAO,QAAQ,KAAK,MAAM,CAAC,CACrC,KAAK,CAAC,WAAW,eAAe;GAAE;GAAW;EAAS,EAAE,CAAC,CACzD,QAAQ,EAAE,gBAAgB,mBAAmB,SAAS,CAAC,CAAC,CACxD,KAAK,EAAE,WAAW,eAAe,oBAAC,MAAD,EAAA,UAAqB,SAAa,GAAzB,SAAyB,CAAC;EAEzE,MAAM,OAAO,oBAAC,gBAAD,CAAiB,CAAA;EAC9B,OACI,OAAO,SAAS,KACZ,oBAAC,OAAD;GAAO,OAAM;GAAY;GACrB,UAAA,oBAAC,MAAD,EAAA,UAAK,OAAW,CAAA;EACb,CAAA;CAGnB;CAEA,MAAM,EAAE,OAAO,KAAK;CAEpB,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,qBAAqB,aAAa,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC;CAEpE,MAAM,sBAAsB,aAAa,SAAS,UAAU,aAAa,SAAS;CAClF,MAAM,gBAAgB,SAAS,KAAK,OAAO,aAAa,aAAa;CACrE,MAAM,gBAAgB,iBAAiB,GAAG,cAAc,GAAG,OAAO;CAElE,MAAM,eAAe,OAAO,SAAY;EACpC,WAAW,IAAI;EACf,IAAI;GACA,MAAM,gBAAgB,aAAa,IAAI;GACvC,MAAM,QAAQ,KAAK,IAAI,aAAa;GACpC,wBAAwB,SAAS,KAAK,YAAY,aAAa,GAAG,SAAS,OAAO,OAAO;GAEzF,IAAI,oBAAoB,SAAS,kBAAkB;EACvD,SAAS,GAAG;GACR,sBAAsB,GAAG,SAAS,KAAK,UAAU,aAAa,GAAG,SAAS,OAAO,KAAK;EAC1F,UAAU;GACN,WAAW,KAAK;EACpB;CACJ;CAEA,OACI,qBAAAA,UAAA,EAAA,UAAA,CACI,oBAAC,SAAD,EAAA,UAAQ,cAAqB,CAAA,GAC7B,qBAAC,OAAD;EAAO,KAAI;EAAX,UAAA,CACI,oBAAC,YAAD;GACI,OAAO,GAAG,cAAc,GAAG;GAC3B,iBAAiB,CACb;IAAE;IAAO,MAAM;GAAmB,GAClC;IAAE,OAAO,GAAG,cAAc,GAAG;IAAS,MAAM;GAAI,CACpD;EACH,CAAA,GACD,oBAAC,MAAD,EAAA,UACI,oBAAC,KAAK,KAAN;GAAU,MAAM;IAAE,MAAM;IAAI,IAAI,cAAc,KAAK;GAAE;GACjD,UAAA,oBAAC,WAAD,EAAA,UACI,qBAAC,KAAD;IAAK,WAAU;IAAO,UAAU,KAAK,SAAS,YAAY;IAAG,KAAI;IAAjE,UAAA,CACI,oBAAC,gBAAD;KACI,SAAS;KACT,QAAQ;KACR,cAAc;MAAE,QAAQ;MAAM,MAAM;KAAE;IACzC,CAAA,GAED,qBAAC,OAAD,EAAA,UAAA;KACI,qBAAC,MAAD;MAAM,MAAK;MAAK,IAAI;MAApB,UAAA;OACK;OAAc;OAAE;MACf;;KAEL;KACA,+BAA+B;KAEhC,qBAAC,OAAD,EAAA,UAAA,CACI,oBAAC,QAAD;MACI,aAAa,oBAAC,eAAD,EAAe,MAAM,GAAK,CAAA;MACvC,WAAW;MACX,MAAM;MACN,SAAQ;MAEP,UAAA,SAAS,OAAO;KACb,CAAA,GACP,uBACG,oBAAC,QAAD;MACI,MAAK;MACL,aAAa,oBAAC,kBAAD,EAAkB,MAAM,GAAK,CAAA;MACjC;MAER,UAAA;KACG,CAAA,CAET,EAAA,CAAA;IACJ,EAAA,CAAA,CACN;GACE,CAAA,EAAA,CAAA;EACL,CAAA,EACR,CAAA,CACH;CACT,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/component/template/FormPage/FormType.ts
|
|
3
|
+
/** Mode in which a CRUD form is opened. */
|
|
4
|
+
var FormType = /* @__PURE__ */ function(FormType) {
|
|
5
|
+
FormType[FormType["Create"] = 0] = "Create";
|
|
6
|
+
FormType[FormType["Edit"] = 1] = "Edit";
|
|
7
|
+
FormType[FormType["View"] = 2] = "View";
|
|
8
|
+
return FormType;
|
|
9
|
+
}({});
|
|
10
|
+
export { FormType };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=FormType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormType.js","names":[],"sources":["../../../../src/component/template/FormPage/FormType.ts"],"sourcesContent":["/** Mode in which a CRUD form is opened. */\nexport enum FormType {\n Create,\n Edit,\n View\n}\n"],"mappings":";;;AACA,IAAY,WAAL,yBAAA,UAAA;CACH,SAAA,SAAA,YAAA,KAAA;CACA,SAAA,SAAA,UAAA,KAAA;CACA,SAAA,SAAA,UAAA,KAAA;;AACJ,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NavItem } from '../../organism/Navbar/NavItem';
|
|
2
|
+
interface Props {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
/** Brand of the app in the header (e.g. the logo with a link to the home page). */
|
|
5
|
+
logo: React.ReactNode;
|
|
6
|
+
/** Items of the side menu. */
|
|
7
|
+
navItems: NavItem[];
|
|
8
|
+
/** Content fixed at the bottom of the side menu (e.g. a link to log out). */
|
|
9
|
+
navFooter?: React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Items of the user menu (e.g. `Menu.Item`s for the profile and to log out), opened by the avatar in the header.
|
|
12
|
+
* Without them, the avatar is not shown.
|
|
13
|
+
*/
|
|
14
|
+
userMenu?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Structure of the pages of the app: header with the brand, the color scheme toggle and the user menu, collapsible side
|
|
18
|
+
* menu and the content area.
|
|
19
|
+
*/
|
|
20
|
+
export declare const Layout: ({ children, logo, navItems, navFooter, userMenu }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|