@centreon/ui 24.4.44 → 24.4.45-develop.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.
Files changed (95) hide show
  1. package/package.json +19 -14
  2. package/public/mockServiceWorker.js +1 -1
  3. package/src/Button/Icon/index.tsx +1 -1
  4. package/src/Button/Save/StartIcon.tsx +3 -3
  5. package/src/Button/Save/index.tsx +9 -5
  6. package/src/Checkbox/Checkbox.tsx +2 -2
  7. package/src/Checkbox/CheckboxGroup/index.tsx +2 -2
  8. package/src/Dashboard/Item.tsx +1 -1
  9. package/src/Dashboard/Layout.tsx +2 -2
  10. package/src/Dialog/index.tsx +1 -1
  11. package/src/FallbackPage/FallbackPage.tsx +3 -3
  12. package/src/FileDropZone/index.tsx +3 -1
  13. package/src/Form/Form.cypress.spec.tsx +133 -0
  14. package/src/Form/Inputs/CheckboxGroup.tsx +1 -4
  15. package/src/Form/Inputs/List/Content.tsx +62 -0
  16. package/src/Form/Inputs/List/List.styles.ts +29 -0
  17. package/src/Form/Inputs/List/List.tsx +58 -0
  18. package/src/Form/Inputs/List/useList.ts +81 -0
  19. package/src/Form/Inputs/index.tsx +3 -1
  20. package/src/Form/Inputs/models.ts +9 -1
  21. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx +2 -2
  22. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +5 -4
  23. package/src/Graph/LineChart/BasicComponents/Thresholds.tsx +2 -2
  24. package/src/Graph/LineChart/BasicComponents/useFilterLines.ts +1 -1
  25. package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +2 -2
  26. package/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +2 -3
  27. package/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx +1 -1
  28. package/src/Graph/LineChart/Legend/useLegend.ts +3 -3
  29. package/src/Graph/LineChart/helpers/doc.ts +16 -13
  30. package/src/Graph/LineChart/helpers/index.ts +1 -1
  31. package/src/Graph/LineChart/index.stories.tsx +4 -2
  32. package/src/Graph/SingleBar/Thresholds.tsx +2 -2
  33. package/src/Graph/Text/Text.stories.tsx +60 -4
  34. package/src/Graph/common/timeSeries/index.ts +3 -3
  35. package/src/InputField/Select/Autocomplete/Connected/index.tsx +10 -7
  36. package/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx +1 -1
  37. package/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx +1 -1
  38. package/src/InputField/Select/Autocomplete/Draggable/index.tsx +1 -1
  39. package/src/InputField/Select/Autocomplete/index.tsx +121 -115
  40. package/src/InputField/Select/IconPopover/index.tsx +2 -2
  41. package/src/InputField/Select/index.tsx +1 -1
  42. package/src/InputField/Text/index.tsx +2 -2
  43. package/src/Listing/Cell/DataCell.tsx +15 -1
  44. package/src/Listing/Header/ListingHeader.tsx +1 -1
  45. package/src/Listing/Listing.styles.ts +2 -3
  46. package/src/Listing/index.stories.tsx +12 -1
  47. package/src/Listing/index.tsx +1 -2
  48. package/src/Module/Module.cypress.spec.tsx +129 -0
  49. package/src/Module/index.tsx +2 -4
  50. package/src/RichTextEditor/RichTextEditor.tsx +12 -1
  51. package/src/SortableItems/index.tsx +2 -7
  52. package/src/ThemeProvider/index.tsx +24 -0
  53. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +6 -7
  54. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +8 -3
  55. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +0 -2
  56. package/src/TimePeriods/DateTimePickerInput.tsx +56 -19
  57. package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +12 -9
  58. package/src/TimePeriods/TimePeriods.cypress.spec.tsx +9 -33
  59. package/src/TimePeriods/helpers/index.ts +1 -1
  60. package/src/TimePeriods/index.stories.tsx +12 -4
  61. package/src/TimePeriods/index.tsx +2 -2
  62. package/src/api/QueryProvider.tsx +1 -1
  63. package/src/api/TestQueryProvider.tsx +1 -1
  64. package/src/api/useFetchQuery/index.ts +27 -23
  65. package/src/api/useMutationQuery/index.ts +45 -21
  66. package/src/components/Button/Icon/IconButton.tsx +6 -2
  67. package/src/components/DataTable/DataListing.tsx +6 -0
  68. package/src/components/DataTable/DataTable.cypress.spec.tsx +193 -0
  69. package/src/components/DataTable/DataTable.stories.tsx +40 -0
  70. package/src/components/DataTable/DataTable.styles.ts +3 -0
  71. package/src/components/DataTable/DataTable.tsx +3 -3
  72. package/src/components/DataTable/Item/DataTableItem.styles.ts +7 -2
  73. package/src/components/DataTable/Item/DataTableItem.tsx +4 -4
  74. package/src/components/DataTable/index.ts +3 -1
  75. package/src/components/Form/Dashboard/DashboardForm.tsx +15 -12
  76. package/src/components/Layout/PageLayout/PageLayout.tsx +1 -1
  77. package/src/components/Layout/PageLayout/PageLayoutActions.tsx +1 -0
  78. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +1 -0
  79. package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +5 -1
  80. package/src/components/Layout/PageLayout/PageQuickAccess.tsx +76 -0
  81. package/src/components/Layout/PageLayout/index.ts +3 -1
  82. package/src/components/Layout/PageLayout.cypress.spec.tsx +66 -0
  83. package/src/components/Modal/Modal.styles.ts +1 -1
  84. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.stories.tsx +3 -3
  85. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.tsx +1 -1
  86. package/src/components/Tooltip/ConfirmationTooltip/models.ts +1 -1
  87. package/src/index.ts +2 -2
  88. package/src/queryParameters/url/index.ts +5 -1
  89. package/src/utils/index.ts +2 -1
  90. package/src/utils/{useLicenseExpirationWarning.cypress.spec.tsx → useLicenseExpirationWarning.test.tsx} +48 -37
  91. package/src/utils/useLicenseExpirationWarning.ts +18 -18
  92. package/src/utils/usePluralizedTranslation.ts +21 -0
  93. package/src/screens/dashboard/DashboardsDetail.stories.tsx +0 -108
  94. package/src/screens/dashboard/DashboardsOverview.stories.tsx +0 -281
  95. package/src/utils/useDateTimePickerAdapter.ts +0 -309
