@boarteam/boar-pack-common-frontend 2.4.1 → 2.5.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.
@@ -0,0 +1,128 @@
1
+ import { message, Popover, Space } from "antd";
2
+ import { QuestionCircleTwoTone } from "@ant-design/icons";
3
+ import _ from "lodash";
4
+ import BulkEditButton from "./BulkEditButton";
5
+ import { ActionType, ProTableProps } from "@ant-design/pro-table";
6
+ import BulkDeleteButton from "./BulkDeleteButton";
7
+ import { MutableRefObject, useState } from "react";
8
+ import { TGetAllParams } from "./tableTypes";
9
+
10
+ export function useBulkEditing<Entity, TPathParams, UpdateDto, U>({
11
+ actionRef,
12
+ columns,
13
+ idColumnName,
14
+ onDeleteMany,
15
+ onUpdateMany,
16
+ entityToUpdateDto,
17
+ pathParams,
18
+ }: {
19
+ actionRef?: MutableRefObject<ActionType | undefined>;
20
+ columns: ProTableProps<Entity, U>['columns'],
21
+ idColumnName?: string & keyof Entity | (string & keyof Entity)[];
22
+ onDeleteMany: ({}: Partial<Entity> & {
23
+ requestBody: { records: Entity[] }
24
+ } & TPathParams) => Promise<void>,
25
+ onUpdateMany: ({}: Partial<Entity> & {
26
+ requestBody: { updateValues: Partial<UpdateDto>[], records: Entity[] }
27
+ } & TPathParams) => Promise<void>,
28
+ entityToUpdateDto: (entity: Entity) => UpdateDto;
29
+ pathParams: TPathParams,
30
+ }) {
31
+ const [allSelected, setAllSelected] = useState(false);
32
+ const [selectedRecords, setSelectedRecords] = useState<Entity[]>([]);
33
+ const [lastRequest, setLastRequest] = useState<[TGetAllParams & TPathParams, any] | []>([]);
34
+ const [messageApi, contextHolder] = message.useMessage();
35
+
36
+ const bulkEditButton = <BulkEditButton<Entity, TPathParams>
37
+ selectedRecords={selectedRecords}
38
+ lastRequest={lastRequest}
39
+ allSelected={allSelected}
40
+ columns={columns}
41
+ idColumnName={idColumnName}
42
+ // @ts-ignore
43
+ onSubmit={values => onUpdateMany({
44
+ ...pathParams,
45
+ ...lastRequest[0],
46
+ requestBody: {
47
+ updateValues: _.pickBy(
48
+ // @ts-ignore
49
+ entityToUpdateDto({
50
+ ...pathParams,
51
+ ...values,
52
+ }),
53
+ (value, key) => _.has(values, key),
54
+ ),
55
+ records: allSelected ? [] : selectedRecords,
56
+ },
57
+ }).then(() => {
58
+ messageApi.open({
59
+ type: 'success',
60
+ content: 'Operation Successful',
61
+ });
62
+ actionRef?.current?.reload();
63
+ })}
64
+ />;
65
+
66
+ const bulkDeleteButton = <BulkDeleteButton<Entity, TPathParams>
67
+ selectedRecords={selectedRecords}
68
+ lastRequest={lastRequest}
69
+ allSelected={allSelected}
70
+ // @ts-ignore
71
+ onDelete={() => onDeleteMany({
72
+ ...pathParams,
73
+ ...lastRequest[0],
74
+ requestBody: {
75
+ records: allSelected ? [] : selectedRecords,
76
+ },
77
+ }).then(() => {
78
+ messageApi.open({
79
+ type: 'success',
80
+ content: 'Operation Successful',
81
+ });
82
+ actionRef?.current?.reload();
83
+ })}
84
+ />;
85
+
86
+ const rowSelection: ProTableProps<Entity, U>['rowSelection'] = {
87
+ selectedRowKeys: selectedRecords.map(record => Array.isArray(idColumnName) ? idColumnName.map(colName => record[colName]).join('-') : record[idColumnName]),
88
+ selections: [
89
+ {
90
+ key: 'all',
91
+ text: (
92
+ <Space>
93
+ Select ALL
94
+ <Popover
95
+ content={(
96
+ <div style={{ width: '100%' }}>
97
+ This includes records from ALL pages of the table.
98
+ </div>
99
+ )}
100
+ title={'Select All'}
101
+ trigger={['hover', 'click']}
102
+ zIndex={1080}
103
+ >
104
+ <QuestionCircleTwoTone />
105
+ </Popover>
106
+ </Space>
107
+ ),
108
+ onSelect: () => {
109
+ setSelectedRecords(lastRequest[1].data);
110
+ setAllSelected(true);
111
+ },
112
+ },
113
+ ],
114
+ onChange: (rowKeys, records) => {
115
+ setSelectedRecords(records);
116
+ allSelected && setAllSelected(false);
117
+ },
118
+ };
119
+
120
+ return {
121
+ rowSelection,
122
+ setSelectedRecords,
123
+ setLastRequest,
124
+ messagesContext: contextHolder,
125
+ bulkEditButton,
126
+ bulkDeleteButton,
127
+ }
128
+ }
@@ -0,0 +1,96 @@
1
+ import { MutableRefObject, useState } from 'react';
2
+ import { Button } from 'antd';
3
+ import { ActionType } from "@ant-design/pro-table";
4
+ import { PlusOutlined } from "@ant-design/icons";
5
+ import { FormattedMessage } from "react-intl";
6
+ import type { SizeType } from "antd/es/config-provider/SizeContext";
7
+ import { CreateEntityModal, CreateEntityModalProps } from "./CreateEntityModal";
8
+
9
+ let creatingRecordsCount = 0;
10
+ export const KEY_SYMBOL = Symbol('key');
11
+ const NEW_RECORD = 'NEW_RECORD';
12
+
13
+ export function getNewId(): string {
14
+ return NEW_RECORD + creatingRecordsCount++;
15
+ }
16
+
17
+ export function isRecordNew(record: Record<string | symbol, any>): boolean {
18
+ return record[KEY_SYMBOL]?.startsWith?.(NEW_RECORD) || record.id?.startsWith?.(NEW_RECORD) || false;
19
+ }
20
+
21
+ export function useCreation<Entity, CreateDto, TPathParams = {}>({
22
+ title,
23
+ mainTitle,
24
+ columns,
25
+ idColumnName,
26
+ onCreate,
27
+ pathParams,
28
+ entityToCreateDto,
29
+ actionRef,
30
+ createButtonSize,
31
+ popupCreation,
32
+ createNewDefaultParams,
33
+ }: {
34
+ actionRef?: MutableRefObject<ActionType | undefined>;
35
+ pathParams: TPathParams;
36
+ entityToCreateDto: (entity: Partial<Entity>) => CreateDto;
37
+ onCreate?: ({}: { requestBody: CreateDto } & TPathParams) => Promise<Entity>;
38
+ createButtonSize: SizeType;
39
+ popupCreation?: boolean;
40
+ createNewDefaultParams?: Partial<Entity>;
41
+ } & Omit<CreateEntityModalProps<Entity>, 'onSubmit' | 'onCancel' | 'entity'>) {
42
+ const [createPopupData, setCreatePopupData] = useState<Partial<Entity> | undefined>();
43
+
44
+ const onCreateSubmit = async (data: Partial<Entity>) => {
45
+ try {
46
+ await onCreate?.({
47
+ ...pathParams,
48
+ requestBody: entityToCreateDto({
49
+ ...pathParams,
50
+ ...data,
51
+ })
52
+ });
53
+ setCreatePopupData(undefined);
54
+ await actionRef?.current?.reload();
55
+ } catch (e) {
56
+ console.error(e);
57
+ }
58
+ };
59
+
60
+ const createButton = <Button
61
+ size={createButtonSize}
62
+ type="primary"
63
+ key="create"
64
+ onClick={() => {
65
+ if (popupCreation) {
66
+ setCreatePopupData(createNewDefaultParams);
67
+ } else {
68
+ actionRef?.current?.addEditRecord({
69
+ [KEY_SYMBOL]: getNewId(),
70
+ ...createNewDefaultParams,
71
+ }, {
72
+ position: 'top',
73
+ });
74
+ }
75
+ }}
76
+ >
77
+ <PlusOutlined /> <FormattedMessage id={'table.newButton'} />
78
+ </Button>;
79
+
80
+ const modal = <CreateEntityModal<Entity, CreateDto, Entity, TPathParams>
81
+ entity={createPopupData}
82
+ title={title}
83
+ mainTitle={mainTitle}
84
+ columns={columns}
85
+ idColumnName={idColumnName}
86
+ onCancel={() => {
87
+ setCreatePopupData(undefined);
88
+ }}
89
+ onSubmit={onCreateSubmit}
90
+ />;
91
+
92
+ return {
93
+ creationModal: modal,
94
+ createButton,
95
+ };
96
+ }
@@ -0,0 +1,84 @@
1
+ import { EditableProps } from "./tableTypes";
2
+ import type { RowEditableConfig } from "@ant-design/pro-utils";
3
+ import { flushSync } from "react-dom";
4
+ import { Button, Tooltip } from "antd";
5
+ import { DeleteOutlined, StopOutlined } from "@ant-design/icons";
6
+ import { FormattedMessage, useIntl } from "react-intl";
7
+ import React, { useState } from "react";
8
+
9
+ export function useEditableTable<Entity, CreateDto, UpdateDto, TPathParams = {}>(
10
+ {
11
+ actionRef,
12
+ pathParams,
13
+ onCreate,
14
+ onUpdate,
15
+ onDelete,
16
+ entityToCreateDto,
17
+ entityToUpdateDto,
18
+ afterSave,
19
+ editable,
20
+ }: {
21
+ pathParams: TPathParams,
22
+ } & EditableProps<Entity, CreateDto, UpdateDto, TPathParams>
23
+ ) {
24
+ const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
25
+ const intl = useIntl();
26
+
27
+ const editableConfig: RowEditableConfig<Entity> = {
28
+ type: 'multiple',
29
+ editableKeys,
30
+ onChange: setEditableRowKeys,
31
+ async onSave(
32
+ id,
33
+ record,
34
+ origin,
35
+ newLine,
36
+ ) {
37
+ if (newLine) {
38
+ await onCreate?.({
39
+ ...pathParams,
40
+ requestBody: entityToCreateDto(record),
41
+ });
42
+ } else {
43
+ await onUpdate({
44
+ ...pathParams,
45
+ ...record,
46
+ requestBody: entityToUpdateDto({
47
+ ...pathParams,
48
+ ...record,
49
+ }),
50
+ })
51
+ }
52
+
53
+ if (typeof afterSave === 'function') {
54
+ await afterSave(record);
55
+ }
56
+
57
+ flushSync(() => {
58
+ actionRef?.current?.reload();
59
+ });
60
+ },
61
+ async onCancel(
62
+ id,
63
+ record,
64
+ origin,
65
+ ) {
66
+ if (record) {
67
+ Object.assign(record, origin);
68
+ }
69
+ },
70
+ async onDelete(id, row) {
71
+ await onDelete({ ...row, ...pathParams });
72
+ },
73
+ deletePopconfirmMessage: intl.formatMessage({ id: 'table.deletePopconfirmMessage' }),
74
+ onlyAddOneLineAlertMessage: intl.formatMessage({ id: 'table.onlyAddOneLineAlertMessage' }),
75
+ cancelText: <Tooltip title={intl.formatMessage({ id: 'table.cancelText' })}><StopOutlined /></Tooltip>,
76
+ deleteText: <Tooltip title={intl.formatMessage({ id: 'table.deleteText' })}><DeleteOutlined /></Tooltip>,
77
+ saveText: <Button size={"small"} type={"primary"}><FormattedMessage id={'table.saveText'} /></Button>,
78
+ ...editable,
79
+ }
80
+
81
+ return {
82
+ editableConfig,
83
+ };
84
+ }
@@ -1,27 +0,0 @@
1
- import { Button, Tooltip } from "antd";
2
- import { AppstoreOutlined, UnorderedListOutlined } from "@ant-design/icons";
3
- export enum VIEW_MODE_TYPE {
4
- TABS = 'tabs',
5
- GENERAL = 'general'
6
- }
7
-
8
- interface ContentViewModeButtonProps {
9
- contentViewMode: VIEW_MODE_TYPE;
10
- setContentViewMode: (mode: VIEW_MODE_TYPE) => void;
11
- }
12
-
13
- const ContentViewModeButton: React.FC<ContentViewModeButtonProps> = ({ contentViewMode, setContentViewMode }) => {
14
- return (
15
- <Tooltip
16
- title={contentViewMode === VIEW_MODE_TYPE.TABS ? 'Switch to general view' : 'Switch to tabs view'}
17
- key="viewModeToggle">
18
- <Button
19
- type="text"
20
- icon={contentViewMode === VIEW_MODE_TYPE.TABS ? <UnorderedListOutlined/> :
21
- <AppstoreOutlined/>}
22
- onClick={() => setContentViewMode(contentViewMode === VIEW_MODE_TYPE.TABS ? VIEW_MODE_TYPE.GENERAL : VIEW_MODE_TYPE.TABS)}
23
- />
24
- </Tooltip>);
25
- };
26
-
27
- export default ContentViewModeButton;