@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,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMediaQuery } from "@mantine/hooks";
|
|
3
|
+
// src/hook/useIsMobile.ts
|
|
4
|
+
/** Maximum screen width considered a mobile device. */
|
|
5
|
+
var MOBILE_MEDIA_QUERY = "(max-width: 768px)";
|
|
6
|
+
/**
|
|
7
|
+
* Tells whether the user is on a mobile device.
|
|
8
|
+
* @return true if the screen has the width of a mobile device, false otherwise
|
|
9
|
+
*/
|
|
10
|
+
var useIsMobile = () => {
|
|
11
|
+
const isMobile = useMediaQuery(MOBILE_MEDIA_QUERY);
|
|
12
|
+
return isMobile == void 0 ? false : isMobile;
|
|
13
|
+
};
|
|
14
|
+
export { useIsMobile };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=useIsMobile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIsMobile.js","names":[],"sources":["../../src/hook/useIsMobile.ts"],"sourcesContent":["import { useMediaQuery } from '@mantine/hooks';\n\n/** Maximum screen width considered a mobile device. */\nconst MOBILE_MEDIA_QUERY = '(max-width: 768px)';\n\n/**\n * Tells whether the user is on a mobile device.\n * @return true if the screen has the width of a mobile device, false otherwise\n */\nexport const useIsMobile = () => {\n const isMobile = useMediaQuery(MOBILE_MEDIA_QUERY);\n\n /* `useMediaQuery` returns `undefined` before the first measurement. The caller expects just true or false, so it is\n treated as false. */\n return isMobile == undefined ? false : isMobile;\n};\n"],"mappings":";;;;AAGA,IAAM,qBAAqB;;;;;AAM3B,IAAa,oBAAoB;CAC7B,MAAM,WAAW,cAAc,kBAAkB;CAIjD,OAAO,YAAY,KAAA,IAAY,QAAQ;AAC3C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Key of a fetch (e.g. the year being queried), which tells which selection a result belongs to. */
|
|
2
|
+
export type ServiceKey = string | number;
|
|
3
|
+
/** Values returned by {@link useKeyedService}. */
|
|
4
|
+
export type UseKeyedService<T> = {
|
|
5
|
+
/** Data of the fetch of the current key; `undefined` while it has not finished or if it failed. */
|
|
6
|
+
data?: T;
|
|
7
|
+
/** Error of the fetch of the current key; `undefined` if it has not finished yet or succeeded. */
|
|
8
|
+
error?: unknown;
|
|
9
|
+
/** Whether the fetch of the current key has not finished yet. */
|
|
10
|
+
loading: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Fetches data that depends on a key (e.g. a filter of the screen) and exposes only the result of the current key.
|
|
14
|
+
* When the key changes, the data and the error of the previous fetch are no longer exposed and `loading` becomes
|
|
15
|
+
* `true` until the new fetch finishes, so the screen never shows data of another selection. A response that arrives
|
|
16
|
+
* after the key changed is discarded.
|
|
17
|
+
* @param key key of the fetch; a new key triggers a new fetch
|
|
18
|
+
* @param fetchMethod function that fetches the data of a key. It must be stable (e.g. defined outside the component),
|
|
19
|
+
* since a new function also triggers a new fetch
|
|
20
|
+
* @return the data, the error and the loading state of the current key
|
|
21
|
+
*/
|
|
22
|
+
export declare function useKeyedService<T>(key: ServiceKey, fetchMethod: (key: ServiceKey) => Promise<T>): UseKeyedService<T>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
// src/hook/useKeyedService.ts
|
|
4
|
+
/**
|
|
5
|
+
* Fetches data that depends on a key (e.g. a filter of the screen) and exposes only the result of the current key.
|
|
6
|
+
* When the key changes, the data and the error of the previous fetch are no longer exposed and `loading` becomes
|
|
7
|
+
* `true` until the new fetch finishes, so the screen never shows data of another selection. A response that arrives
|
|
8
|
+
* after the key changed is discarded.
|
|
9
|
+
* @param key key of the fetch; a new key triggers a new fetch
|
|
10
|
+
* @param fetchMethod function that fetches the data of a key. It must be stable (e.g. defined outside the component),
|
|
11
|
+
* since a new function also triggers a new fetch
|
|
12
|
+
* @return the data, the error and the loading state of the current key
|
|
13
|
+
*/
|
|
14
|
+
function useKeyedService(key, fetchMethod) {
|
|
15
|
+
const [result, setResult] = useState();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let obsolete = false;
|
|
18
|
+
fetchMethod(key).then((data) => !obsolete && setResult({
|
|
19
|
+
key,
|
|
20
|
+
data
|
|
21
|
+
})).catch((error) => !obsolete && setResult({
|
|
22
|
+
key,
|
|
23
|
+
error
|
|
24
|
+
}));
|
|
25
|
+
return () => {
|
|
26
|
+
obsolete = true;
|
|
27
|
+
};
|
|
28
|
+
}, [key, fetchMethod]);
|
|
29
|
+
const current = result?.key === key ? result : void 0;
|
|
30
|
+
return {
|
|
31
|
+
data: current?.data,
|
|
32
|
+
error: current?.error,
|
|
33
|
+
loading: !current
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export { useKeyedService };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=useKeyedService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeyedService.js","names":[],"sources":["../../src/hook/useKeyedService.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/** Key of a fetch (e.g. the year being queried), which tells which selection a result belongs to. */\nexport type ServiceKey = string | number;\n\n/** Values returned by {@link useKeyedService}. */\nexport type UseKeyedService<T> = {\n /** Data of the fetch of the current key; `undefined` while it has not finished or if it failed. */\n data?: T;\n\n /** Error of the fetch of the current key; `undefined` if it has not finished yet or succeeded. */\n error?: unknown;\n\n /** Whether the fetch of the current key has not finished yet. */\n loading: boolean;\n};\n\n/** Result of a fetch, kept with the key that was queried. */\ntype KeyedResult<T> = { key: ServiceKey; data?: T; error?: unknown };\n\n/**\n * Fetches data that depends on a key (e.g. a filter of the screen) and exposes only the result of the current key.\n * When the key changes, the data and the error of the previous fetch are no longer exposed and `loading` becomes\n * `true` until the new fetch finishes, so the screen never shows data of another selection. A response that arrives\n * after the key changed is discarded.\n * @param key key of the fetch; a new key triggers a new fetch\n * @param fetchMethod function that fetches the data of a key. It must be stable (e.g. defined outside the component),\n * since a new function also triggers a new fetch\n * @return the data, the error and the loading state of the current key\n */\nexport function useKeyedService<T>(key: ServiceKey, fetchMethod: (key: ServiceKey) => Promise<T>): UseKeyedService<T> {\n const [result, setResult] = useState<KeyedResult<T>>();\n\n useEffect(() => {\n // If the key changes before the fetch finishes, its response cannot replace the one of the new key.\n let obsolete = false;\n fetchMethod(key)\n .then(data => !obsolete && setResult({ key, data }))\n .catch(error => !obsolete && setResult({ key, error }));\n\n return () => {\n obsolete = true;\n };\n }, [key, fetchMethod]);\n\n // A result of another key stays in the state until the new fetch finishes: it is not exposed.\n const current = result?.key === key ? result : undefined;\n return { data: current?.data, error: current?.error, loading: !current };\n}\n"],"mappings":";;;;;;;;;;;;;AA8BA,SAAgB,gBAAmB,KAAiB,aAAkE;CAClH,MAAM,CAAC,QAAQ,aAAa,SAAyB;CAErD,gBAAgB;EAEZ,IAAI,WAAW;EACf,YAAY,GAAG,CAAC,CACX,MAAK,SAAQ,CAAC,YAAY,UAAU;GAAE;GAAK;EAAK,CAAC,CAAC,CAAC,CACnD,OAAM,UAAS,CAAC,YAAY,UAAU;GAAE;GAAK;EAAM,CAAC,CAAC;EAE1D,aAAa;GACT,WAAW;EACf;CACJ,GAAG,CAAC,KAAK,WAAW,CAAC;CAGrB,MAAM,UAAU,QAAQ,QAAQ,MAAM,SAAS,KAAA;CAC/C,OAAO;EAAE,MAAM,SAAS;EAAM,OAAO,SAAS;EAAO,SAAS,CAAC;CAAQ;AAC3E"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Always prints the page with the light color scheme, even if the user uses the dark one: on paper (or in a PDF),
|
|
3
|
+
* light text on a dark background wastes ink and is hard to read. The scheme changes only while the print dialog is
|
|
4
|
+
* open (`beforeprint`/`afterprint`), without changing the preference saved by the user.
|
|
5
|
+
*
|
|
6
|
+
* It changes only what comes from the Mantine CSS variables. A component that chooses the color in JavaScript from the
|
|
7
|
+
* color scheme (e.g. with `useMantineColorScheme`) is not redrawn and keeps the dark colors.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useLightColorSchemeOnPrint(): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
// src/hook/useLightColorSchemeOnPrint.ts
|
|
4
|
+
/** Attribute where Mantine stores the color scheme of the page (`light` or `dark`). */
|
|
5
|
+
var COLOR_SCHEME_ATTRIBUTE = "data-mantine-color-scheme";
|
|
6
|
+
/**
|
|
7
|
+
* Always prints the page with the light color scheme, even if the user uses the dark one: on paper (or in a PDF),
|
|
8
|
+
* light text on a dark background wastes ink and is hard to read. The scheme changes only while the print dialog is
|
|
9
|
+
* open (`beforeprint`/`afterprint`), without changing the preference saved by the user.
|
|
10
|
+
*
|
|
11
|
+
* It changes only what comes from the Mantine CSS variables. A component that chooses the color in JavaScript from the
|
|
12
|
+
* color scheme (e.g. with `useMantineColorScheme`) is not redrawn and keeps the dark colors.
|
|
13
|
+
*/
|
|
14
|
+
function useLightColorSchemeOnPrint() {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const html = document.documentElement;
|
|
17
|
+
let savedScheme = null;
|
|
18
|
+
const beforePrint = () => {
|
|
19
|
+
savedScheme = html.getAttribute(COLOR_SCHEME_ATTRIBUTE);
|
|
20
|
+
html.setAttribute(COLOR_SCHEME_ATTRIBUTE, "light");
|
|
21
|
+
};
|
|
22
|
+
const afterPrint = () => {
|
|
23
|
+
if (savedScheme) html.setAttribute(COLOR_SCHEME_ATTRIBUTE, savedScheme);
|
|
24
|
+
else html.removeAttribute(COLOR_SCHEME_ATTRIBUTE);
|
|
25
|
+
};
|
|
26
|
+
window.addEventListener("beforeprint", beforePrint);
|
|
27
|
+
window.addEventListener("afterprint", afterPrint);
|
|
28
|
+
return () => {
|
|
29
|
+
window.removeEventListener("beforeprint", beforePrint);
|
|
30
|
+
window.removeEventListener("afterprint", afterPrint);
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
}
|
|
34
|
+
export { useLightColorSchemeOnPrint };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=useLightColorSchemeOnPrint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLightColorSchemeOnPrint.js","names":[],"sources":["../../src/hook/useLightColorSchemeOnPrint.ts"],"sourcesContent":["import { useEffect } from 'react';\n\n/** Attribute where Mantine stores the color scheme of the page (`light` or `dark`). */\nconst COLOR_SCHEME_ATTRIBUTE = 'data-mantine-color-scheme';\n\n/**\n * Always prints the page with the light color scheme, even if the user uses the dark one: on paper (or in a PDF),\n * light text on a dark background wastes ink and is hard to read. The scheme changes only while the print dialog is\n * open (`beforeprint`/`afterprint`), without changing the preference saved by the user.\n *\n * It changes only what comes from the Mantine CSS variables. A component that chooses the color in JavaScript from the\n * color scheme (e.g. with `useMantineColorScheme`) is not redrawn and keeps the dark colors.\n */\nexport function useLightColorSchemeOnPrint(): void {\n useEffect(() => {\n const html = document.documentElement;\n let savedScheme: string | null = null;\n\n const beforePrint = (): void => {\n savedScheme = html.getAttribute(COLOR_SCHEME_ATTRIBUTE);\n html.setAttribute(COLOR_SCHEME_ATTRIBUTE, 'light');\n };\n // Without a scheme before printing, removes the attribute, instead of leaving the light scheme set.\n const afterPrint = (): void => {\n if (savedScheme) html.setAttribute(COLOR_SCHEME_ATTRIBUTE, savedScheme);\n else html.removeAttribute(COLOR_SCHEME_ATTRIBUTE);\n };\n\n window.addEventListener('beforeprint', beforePrint);\n window.addEventListener('afterprint', afterPrint);\n return (): void => {\n window.removeEventListener('beforeprint', beforePrint);\n window.removeEventListener('afterprint', afterPrint);\n };\n }, []);\n}\n"],"mappings":";;;;AAGA,IAAM,yBAAyB;;;;;;;;;AAU/B,SAAgB,6BAAmC;CAC/C,gBAAgB;EACZ,MAAM,OAAO,SAAS;EACtB,IAAI,cAA6B;EAEjC,MAAM,oBAA0B;GAC5B,cAAc,KAAK,aAAa,sBAAsB;GACtD,KAAK,aAAa,wBAAwB,OAAO;EACrD;EAEA,MAAM,mBAAyB;GAC3B,IAAI,aAAa,KAAK,aAAa,wBAAwB,WAAW;QACjE,KAAK,gBAAgB,sBAAsB;EACpD;EAEA,OAAO,iBAAiB,eAAe,WAAW;EAClD,OAAO,iBAAiB,cAAc,UAAU;EAChD,aAAmB;GACf,OAAO,oBAAoB,eAAe,WAAW;GACrD,OAAO,oBAAoB,cAAc,UAAU;EACvD;CACJ,GAAG,CAAC,CAAC;AACT"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Values returned by {@link useService}. */
|
|
2
|
+
export type UseService<D> = {
|
|
3
|
+
/** Data of the fetch, or the initial value while it has not finished (or if it failed). */
|
|
4
|
+
data: D;
|
|
5
|
+
/** Error of the fetch; `null` if it has not finished yet or succeeded. */
|
|
6
|
+
error: unknown | null;
|
|
7
|
+
/** Whether the fetch has not finished yet. */
|
|
8
|
+
loading: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Fetches data when the component mounts and every time `fetchMethod` changes.
|
|
12
|
+
* Without an initial value, `data` is `undefined` while loading (or after a failure), so the caller must handle it.
|
|
13
|
+
* @param fetchMethod function that fetches the data. It must be stable (e.g. with `useCallback`), since a new function
|
|
14
|
+
* triggers a new fetch
|
|
15
|
+
* @return the data (`undefined` until the fetch finishes), the error and whether the fetch is still running
|
|
16
|
+
*/
|
|
17
|
+
declare function useService<T>(fetchMethod: () => Promise<T>): UseService<T | undefined>;
|
|
18
|
+
/**
|
|
19
|
+
* Fetches data when the component mounts and every time `fetchMethod` changes, starting with the given value (e.g. an
|
|
20
|
+
* empty array for a list), so `data` always has the type of the fetched data.
|
|
21
|
+
* @param fetchMethod function that fetches the data. It must be stable (e.g. with `useCallback`), since a new function
|
|
22
|
+
* triggers a new fetch
|
|
23
|
+
* @param initialData value of `data` until the fetch finishes (and after a failure)
|
|
24
|
+
* @return the data, the error and whether the fetch is still running
|
|
25
|
+
*/
|
|
26
|
+
declare function useService<T>(fetchMethod: () => Promise<T>, initialData: T): UseService<T>;
|
|
27
|
+
export default useService;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
// src/hook/useService.ts
|
|
4
|
+
function useService(fetchMethod, initialData) {
|
|
5
|
+
const [data, setData] = useState(initialData);
|
|
6
|
+
const [error, setError] = useState(null);
|
|
7
|
+
const [loading, setLoading] = useState(true);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
let obsolete = false;
|
|
10
|
+
fetchMethod().then((responseData) => !obsolete && setData(responseData)).catch((e) => !obsolete && setError(e)).finally(() => !obsolete && setLoading(false));
|
|
11
|
+
return () => {
|
|
12
|
+
obsolete = true;
|
|
13
|
+
};
|
|
14
|
+
}, [fetchMethod]);
|
|
15
|
+
return {
|
|
16
|
+
data,
|
|
17
|
+
error,
|
|
18
|
+
loading
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export { useService as default };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=useService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useService.js","names":[],"sources":["../../src/hook/useService.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/** Values returned by {@link useService}. */\nexport type UseService<D> = {\n /** Data of the fetch, or the initial value while it has not finished (or if it failed). */\n data: D;\n\n /** Error of the fetch; `null` if it has not finished yet or succeeded. */\n error: unknown | null;\n\n /** Whether the fetch has not finished yet. */\n loading: boolean;\n};\n\n/**\n * Fetches data when the component mounts and every time `fetchMethod` changes.\n * Without an initial value, `data` is `undefined` while loading (or after a failure), so the caller must handle it.\n * @param fetchMethod function that fetches the data. It must be stable (e.g. with `useCallback`), since a new function\n * triggers a new fetch\n * @return the data (`undefined` until the fetch finishes), the error and whether the fetch is still running\n */\nfunction useService<T>(fetchMethod: () => Promise<T>): UseService<T | undefined>;\n\n/**\n * Fetches data when the component mounts and every time `fetchMethod` changes, starting with the given value (e.g. an\n * empty array for a list), so `data` always has the type of the fetched data.\n * @param fetchMethod function that fetches the data. It must be stable (e.g. with `useCallback`), since a new function\n * triggers a new fetch\n * @param initialData value of `data` until the fetch finishes (and after a failure)\n * @return the data, the error and whether the fetch is still running\n */\nfunction useService<T>(fetchMethod: () => Promise<T>, initialData: T): UseService<T>;\n\nfunction useService<T>(fetchMethod: () => Promise<T>, initialData?: T): UseService<T | undefined> {\n const [data, setData] = useState<T | undefined>(initialData);\n const [error, setError] = useState<unknown | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n /* When fetchMethod changes (e.g. another filter), the previous fetch becomes obsolete. If its response arrives\n after the one of the new fetch, it cannot overwrite the current data. */\n let obsolete = false;\n fetchMethod()\n .then(responseData => !obsolete && setData(responseData))\n .catch(e => !obsolete && setError(e))\n .finally(() => !obsolete && setLoading(false));\n\n return () => {\n obsolete = true;\n };\n }, [fetchMethod]);\n\n return { data, error, loading };\n}\n\nexport default useService;\n"],"mappings":";;;AAiCA,SAAS,WAAc,aAA+B,aAA4C;CAC9F,MAAM,CAAC,MAAM,WAAW,SAAwB,WAAW;CAC3D,MAAM,CAAC,OAAO,YAAY,SAAyB,IAAI;CACvD,MAAM,CAAC,SAAS,cAAc,SAAS,IAAI;CAE3C,gBAAgB;EAGZ,IAAI,WAAW;EACf,YAAY,CAAC,CACR,MAAK,iBAAgB,CAAC,YAAY,QAAQ,YAAY,CAAC,CAAC,CACxD,OAAM,MAAK,CAAC,YAAY,SAAS,CAAC,CAAC,CAAC,CACpC,cAAc,CAAC,YAAY,WAAW,KAAK,CAAC;EAEjD,aAAa;GACT,WAAW;EACf;CACJ,GAAG,CAAC,WAAW,CAAC;CAEhB,OAAO;EAAE;EAAM;EAAO;CAAQ;AAClC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error of a request to the API, with the user-friendly message already extracted by the {@link AxiosHttpClient}
|
|
3
|
+
* and, optionally, the `code` returned by the backend. The `code` allows the code that handles the error to identify
|
|
4
|
+
* the reason programmatically (e.g. a concurrent update), without relying on the text of `message`, which is just for
|
|
5
|
+
* display.
|
|
6
|
+
* @template C type of the error codes of the backend. An app may restrict it to the codes the backend sends (e.g. a
|
|
7
|
+
* union of strings generated from a backend enum), so the compiler points out codes that no longer exist.
|
|
8
|
+
* @author Manoel Campos
|
|
9
|
+
*/
|
|
10
|
+
export declare class ApiError<C extends string = string> extends Error {
|
|
11
|
+
readonly code?: C;
|
|
12
|
+
constructor(message: string, code?: C);
|
|
13
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/http/ApiError.ts
|
|
3
|
+
/**
|
|
4
|
+
* Error of a request to the API, with the user-friendly message already extracted by the {@link AxiosHttpClient}
|
|
5
|
+
* and, optionally, the `code` returned by the backend. The `code` allows the code that handles the error to identify
|
|
6
|
+
* the reason programmatically (e.g. a concurrent update), without relying on the text of `message`, which is just for
|
|
7
|
+
* display.
|
|
8
|
+
* @template C type of the error codes of the backend. An app may restrict it to the codes the backend sends (e.g. a
|
|
9
|
+
* union of strings generated from a backend enum), so the compiler points out codes that no longer exist.
|
|
10
|
+
* @author Manoel Campos
|
|
11
|
+
*/
|
|
12
|
+
var ApiError = class extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(message, code) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "ApiError";
|
|
17
|
+
this.code = code;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export { ApiError };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=ApiError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiError.js","names":[],"sources":["../../src/http/ApiError.ts"],"sourcesContent":["/**\n * Error of a request to the API, with the user-friendly message already extracted by the {@link AxiosHttpClient}\n * and, optionally, the `code` returned by the backend. The `code` allows the code that handles the error to identify\n * the reason programmatically (e.g. a concurrent update), without relying on the text of `message`, which is just for\n * display.\n * @template C type of the error codes of the backend. An app may restrict it to the codes the backend sends (e.g. a\n * union of strings generated from a backend enum), so the compiler points out codes that no longer exist.\n * @author Manoel Campos\n */\nexport class ApiError<C extends string = string> extends Error {\n public readonly code?: C;\n\n constructor(message: string, code?: C) {\n super(message);\n this.name = 'ApiError';\n this.code = code;\n }\n}\n"],"mappings":";;;;;;;;;;;AASA,IAAa,WAAb,cAAyD,MAAM;CAC3D;CAEA,YAAY,SAAiB,MAAU;EACnC,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;CAChB;AACJ"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
2
|
+
import { AxiosHttpClientConfig } from './AxiosHttpClientConfig';
|
|
3
|
+
/**
|
|
4
|
+
* HTTP client of a REST API, on top of Axios. It centralizes the error handling: converts backend errors into an
|
|
5
|
+
* {@link ApiError}, with the user-friendly message and the error code, and network errors into a plain `Error`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AxiosHttpClient {
|
|
8
|
+
private readonly _axiosInstance;
|
|
9
|
+
private readonly _errorParser;
|
|
10
|
+
private readonly _messages;
|
|
11
|
+
constructor(config: AxiosHttpClientConfig);
|
|
12
|
+
/** Axios instance used in the requests, so the app can register interceptors (e.g. the authentication token). */
|
|
13
|
+
get axiosInstance(): AxiosInstance;
|
|
14
|
+
private _handleRequest;
|
|
15
|
+
private _handleError;
|
|
16
|
+
post<T>(path: string, data?: unknown, options?: AxiosRequestConfig): Promise<T>;
|
|
17
|
+
get<T>(path: string, options?: AxiosRequestConfig): Promise<T>;
|
|
18
|
+
put<T>(path: string, data?: unknown, options?: AxiosRequestConfig): Promise<T>;
|
|
19
|
+
patch<T>(path: string, data?: unknown, options?: AxiosRequestConfig): Promise<T>;
|
|
20
|
+
delete<T>(path: string, options?: AxiosRequestConfig): Promise<T>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { resolveMessages } from "../i18n/resolveMessages.js";
|
|
3
|
+
import { ApiError } from "./ApiError.js";
|
|
4
|
+
import { parseErrorBody } from "./AxiosHttpClientConfig.js";
|
|
5
|
+
import axios from "axios";
|
|
6
|
+
// src/http/AxiosHttpClient.ts
|
|
7
|
+
/**
|
|
8
|
+
* HTTP client of a REST API, on top of Axios. It centralizes the error handling: converts backend errors into an
|
|
9
|
+
* {@link ApiError}, with the user-friendly message and the error code, and network errors into a plain `Error`.
|
|
10
|
+
*/
|
|
11
|
+
var AxiosHttpClient = class {
|
|
12
|
+
_axiosInstance;
|
|
13
|
+
_errorParser;
|
|
14
|
+
_messages;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this._axiosInstance = axios.create({
|
|
17
|
+
baseURL: config.baseURL,
|
|
18
|
+
timeout: config.timeout ?? 5e3,
|
|
19
|
+
withCredentials: config.withCredentials ?? false,
|
|
20
|
+
headers: config.headers
|
|
21
|
+
});
|
|
22
|
+
this._errorParser = config.errorParser ?? parseErrorBody;
|
|
23
|
+
this._messages = resolveMessages(config.locale, { http: config.messages }).http;
|
|
24
|
+
}
|
|
25
|
+
/** Axios instance used in the requests, so the app can register interceptors (e.g. the authentication token). */
|
|
26
|
+
get axiosInstance() {
|
|
27
|
+
return this._axiosInstance;
|
|
28
|
+
}
|
|
29
|
+
async _handleRequest(method, path, data, options) {
|
|
30
|
+
try {
|
|
31
|
+
return (await this._axiosInstance.request({
|
|
32
|
+
method,
|
|
33
|
+
url: path,
|
|
34
|
+
data,
|
|
35
|
+
...options
|
|
36
|
+
})).data;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw this._handleError(error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
_handleError(error) {
|
|
42
|
+
if (axios.isAxiosError(error) && error.response) {
|
|
43
|
+
const { message, code } = this._errorParser(error.response.data);
|
|
44
|
+
return new ApiError(message || this._messages.unknownError, code);
|
|
45
|
+
}
|
|
46
|
+
if (error.request) return new Error(this._messages.noResponse);
|
|
47
|
+
return new Error(error.message || this._messages.requestFailed);
|
|
48
|
+
}
|
|
49
|
+
async post(path, data, options) {
|
|
50
|
+
return this._handleRequest("post", path, data, options);
|
|
51
|
+
}
|
|
52
|
+
async get(path, options) {
|
|
53
|
+
return this._handleRequest("get", path, void 0, options);
|
|
54
|
+
}
|
|
55
|
+
async put(path, data, options) {
|
|
56
|
+
return this._handleRequest("put", path, data, options);
|
|
57
|
+
}
|
|
58
|
+
async patch(path, data, options) {
|
|
59
|
+
return this._handleRequest("patch", path, data, options);
|
|
60
|
+
}
|
|
61
|
+
async delete(path, options) {
|
|
62
|
+
return this._handleRequest("delete", path, void 0, options);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
export { AxiosHttpClient };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=AxiosHttpClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AxiosHttpClient.js","names":[],"sources":["../../src/http/AxiosHttpClient.ts"],"sourcesContent":["import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';\n\nimport { HttpMessages } from '../i18n/KitMessages';\nimport { resolveMessages } from '../i18n/resolveMessages';\nimport { ApiError } from './ApiError';\nimport { AxiosHttpClientConfig, DEFAULT_TIMEOUT_MS, ParsedApiError, parseErrorBody } from './AxiosHttpClientConfig';\n\n/**\n * HTTP client of a REST API, on top of Axios. It centralizes the error handling: converts backend errors into an\n * {@link ApiError}, with the user-friendly message and the error code, and network errors into a plain `Error`.\n */\nexport class AxiosHttpClient {\n private readonly _axiosInstance: AxiosInstance;\n private readonly _errorParser: (body: unknown) => ParsedApiError;\n private readonly _messages: HttpMessages;\n\n constructor(config: AxiosHttpClientConfig) {\n this._axiosInstance = axios.create({\n baseURL: config.baseURL,\n timeout: config.timeout ?? DEFAULT_TIMEOUT_MS,\n withCredentials: config.withCredentials ?? false,\n headers: config.headers\n });\n this._errorParser = config.errorParser ?? parseErrorBody;\n this._messages = resolveMessages(config.locale, { http: config.messages }).http;\n }\n\n /** Axios instance used in the requests, so the app can register interceptors (e.g. the authentication token). */\n public get axiosInstance(): AxiosInstance {\n return this._axiosInstance;\n }\n\n private async _handleRequest<T>(\n method: string,\n path: string,\n data?: unknown,\n options?: AxiosRequestConfig\n ): Promise<T> {\n try {\n const response: AxiosResponse<T> = await this._axiosInstance.request<T>({\n method,\n url: path,\n data,\n ...options\n });\n\n return response.data;\n } catch (error) {\n throw this._handleError(error as AxiosError);\n }\n }\n\n private _handleError(error: AxiosError): Error {\n if (axios.isAxiosError(error) && error.response) {\n const { message, code } = this._errorParser(error.response.data);\n return new ApiError(message || this._messages.unknownError, code);\n }\n\n if (error.request) {\n return new Error(this._messages.noResponse);\n }\n\n return new Error(error.message || this._messages.requestFailed);\n }\n\n public async post<T>(path: string, data?: unknown, options?: AxiosRequestConfig): Promise<T> {\n return this._handleRequest<T>('post', path, data, options);\n }\n\n public async get<T>(path: string, options?: AxiosRequestConfig): Promise<T> {\n return this._handleRequest<T>('get', path, undefined, options);\n }\n\n public async put<T>(path: string, data?: unknown, options?: AxiosRequestConfig): Promise<T> {\n return this._handleRequest<T>('put', path, data, options);\n }\n\n public async patch<T>(path: string, data?: unknown, options?: AxiosRequestConfig): Promise<T> {\n return this._handleRequest<T>('patch', path, data, options);\n }\n\n public async delete<T>(path: string, options?: AxiosRequestConfig): Promise<T> {\n return this._handleRequest<T>('delete', path, undefined, options);\n }\n}\n"],"mappings":";;;;;;;;;;AAWA,IAAa,kBAAb,MAA6B;CACzB;CACA;CACA;CAEA,YAAY,QAA+B;EACvC,KAAK,iBAAiB,MAAM,OAAO;GAC/B,SAAS,OAAO;GAChB,SAAS,OAAO,WAAA;GAChB,iBAAiB,OAAO,mBAAmB;GAC3C,SAAS,OAAO;EACpB,CAAC;EACD,KAAK,eAAe,OAAO,eAAe;EAC1C,KAAK,YAAY,gBAAgB,OAAO,QAAQ,EAAE,MAAM,OAAO,SAAS,CAAC,CAAC,CAAC;CAC/E;;CAGA,IAAW,gBAA+B;EACtC,OAAO,KAAK;CAChB;CAEA,MAAc,eACV,QACA,MACA,MACA,SACU;EACV,IAAI;GAQA,QAAO,MAPkC,KAAK,eAAe,QAAW;IACpE;IACA,KAAK;IACL;IACA,GAAG;GACP,CAAC,EAAA,CAEe;EACpB,SAAS,OAAO;GACZ,MAAM,KAAK,aAAa,KAAmB;EAC/C;CACJ;CAEA,aAAqB,OAA0B;EAC3C,IAAI,MAAM,aAAa,KAAK,KAAK,MAAM,UAAU;GAC7C,MAAM,EAAE,SAAS,SAAS,KAAK,aAAa,MAAM,SAAS,IAAI;GAC/D,OAAO,IAAI,SAAS,WAAW,KAAK,UAAU,cAAc,IAAI;EACpE;EAEA,IAAI,MAAM,SACN,OAAO,IAAI,MAAM,KAAK,UAAU,UAAU;EAG9C,OAAO,IAAI,MAAM,MAAM,WAAW,KAAK,UAAU,aAAa;CAClE;CAEA,MAAa,KAAQ,MAAc,MAAgB,SAA0C;EACzF,OAAO,KAAK,eAAkB,QAAQ,MAAM,MAAM,OAAO;CAC7D;CAEA,MAAa,IAAO,MAAc,SAA0C;EACxE,OAAO,KAAK,eAAkB,OAAO,MAAM,KAAA,GAAW,OAAO;CACjE;CAEA,MAAa,IAAO,MAAc,MAAgB,SAA0C;EACxF,OAAO,KAAK,eAAkB,OAAO,MAAM,MAAM,OAAO;CAC5D;CAEA,MAAa,MAAS,MAAc,MAAgB,SAA0C;EAC1F,OAAO,KAAK,eAAkB,SAAS,MAAM,MAAM,OAAO;CAC9D;CAEA,MAAa,OAAU,MAAc,SAA0C;EAC3E,OAAO,KAAK,eAAkB,UAAU,MAAM,KAAA,GAAW,OAAO;CACpE;AACJ"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { KitLocale } from '../i18n/KitLocale';
|
|
2
|
+
import { HttpMessages } from '../i18n/KitMessages';
|
|
3
|
+
/** Message and code extracted from the body of an error response of the backend. */
|
|
4
|
+
export type ParsedApiError = {
|
|
5
|
+
/** Message to show to the user; if absent, a generic message is used. */
|
|
6
|
+
message?: string;
|
|
7
|
+
/** Code that identifies the reason of the error (see {@link ApiError}). */
|
|
8
|
+
code?: string;
|
|
9
|
+
};
|
|
10
|
+
/** Configuration of an {@link AxiosHttpClient}. */
|
|
11
|
+
export type AxiosHttpClientConfig = {
|
|
12
|
+
/** Address of the API, prefixed to the paths of the requests (e.g. `http://localhost:8080`). */
|
|
13
|
+
baseURL: string;
|
|
14
|
+
/** Maximum time to wait for a response (ms). Default: {@link DEFAULT_TIMEOUT_MS}. */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** Whether cookies and credentials are sent in requests to another origin. Default: `false`. */
|
|
17
|
+
withCredentials?: boolean;
|
|
18
|
+
/** Headers sent in every request. */
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Extracts the message and the code from the body of an error response. The default ({@link parseErrorBody})
|
|
22
|
+
* reads the `message` and `code` fields of a JSON object (e.g. the error body of a Spring API).
|
|
23
|
+
*/
|
|
24
|
+
errorParser?: (body: unknown) => ParsedApiError;
|
|
25
|
+
/** Locale of the generic error messages. Default: `en-US`. */
|
|
26
|
+
locale?: KitLocale;
|
|
27
|
+
/** Generic error messages, replacing the ones of the locale. */
|
|
28
|
+
messages?: Partial<HttpMessages>;
|
|
29
|
+
};
|
|
30
|
+
/** Default maximum time to wait for a response (ms). */
|
|
31
|
+
export declare const DEFAULT_TIMEOUT_MS = 5000;
|
|
32
|
+
/**
|
|
33
|
+
* Default error parser: reads the `message` and `code` fields of the response body, if it is an object.
|
|
34
|
+
* @param body body of the error response
|
|
35
|
+
* @return the message and the code found
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseErrorBody(body: unknown): ParsedApiError;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/http/AxiosHttpClientConfig.ts
|
|
3
|
+
/** Default maximum time to wait for a response (ms). */
|
|
4
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
5
|
+
/**
|
|
6
|
+
* Default error parser: reads the `message` and `code` fields of the response body, if it is an object.
|
|
7
|
+
* @param body body of the error response
|
|
8
|
+
* @return the message and the code found
|
|
9
|
+
*/
|
|
10
|
+
function parseErrorBody(body) {
|
|
11
|
+
if (body === null || typeof body !== "object") return {};
|
|
12
|
+
return {
|
|
13
|
+
message: "message" in body && body.message ? String(body.message) : void 0,
|
|
14
|
+
code: "code" in body && body.code ? String(body.code) : void 0
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export { DEFAULT_TIMEOUT_MS, parseErrorBody };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=AxiosHttpClientConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AxiosHttpClientConfig.js","names":[],"sources":["../../src/http/AxiosHttpClientConfig.ts"],"sourcesContent":["import { KitLocale } from '../i18n/KitLocale';\nimport { HttpMessages } from '../i18n/KitMessages';\n\n/** Message and code extracted from the body of an error response of the backend. */\nexport type ParsedApiError = {\n /** Message to show to the user; if absent, a generic message is used. */\n message?: string;\n\n /** Code that identifies the reason of the error (see {@link ApiError}). */\n code?: string;\n};\n\n/** Configuration of an {@link AxiosHttpClient}. */\nexport type AxiosHttpClientConfig = {\n /** Address of the API, prefixed to the paths of the requests (e.g. `http://localhost:8080`). */\n baseURL: string;\n\n /** Maximum time to wait for a response (ms). Default: {@link DEFAULT_TIMEOUT_MS}. */\n timeout?: number;\n\n /** Whether cookies and credentials are sent in requests to another origin. Default: `false`. */\n withCredentials?: boolean;\n\n /** Headers sent in every request. */\n headers?: Record<string, string>;\n\n /**\n * Extracts the message and the code from the body of an error response. The default ({@link parseErrorBody})\n * reads the `message` and `code` fields of a JSON object (e.g. the error body of a Spring API).\n */\n errorParser?: (body: unknown) => ParsedApiError;\n\n /** Locale of the generic error messages. Default: `en-US`. */\n locale?: KitLocale;\n\n /** Generic error messages, replacing the ones of the locale. */\n messages?: Partial<HttpMessages>;\n};\n\n/** Default maximum time to wait for a response (ms). */\nexport const DEFAULT_TIMEOUT_MS = 5000;\n\n/**\n * Default error parser: reads the `message` and `code` fields of the response body, if it is an object.\n * @param body body of the error response\n * @return the message and the code found\n */\nexport function parseErrorBody(body: unknown): ParsedApiError {\n if (body === null || typeof body !== 'object') return {};\n\n const message = 'message' in body && body.message ? String(body.message) : undefined;\n const code = 'code' in body && body.code ? String(body.code) : undefined;\n\n return { message, code };\n}\n"],"mappings":";;;AAwCA,IAAa,qBAAqB;;;;;;AAOlC,SAAgB,eAAe,MAA+B;CAC1D,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU,OAAO,CAAC;CAKvD,OAAO;EAAE,SAHO,aAAa,QAAQ,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI,KAAA;EAGzD,MAFL,UAAU,QAAQ,KAAK,OAAO,OAAO,KAAK,IAAI,IAAI,KAAA;CAExC;AAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KitLocale.js","names":[],"sources":["../../src/i18n/KitLocale.ts"],"sourcesContent":["/** Locales with a built-in message catalog. */\nexport type KitLocale = 'pt-BR' | 'en-US';\n\n/** Locale used when the app does not choose one. */\nexport const DEFAULT_LOCALE: KitLocale = 'en-US';\n"],"mappings":";;;AAIA,IAAa,iBAA4B"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { ChartTypeId } from '../component/organism/EChart/chart/ChartTypeId';
|
|
2
|
+
/** Pagination range shown below a table (e.g. "Showing 1 to 10 of 42 records"). */
|
|
3
|
+
export type PaginationRange = {
|
|
4
|
+
from: number;
|
|
5
|
+
to: number;
|
|
6
|
+
totalRecords: number;
|
|
7
|
+
};
|
|
8
|
+
/** Action of a CRUD form, used to build its titles and messages. */
|
|
9
|
+
export type FormAction = 'create' | 'edit' | 'view' | 'custom';
|
|
10
|
+
/** Texts shared by many components. */
|
|
11
|
+
export type CommonMessages = {
|
|
12
|
+
back: string;
|
|
13
|
+
save: string;
|
|
14
|
+
cancel: string;
|
|
15
|
+
confirm: string;
|
|
16
|
+
add: string;
|
|
17
|
+
home: string;
|
|
18
|
+
success: string;
|
|
19
|
+
warning: string;
|
|
20
|
+
error: string;
|
|
21
|
+
/** Title of the alert shown when the data of a component cannot be loaded. */
|
|
22
|
+
loadError: string;
|
|
23
|
+
/** Date format of date fields, in Day.js tokens (e.g. `DD/MM/YYYY`). */
|
|
24
|
+
dateFormat: string;
|
|
25
|
+
};
|
|
26
|
+
/** Texts of the CRUD form templates (`FormPage`, `CreateFormPage`, `EditFormPage`, `ViewPage`, `DataForm`). */
|
|
27
|
+
export type FormMessages = {
|
|
28
|
+
/** Verb of each form action, used in titles and buttons (e.g. "Create", "Update"). */
|
|
29
|
+
action: Record<FormAction, string>;
|
|
30
|
+
/** Message shown after the record is saved, built from the action verb. */
|
|
31
|
+
saveSuccess: (action: string) => string;
|
|
32
|
+
/** Message shown when the record cannot be saved, built from the action verb. */
|
|
33
|
+
saveError: (action: string) => string;
|
|
34
|
+
createSuccess: string;
|
|
35
|
+
createError: string;
|
|
36
|
+
updateSuccess: string;
|
|
37
|
+
updateError: string;
|
|
38
|
+
/** Title of the confirmation dialog shown before submitting a form that asks for it. */
|
|
39
|
+
confirmTitle: string;
|
|
40
|
+
};
|
|
41
|
+
/** Texts of the tables (`Table`, `ViewTable`, `ListPage`). */
|
|
42
|
+
export type TableMessages = {
|
|
43
|
+
actions: string;
|
|
44
|
+
view: string;
|
|
45
|
+
edit: string;
|
|
46
|
+
delete: string;
|
|
47
|
+
deleteConfirm: string;
|
|
48
|
+
deleteSuccess: string;
|
|
49
|
+
noRecords: string;
|
|
50
|
+
recordsPerPage: string;
|
|
51
|
+
pagination: (range: PaginationRange) => string;
|
|
52
|
+
/** Title of the card that holds the table of a list page, built from the plural name of the records. */
|
|
53
|
+
listTitle: (pluralName: string) => string;
|
|
54
|
+
};
|
|
55
|
+
/** Tooltips of the buttons that edit a table row in place. */
|
|
56
|
+
export type RowEditMessages = {
|
|
57
|
+
edit: string;
|
|
58
|
+
confirm: string;
|
|
59
|
+
cancel: string;
|
|
60
|
+
};
|
|
61
|
+
/** Texts of the `SelectField`. */
|
|
62
|
+
export type SelectMessages = {
|
|
63
|
+
/** Placeholder built from the field label, when the field has no placeholder of its own. */
|
|
64
|
+
placeholder: (label: string) => string;
|
|
65
|
+
/** Text shown when no option matches the search, built from the field label. */
|
|
66
|
+
nothingFound: (label: string) => string;
|
|
67
|
+
};
|
|
68
|
+
/** Texts of the `Layout` header and side menu. */
|
|
69
|
+
export type LayoutMessages = {
|
|
70
|
+
userMenu: string;
|
|
71
|
+
userMenuTitle: string;
|
|
72
|
+
enableDarkTheme: string;
|
|
73
|
+
enableLightTheme: string;
|
|
74
|
+
collapseNavigation: string;
|
|
75
|
+
expandNavigation: string;
|
|
76
|
+
};
|
|
77
|
+
/** Texts of the print pages (`PrintPage`). */
|
|
78
|
+
export type PrintMessages = {
|
|
79
|
+
pdfTipTitle: string;
|
|
80
|
+
pdfTip: string;
|
|
81
|
+
printButton: string;
|
|
82
|
+
};
|
|
83
|
+
/** Texts of the stats cards (`StatsCard`, `StatsGrid`). */
|
|
84
|
+
export type StatsMessages = {
|
|
85
|
+
comparedToLastMonth: string;
|
|
86
|
+
};
|
|
87
|
+
/** Texts of the exported files (Excel and CSV) and of the export button. */
|
|
88
|
+
export type ExportMessages = {
|
|
89
|
+
button: string;
|
|
90
|
+
/** Message shown when the export fails, built from the format name (e.g. "Excel (.xlsx)"). */
|
|
91
|
+
failed: (formatLabel: string) => string;
|
|
92
|
+
/** Date and time the data was generated, shown below the title (e.g. "Generated on 10/20/2026 at 2:30 PM"). */
|
|
93
|
+
generatedAt: (date: Date) => string;
|
|
94
|
+
/** Footer that tells which system generated the data. */
|
|
95
|
+
footer: (systemName: string) => string;
|
|
96
|
+
/**
|
|
97
|
+
* Page number in the footer of the printed spreadsheet, with the Excel header/footer codes `&P` (page) and `&N`
|
|
98
|
+
* (total pages).
|
|
99
|
+
*/
|
|
100
|
+
excelPageNumber: string;
|
|
101
|
+
/** Text of a cell whose value could not be computed. */
|
|
102
|
+
invalidCell: string;
|
|
103
|
+
/** File name used when the document name has no valid character. */
|
|
104
|
+
defaultFileName: string;
|
|
105
|
+
/** Sheet name used when the sheet has no valid name, built from its position (starting at 1). */
|
|
106
|
+
defaultSheetName: (position: number) => string;
|
|
107
|
+
};
|
|
108
|
+
/** Texts of the charts. */
|
|
109
|
+
export type ChartMessages = {
|
|
110
|
+
/** Name of each chart type, shown in a chart type selector. */
|
|
111
|
+
types: Record<ChartTypeId, string>;
|
|
112
|
+
/** Title of the button that saves the chart as an image. */
|
|
113
|
+
saveAsImage: string;
|
|
114
|
+
/** Subtitle of the donut chart with the formatted sum of the slices. */
|
|
115
|
+
total: (formattedTotal: string) => string;
|
|
116
|
+
};
|
|
117
|
+
/** Messages of the HTTP client errors. */
|
|
118
|
+
export type HttpMessages = {
|
|
119
|
+
/** The backend answered with an error, but without a message. */
|
|
120
|
+
unknownError: string;
|
|
121
|
+
/** The request was sent, but there was no answer (e.g. backend down or timeout). */
|
|
122
|
+
noResponse: string;
|
|
123
|
+
/** The request was not even sent and Axios gave no reason. */
|
|
124
|
+
requestFailed: string;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Every text the library shows to users, grouped by component. Each locale is an object of this type
|
|
128
|
+
* (`messages/ptBR.ts`, `messages/enUS.ts`), so a missing translation is a compile error.
|
|
129
|
+
*/
|
|
130
|
+
export type KitMessages = {
|
|
131
|
+
common: CommonMessages;
|
|
132
|
+
form: FormMessages;
|
|
133
|
+
table: TableMessages;
|
|
134
|
+
rowEdit: RowEditMessages;
|
|
135
|
+
select: SelectMessages;
|
|
136
|
+
layout: LayoutMessages;
|
|
137
|
+
print: PrintMessages;
|
|
138
|
+
stats: StatsMessages;
|
|
139
|
+
export: ExportMessages;
|
|
140
|
+
chart: ChartMessages;
|
|
141
|
+
http: HttpMessages;
|
|
142
|
+
};
|
|
143
|
+
/** Partial {@link KitMessages}, used by an app to override some texts of a locale. */
|
|
144
|
+
export type KitMessagesOverride = {
|
|
145
|
+
[Section in keyof KitMessages]?: Partial<KitMessages[Section]>;
|
|
146
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|