@@ -1,108 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- import React, { ReactElement } from 'react';
3
-
4
- import { Meta } from '@storybook/react';
5
-
6
- import {
7
- Add as AddIcon,
8
- Settings as SettingsIcon,
9
- Share as ShareIcon
10
- } from '@mui/icons-material';
11
-
12
- import {
13
- Button,
14
- IconButton,
15
- Menu,
16
- PageHeader,
17
- PageLayout
18
- } from '../../components';
19
-
20
- const meta: Meta = {
21
- args: {
22
- actions: {}
23
- },
24
- parameters: {
25
- layout: 'fullscreen'
26
- },
27
- title: 'screens/Dashboards detail'
28
- };
29
-
30
- export default meta;
31
-
32
- const DefaultView = (args): ReactElement => {
33
- const { data } = args;
34
-
35
- return (
36
- <PageLayout>
37
- <PageLayout.Header>
38
- <PageHeader>
39
- <PageHeader.Main>
40
- <PageHeader.Menu>
41
- <Menu>
42
- <Menu.Button />
43
- <Menu.Items>
44
- <Menu.Item>Menu Item</Menu.Item>
45
- <Menu.Item>Menu Item</Menu.Item>
46
- <Menu.Item>Menu Item</Menu.Item>
47
- <Menu.Divider />
48
- <Menu.Item>
49
- <Button
50
- icon={<AddIcon />}
51
- iconVariant="start"
52
- variant="ghost"
53
- >
54
- Add item
55
- </Button>
56
- </Menu.Item>
57
- </Menu.Items>
58
- </Menu>
59
- </PageHeader.Menu>
60
- <PageHeader.Title
61
- description={data.dashboard.description}
62
- title={data.dashboard.name}
63
- />
64
- </PageHeader.Main>
65
- </PageHeader>
66
- </PageLayout.Header>
67
- <PageLayout.Body>
68
- <PageLayout.Actions>
69
- <IconButton
70
- aria-label="edit"
71
- data-testid="edit"
72
- icon={<SettingsIcon />}
73
- size="small"
74
- variant="ghost"
75
- />
76
- <IconButton
77
- aria-label="share"
78
- data-testid="share"
79
- icon={<ShareIcon />}
80
- size="small"
81
- variant="ghost"
82
- />
83
- </PageLayout.Actions>
84
- </PageLayout.Body>
85
- </PageLayout>
86
- );
87
- };
88
-
89
- export const Default = {
90
- args: {
91
- data: {
92
- dashboard: {
93
- description:
94
- 'Description et culpa sit commodo ea enim excepteur elit. Velit irure velit tempor culpa commodo eu adipisicing eu proident ullamco.',
95
- id: 1,
96
- name: 'Dashboard 1'
97
- }
98
- }
99
- },
100
- render: DefaultView
101
- };
102
-
103
- export const AsEditLayoutState = {
104
- args: {
105
- ...Default.args
106
- },
107
- render: DefaultView
108
- };
@@ -1,281 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- import { useEffect } from 'react';
3
-
4
- import { Meta } from '@storybook/react';
5
- import { atom, useAtom } from 'jotai';
6
-
7
- import { Add as AddIcon } from '@mui/icons-material';
8
-
9
- import {
10
- Button,
11
- DashboardForm,
12
- DashboardFormProps,
13
- DataTable,
14
- Modal,
15
- PageHeader,
16
- PageLayout
17
- } from '../../components';
18
- import { Default as DashboardFormDefaultStory } from '../../components/Form/Dashboard/DashboardForm.stories';
19
-
20
- const meta: Meta = {
21
- args: {
22
- actions: {
23
- create: {
24
- label: 'Create a dashboard'
25
- }
26
- },
27
- deleteConfirmation: {
28
- labels: {
29
- actions: {
30
- cancel: 'Cancel',
31
- confirm: 'Delete'
32
- },
33
- description: (name) => (
34
- <>
35
- Are you sure you want to delete <strong>{name}</strong> ?
36
- </>
37
- ),
38
- title: 'Delete dashboard'
39
- }
40
- },
41
- form: {
42
- labels: {
43
- ...DashboardFormDefaultStory.args!.labels,
44
- title: {
45
- create: 'Create dashboard',
46
- update: 'Update dashboard'
47
- }
48
- }
49
- },
50
- list: {
51
- emptyState: {
52
- labels: {
53
- actions: {
54
- create: 'Create dashboard'
55
- },
56
- title: 'No dashboards found'
57
- }
58
- }
59
- },
60
- title: 'Dashboards overview'
61
- },
62
- parameters: {
63
- layout: 'fullscreen'
64
- },
65
- title: 'screens/Dashboards overview'
66
- };
67
-
68
- export default meta;
69
-
70
- interface dashboardItem {
71
- description: string;
72
- id: number;
73
- name: string;
74
- }
75
-
76
- const dialogStateAtom = atom<{
77
- item: dashboardItem | null;
78
- open: boolean;
79
- variant: DashboardFormProps['variant'];
80
- }>({
81
- item: null,
82
- open: false,
83
- variant: 'create'
84
- });
85
-
86
- const deleteDialogStateAtom = atom<{
87
- item: dashboardItem | null;
88
- open: boolean;
89
- }>({
90
- item: null,
91
- open: false
92
- });
93
-
94
- const dataDashboardsAtom = atom<Array<dashboardItem>>([]);
95
-
96
- const DefaultView = (args): JSX.Element => {
97
- const { data, title, actions, list, form, deleteConfirmation } = args;
98
- const [dialogState, setDialogState] = useAtom(dialogStateAtom);
99
- const [deleteDialogState, setDeleteDialogState] = useAtom(
100
- deleteDialogStateAtom
101
- );
102
- const [dataDashboards, setDataDashboards] = useAtom(dataDashboardsAtom);
103
-
104
- useEffect(() => {
105
- setDataDashboards(data.dashboards);
106
- }, [data.dashboards]);
107
-
108
- const createDashboard = (d): void => {
109
- const dashboard = { ...d };
110
- dashboard.id = dataDashboards.length
111
- ? Math.max(...dataDashboards.map((db) => db.id)) + 1
112
- : 0;
113
- setDataDashboards((prev) =>
114
- [...prev, dashboard].sort((a, b) => a.name.localeCompare(b.name))
115
- );
116
- setDialogState({ item: null, open: false, variant: 'create' });
117
- };
118
-
119
- const updateDashboard = (d): void => {
120
- setDataDashboards((prev) =>
121
- prev
122
- .map((dashboard) => (dashboard.id === d.id ? d : dashboard))
123
- .sort((a, b) => a.name.localeCompare(b.name))
124
- );
125
- setDialogState({ item: null, open: false, variant: 'update' });
126
- };
127
-
128
- const deleteDashboard = (id): void => {
129
- setDataDashboards((prev) =>
130
- prev.filter((dashboard) => dashboard.id !== id)
131
- );
132
- };
133
-
134
- return (
135
- <PageLayout>
136
- <PageLayout.Header>
137
- <PageHeader>
138
- <PageHeader.Main>
139
- <PageHeader.Title title={title} />
140
- </PageHeader.Main>
141
- </PageHeader>
142
- </PageLayout.Header>
143
- <PageLayout.Body>
144
- <PageLayout.Actions>
145
- {dataDashboards.length !== 0 && (
146
- <Button
147
- aria-label="add"
148
- icon={<AddIcon />}
149
- iconVariant="start"
150
- onClick={() =>
151
- setDialogState({ item: null, open: true, variant: 'create' })
152
- }
153
- >
154
- {actions.create.label}
155
- </Button>
156
- )}
157
- </PageLayout.Actions>
158
-
159
- <DataTable isEmpty={dataDashboards.length === 0}>
160
- {dataDashboards.length === 0 ? (
161
- <DataTable.EmptyState
162
- labels={list.emptyState.labels}
163
- onCreate={() =>
164
- setDialogState({
165
- item: null,
166
- open: true,
167
- variant: 'create'
168
- })
169
- }
170
- />
171
- ) : (
172
- dataDashboards.map((dashboard) => (
173
- <DataTable.Item
174
- hasActions
175
- hasCardAction
176
- description={dashboard.description}
177
- key={dashboard.id}
178
- title={dashboard.name}
179
- onDelete={() =>
180
- setDeleteDialogState({ item: dashboard, open: true })
181
- }
182
- onEdit={() =>
183
- setDialogState({
184
- item: dashboard,
185
- open: true,
186
- variant: 'update'
187
- })
188
- }
189
- />
190
- ))
191
- )}
192
- </DataTable>
193
- </PageLayout.Body>
194
-
195
- <Modal
196
- open={dialogState.open}
197
- onClose={() =>
198
- setDialogState({
199
- item: null,
200
- open: false,
201
- variant: dialogState.variant
202
- })
203
- }
204
- >
205
- <Modal.Header>
206
- {form.labels.title[dialogState.variant ?? 'create']}
207
- </Modal.Header>
208
- <Modal.Body>
209
- <DashboardForm
210
- labels={DashboardFormDefaultStory!.args!.labels!}
211
- resource={dialogState.item || undefined}
212
- variant={dialogState.variant}
213
- onCancel={() =>
214
- setDialogState({
215
- item: null,
216
- open: false,
217
- variant: dialogState.variant
218
- })
219
- }
220
- onSubmit={(values) =>
221
- dialogState.variant === 'create'
222
- ? createDashboard(values)
223
- : updateDashboard(values)
224
- }
225
- />
226
- </Modal.Body>
227
- </Modal>
228
- <Modal
229
- open={deleteDialogState.open}
230
- onClose={() =>
231
- setDeleteDialogState({
232
- ...deleteDialogState,
233
- open: false
234
- })
235
- }
236
- >
237
- <Modal.Header>{deleteConfirmation.labels.title}</Modal.Header>
238
- <Modal.Body>
239
- <p>
240
- {deleteConfirmation.labels.description(
241
- deleteDialogState.item?.name
242
- )}
243
- </p>
244
- </Modal.Body>
245
- <Modal.Actions
246
- isDanger
247
- labels={deleteConfirmation.labels.actions}
248
- onCancel={() => setDeleteDialogState({ item: null, open: false })}
249
- onConfirm={() => {
250
- deleteDashboard(deleteDialogState.item?.id);
251
- setDeleteDialogState({ item: null, open: false });
252
- }}
253
- />
254
- </Modal>
255
- </PageLayout>
256
- );
257
- };
258
-
259
- export const Default = {
260
- args: {
261
- data: {
262
- dashboards: [
263
- { description: 'Dashboard 1 description', id: 1, name: 'Dashboard 1' },
264
- { description: 'Dashboard 2 description', id: 2, name: 'Dashboard 2' },
265
- { description: 'Dashboard 3 description', id: 3, name: 'Dashboard 3' },
266
- { description: 'Dashboard 4 description', id: 4, name: 'Dashboard 4' },
267
- { description: 'Dashboard 5 description', id: 5, name: 'Dashboard 5' }
268
- ]
269
- }
270
- },
271
- render: DefaultView
272
- };
273
-
274
- export const AsInitialState = {
275
- args: {
276
- data: {
277
- dashboards: []
278
- }
279
- },
280
- render: DefaultView
281
- };
@@ -1,309 +0,0 @@
1
- /* eslint-disable class-methods-use-this */
2
- import { useCallback } from 'react';
3
-
4
- import dayjs from 'dayjs';
5
- import { useAtomValue } from 'jotai';
6
- import { equals, isNil, not } from 'ramda';
7
-
8
- import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
9
-
10
- import { useLocaleDateTimeFormat } from '@centreon/ui';
11
- import { userAtom } from '@centreon/ui-context';
12
-
13
- interface GetDestinationAndConfiguredTimezoneOffsetProps {
14
- endTimezone?: string;
15
- startTimezone?: string;
16
- }
17
-
18
- interface UseDateTimePickerAdapterProps {
19
- Adapter;
20
- desktopPickerMediaQuery: string;
21
- }
22
-
23
- enum DSTState {
24
- SUMMER,
25
- WINTER,
26
- NODST
27
- }
28
-
29
- interface ToTimezonedDateProps {
30
- date: Date;
31
- timeZone?: string;
32
- }
33
-
34
- interface GetDSTStateProps {
35
- date: dayjs.Dayjs;
36
- timezoneToUse?: string;
37
- }
38
-
39
- export const useDateTimePickerAdapter = (): UseDateTimePickerAdapterProps => {
40
- const { timezone, locale } = useAtomValue(userAtom);
41
- const { format } = useLocaleDateTimeFormat();
42
-
43
- const desktopPickerMediaQuery =
44
- '@media (pointer: fine) or (min-width: 1024px)';
45
-
46
- const toTimezonedDate = ({
47
- date,
48
- timeZone = undefined
49
- }: ToTimezonedDateProps): Date => {
50
- if (isNil(timeZone)) {
51
- return new Date(date.toLocaleString('en-US'));
52
- }
53
-
54
- return new Date(date.toLocaleString('en-US', { timeZone }));
55
- };
56
-
57
- const getDestinationAndConfiguredTimezoneOffset = ({
58
- startTimezone = undefined,
59
- endTimezone = timezone
60
- }: GetDestinationAndConfiguredTimezoneOffsetProps): number => {
61
- const now = new Date();
62
- const currentTimezoneDate = toTimezonedDate({
63
- date: now,
64
- timeZone: startTimezone
65
- });
66
- const destinationTimezoneDate = toTimezonedDate({
67
- date: now,
68
- timeZone: endTimezone
69
- });
70
-
71
- return Math.floor(
72
- (currentTimezoneDate.getTime() - destinationTimezoneDate.getTime()) /
73
- 60 /
74
- 60 /
75
- 1000
76
- );
77
- };
78
-
79
- const getDSTState = useCallback(
80
- ({ date, timezoneToUse }: GetDSTStateProps): DSTState => {
81
- const hasNoTimezone = isNil(timezoneToUse);
82
- const currentYear = toTimezonedDate({
83
- date: new Date(),
84
- timeZone: timezoneToUse
85
- }).getFullYear();
86
-
87
- const january = hasNoTimezone
88
- ? dayjs(new Date(currentYear, 0, 1)).utcOffset()
89
- : dayjs(new Date(currentYear, 0, 1)).tz(timezoneToUse).utcOffset();
90
- const july = hasNoTimezone
91
- ? dayjs(new Date(currentYear, 6, 1)).utcOffset()
92
- : dayjs(new Date(currentYear, 6, 1)).tz(timezoneToUse).utcOffset();
93
-
94
- if (equals(january, july)) {
95
- return DSTState.NODST;
96
- }
97
-
98
- return july === date.tz().utcOffset() ? DSTState.SUMMER : DSTState.WINTER;
99
- },
100
- [timezone]
101
- );
102
-
103
- const getDSTStateForCurrentTimezone = useCallback(
104
- (date: dayjs.Dayjs): DSTState => {
105
- return getDSTState({ date });
106
- },
107
- []
108
- );
109
-
110
- interface Chunk {
111
- array: Array<unknown>;
112
- size: number;
113
- }
114
- class Adapter extends AdapterDayjs {
115
- public formatByString = (value, formatKey: string): string => {
116
- return format({
117
- date: value.tz(timezone).toDate(),
118
- formatString: formatKey
119
- });
120
- };
121
-
122
- public format = (date: dayjs.Dayjs, formatKey: string): string => {
123
- return this.formatByString(
124
- date.tz(timezone, true),
125
- this.formats[formatKey]
126
- );
127
- };
128
-
129
- public startOfWeek = (date: dayjs.Dayjs): dayjs.Dayjs => {
130
- if (date.tz(timezone).isUTC()) {
131
- return date.tz(timezone).startOf('week').utc();
132
- }
133
-
134
- return date.tz(timezone).startOf('week');
135
- };
136
-
137
- public setMinutes = (date: dayjs.Dayjs, count: number): dayjs.Dayjs => {
138
- return date.minute(count);
139
- };
140
-
141
- public setHours = (date: dayjs.Dayjs, count: number): dayjs.Dayjs => {
142
- return date.hour(count);
143
- };
144
-
145
- public isSameDay = (date: dayjs.Dayjs, comparing: dayjs.Dayjs): boolean => {
146
- const isSameYearAndMonth = this.isSameYear(date, comparing)
147
- ? this.isSameMonth(date, comparing)
148
- : false;
149
-
150
- return (
151
- isSameYearAndMonth &&
152
- date.tz(timezone).isSame(comparing.tz(timezone), 'day')
153
- );
154
- };
155
-
156
- public startOfDay = (date: dayjs.Dayjs): dayjs.Dayjs => {
157
- return date.tz(timezone).startOf('day') as dayjs.Dayjs;
158
- };
159
-
160
- public endOfDay = (date: dayjs.Dayjs): dayjs.Dayjs => {
161
- return date.tz(timezone).endOf('day') as dayjs.Dayjs;
162
- };
163
-
164
- public startOfMonth = (date: dayjs.Dayjs): dayjs.Dayjs => {
165
- if (date.tz(timezone).isUTC()) {
166
- return date.tz(timezone).utc();
167
- }
168
-
169
- return date.tz(timezone);
170
- };
171
-
172
- public endOfMonth = (date: dayjs.Dayjs): dayjs.Dayjs => {
173
- return date.tz(timezone).endOf('month') as dayjs.Dayjs;
174
- };
175
-
176
- public isSameMonth = (
177
- date: dayjs.Dayjs,
178
- comparing: dayjs.Dayjs
179
- ): boolean => {
180
- return date.tz(timezone).isSame(comparing.tz(timezone), 'month');
181
- };
182
-
183
- public getMonth = (date: dayjs.Dayjs): number => {
184
- return date.tz(timezone).month();
185
- };
186
-
187
- public isAfter = (date: dayjs.Dayjs, value: dayjs.Dayjs): boolean => {
188
- return date.isAfter(value.endOf('month'));
189
- };
190
-
191
- public isBefore = (date: dayjs.Dayjs, value: dayjs.Dayjs): boolean => {
192
- return date.isBefore(value.startOf('month'));
193
- };
194
-
195
- public getDaysInMonth = (date: dayjs.Dayjs): number => {
196
- return date.tz(timezone).daysInMonth();
197
- };
198
-
199
- public getWeekdays = (): Array<string> => {
200
- const start = dayjs().locale(locale).tz(timezone).startOf('week');
201
-
202
- return [0, 1, 2, 3, 4, 5, 6].map((diff) =>
203
- this.formatByString(start.add(diff, 'day'), 'dd')
204
- );
205
- };
206
-
207
- public getChunkFromArray = ({ array, size }: Chunk): Array<unknown> => {
208
- if (!array.length) {
209
- return [];
210
- }
211
- const head = array.slice(0, size);
212
- const tail = array.slice(size);
213
-
214
- return [head, ...this.getChunkFromArray({ array: tail, size })];
215
- };
216
-
217
- public getWeekArray = (date: dayjs.Dayjs): Array<Array<dayjs.Dayjs>> => {
218
- const isMorning = equals(dayjs().tz(timezone).format('a'), 'am');
219
- const startOfWeek = date.tz(timezone).startOf('month').startOf('week');
220
- const endOfWeek = date.tz(timezone).endOf('month').endOf('week');
221
- const start = startOfWeek.startOf('day');
222
- const end = endOfWeek.endOf('day');
223
- const customStart = isMorning
224
- ? startOfWeek.startOf('day')
225
- : startOfWeek.startOf('day');
226
- const customEnd = isMorning
227
- ? endOfWeek.startOf('day')
228
- : endOfWeek.startOf('day');
229
- const currentStart = start.isUTC()
230
- ? start.tz(timezone, true)
231
- : customStart;
232
- const currentEnd = end.isUTC() ? end.tz(timezone, true) : customEnd;
233
- const numberOfDaysInCurrentMonth = currentEnd.diff(
234
- currentStart,
235
- 'd',
236
- true
237
- );
238
- const daysOfMonthWithTimezone = [
239
- ...Array(Math.round(numberOfDaysInCurrentMonth)).keys()
240
- ].reduce(
241
- (acc, _, currentIndex) => {
242
- if (acc[currentIndex].isUTC()) {
243
- const newCurrent = acc[currentIndex]
244
- .utc()
245
- .add(1, 'day')
246
- .tz(timezone, true);
247
-
248
- return [...acc, newCurrent];
249
- }
250
- const newCurrent = acc[currentIndex].add(1, 'day');
251
-
252
- return [...acc, newCurrent];
253
- },
254
- [currentStart]
255
- );
256
- const weeksArray = this.getChunkFromArray({
257
- array: daysOfMonthWithTimezone,
258
- size: 7
259
- });
260
-
261
- return weeksArray as Array<Array<dayjs.Dayjs>>;
262
- };
263
-
264
- public mergeDateAndTime = (
265
- date: dayjs.Dayjs,
266
- time: dayjs.Dayjs
267
- ): dayjs.Dayjs => {
268
- const dateWithTimezone = date.tz(timezone).startOf('day');
269
- const timeWithTimezone = time.tz(timezone);
270
- const dateDSTState = getDSTState({
271
- date: dateWithTimezone,
272
- timezoneToUse: timezone
273
- });
274
- const dateDSTStateWithCurrentTimezone =
275
- getDSTStateForCurrentTimezone(date);
276
-
277
- if (equals(dateDSTStateWithCurrentTimezone, DSTState.WINTER)) {
278
- return dateWithTimezone
279
- .add(
280
- timeWithTimezone.hour() -
281
- getDestinationAndConfiguredTimezoneOffset({
282
- endTimezone: 'UTC',
283
- startTimezone: dayjs.tz.guess()
284
- }),
285
- 'hour'
286
- )
287
- .add(timeWithTimezone.minute(), 'minute')
288
- .add(timeWithTimezone.second(), 'second');
289
- }
290
-
291
- if (not(equals(dateDSTState, DSTState.SUMMER))) {
292
- return dateWithTimezone
293
- .add(timeWithTimezone.hour(), 'hour')
294
- .add(timeWithTimezone.minute(), 'minute')
295
- .add(timeWithTimezone.second(), 'second');
296
- }
297
-
298
- return dateWithTimezone
299
- .hour(timeWithTimezone.hour())
300
- .minute(timeWithTimezone.minute())
301
- .second(timeWithTimezone.second());
302
- };
303
- }
304
-
305
- return {
306
- Adapter,
307
- desktopPickerMediaQuery
308
- };
309
- };