ish-ui 1.0.2

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 (126) hide show
  1. package/.eslintrc.json +39 -0
  2. package/.gitattributes +3 -0
  3. package/.github/workflows/release-package.yml +33 -0
  4. package/.prettierrc +5 -0
  5. package/README.md +80 -0
  6. package/assets/fonts/inter/Inter-Italic.var.woff2 +0 -0
  7. package/assets/fonts/inter/Inter-Roman.var.woff2 +0 -0
  8. package/assets/fonts/inter/LICENSE.txt +92 -0
  9. package/assets/fonts/inter/index.d.ts +10 -0
  10. package/assets/fonts/inter/inter.scss +17 -0
  11. package/package.json +108 -0
  12. package/src/actions/FieldProcessing.ts +21 -0
  13. package/src/actions/index.ts +10 -0
  14. package/src/appBar/AppBarHelpMenu.tsx +139 -0
  15. package/src/appBar/index.ts +9 -0
  16. package/src/buttons/AddButton.tsx +30 -0
  17. package/src/buttons/TimetableButton.tsx +19 -0
  18. package/src/buttons/index.ts +10 -0
  19. package/src/colorPicker/ColorPicker.tsx +223 -0
  20. package/src/colorPicker/index.ts +9 -0
  21. package/src/dialog/BrowserWarning.tsx +24 -0
  22. package/src/dialog/confirm/ConfirmBase.tsx +59 -0
  23. package/src/dialog/index.ts +11 -0
  24. package/src/dialog/message/Message.tsx +140 -0
  25. package/src/documents/DocumentIconsChooser.tsx +69 -0
  26. package/src/documents/index.ts +10 -0
  27. package/src/documents/utils/index.tsx +71 -0
  28. package/src/dynamicSizeList/DynamicSizeList.tsx +208 -0
  29. package/src/dynamicSizeList/index.ts +9 -0
  30. package/src/fieldMessage/ErrorMessage.tsx +28 -0
  31. package/src/fieldMessage/WarningMessage.tsx +28 -0
  32. package/src/fieldMessage/index.ts +11 -0
  33. package/src/fieldMessage/styles.ts +21 -0
  34. package/src/fileUploader/FileUploaderDialog.tsx +158 -0
  35. package/src/fileUploader/index.ts +9 -0
  36. package/src/formFields/CheckboxField.tsx +90 -0
  37. package/src/formFields/CodeEditorField.tsx +103 -0
  38. package/src/formFields/ColoredCheckBox.tsx +74 -0
  39. package/src/formFields/DateTimeField.tsx +61 -0
  40. package/src/formFields/EditInPlaceDateTimeField.tsx +285 -0
  41. package/src/formFields/EditInPlaceDurationField.tsx +79 -0
  42. package/src/formFields/EditInPlaceField.tsx +131 -0
  43. package/src/formFields/EditInPlaceFieldBase.tsx +241 -0
  44. package/src/formFields/EditInPlaceFileField.tsx +67 -0
  45. package/src/formFields/EditInPlaceMoneyField.tsx +64 -0
  46. package/src/formFields/EditInPlacePhoneField.tsx +97 -0
  47. package/src/formFields/EditInPlaceSearchSelect.tsx +562 -0
  48. package/src/formFields/FieldAdornments.tsx +70 -0
  49. package/src/formFields/FilePreview.tsx +149 -0
  50. package/src/formFields/FormRadioButtons.tsx +62 -0
  51. package/src/formFields/SelectCustomComponents.tsx +228 -0
  52. package/src/formFields/Switch.tsx +146 -0
  53. package/src/formFields/TextField.tsx +60 -0
  54. package/src/formFields/UneditableBase.tsx +101 -0
  55. package/src/formFields/index.ts +27 -0
  56. package/src/index.ts +26 -0
  57. package/src/layout/InfoPill.tsx +36 -0
  58. package/src/layout/index.ts +10 -0
  59. package/src/layout/resizable/ResizableWrapper.tsx +87 -0
  60. package/src/markdownEditor/HtmlEditor.tsx +44 -0
  61. package/src/markdownEditor/WysiwygEditor.tsx +137 -0
  62. package/src/markdownEditor/index.ts +12 -0
  63. package/src/markdownEditor/style.ts +188 -0
  64. package/src/markdownEditor/utils/index.ts +48 -0
  65. package/src/model/AppBar.ts +20 -0
  66. package/src/model/CommomObjects.ts +8 -0
  67. package/src/model/CommonFunctions.ts +20 -0
  68. package/src/model/Confirm.ts +27 -0
  69. package/src/model/Fields.ts +254 -0
  70. package/src/model/NestedEntity.ts +14 -0
  71. package/src/model/Theme.ts +42 -0
  72. package/src/model/index.ts +16 -0
  73. package/src/styles/GlobalStylesProvider.tsx +520 -0
  74. package/src/styles/StylesProviderCustom.tsx +8 -0
  75. package/src/styles/animateStyles.ts +94 -0
  76. package/src/styles/bootstrap.ts +503 -0
  77. package/src/styles/hooks.ts +44 -0
  78. package/src/styles/index.ts +18 -0
  79. package/src/styles/makeStyles.ts +21 -0
  80. package/src/styles/mixins/common.ts +40 -0
  81. package/src/styles/mixins/keyframes.ts +16 -0
  82. package/src/styles/mixins/prefixer.ts +21 -0
  83. package/src/tagsInput/AddTagMenu.tsx +74 -0
  84. package/src/tagsInput/AddTagMenuItem.tsx +50 -0
  85. package/src/tagsInput/TagInputList.tsx +428 -0
  86. package/src/tagsInput/index.ts +4 -0
  87. package/src/themes/appTheme.ts +324 -0
  88. package/src/themes/index.ts +10 -0
  89. package/src/themes/ishTheme.ts +401 -0
  90. package/src/timetable/datePeriodFilter/DayPeriodIcons.tsx +95 -0
  91. package/src/timetable/datePeriodFilter/index.ts +10 -0
  92. package/src/timetable/index.ts +11 -0
  93. package/src/timetable/miniCalendar/CalendarDay.tsx +109 -0
  94. package/src/timetable/miniCalendar/CalendarHeader.tsx +37 -0
  95. package/src/timetable/miniCalendar/CalendarWeekPanel.tsx +35 -0
  96. package/src/timetable/miniCalendar/WeekDay.tsx +49 -0
  97. package/src/timetable/miniCalendar/index.ts +13 -0
  98. package/src/utils/DOM/Links.ts +17 -0
  99. package/src/utils/DOM/getCaretCoordinates.ts +122 -0
  100. package/src/utils/DOM/getOS.ts +32 -0
  101. package/src/utils/DOM/index.ts +34 -0
  102. package/src/utils/dates/datesNormalizing.ts +4 -0
  103. package/src/utils/dates/format.ts +52 -0
  104. package/src/utils/dates/formatRelative.ts +22 -0
  105. package/src/utils/dates/formatString.ts +233 -0
  106. package/src/utils/dates/formatTimezone.ts +37 -0
  107. package/src/utils/dates/index.ts +15 -0
  108. package/src/utils/dates/timetable.ts +46 -0
  109. package/src/utils/events/index.ts +8 -0
  110. package/src/utils/fields/index.ts +23 -0
  111. package/src/utils/formatting/PhoneMasks.ts +320 -0
  112. package/src/utils/formatting/index.tsx +20 -0
  113. package/src/utils/hooks/index.ts +19 -0
  114. package/src/utils/index.ts +15 -0
  115. package/src/utils/numbers/decimalCalculation.ts +26 -0
  116. package/src/utils/numbers/index.ts +11 -0
  117. package/src/utils/numbers/numbersNormalizing.ts +52 -0
  118. package/src/utils/stubs/index.tsx +12 -0
  119. package/src/utils/tags/index.ts +53 -0
  120. package/tools/webpack/webpack.aliases.js +13 -0
  121. package/tools/webpack/webpack.config.dev.js +29 -0
  122. package/tools/webpack/webpack.config.prod.js +36 -0
  123. package/tools/webpack/webpack.helpers.js +26 -0
  124. package/tools/webpack/webpack.plugins.js +15 -0
  125. package/tools/webpack/webpack.rules.js +51 -0
  126. package/tsconfig.json +24 -0
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ import { Button, Typography } from "@mui/material";
3
+ import { createStyles, withStyles } from "@mui/styles";
4
+ import clsx from "clsx";
5
+
6
+ interface Props {
7
+ name: string;
8
+ selected: boolean;
9
+ click: (id) => void;
10
+ id: number;
11
+ classes?: any;
12
+ }
13
+
14
+ const styles = theme =>
15
+ createStyles({
16
+ weekButton: {
17
+ padding: theme.spacing(0.5),
18
+ minWidth: "initial",
19
+ textTransform: "capitalize"
20
+ },
21
+ selectedWeekDay: {
22
+ boxShadow: "none",
23
+ "&:active": {
24
+ boxShadow: "none"
25
+ }
26
+ },
27
+ weekDayText: {
28
+ color: theme.palette.common.white
29
+ }
30
+ });
31
+
32
+ const WeekDay = ({
33
+ classes, name, selected, click, id
34
+ }: Props) => (
35
+ <Button
36
+ className={clsx(classes.weekButton, {
37
+ [classes.selectedWeekDay]: selected
38
+ })}
39
+ onClick={() => click(id)}
40
+ variant={selected ? "contained" : "text"}
41
+ color={selected ? "primary" : "inherit"}
42
+ >
43
+ <Typography variant="caption" align="center" className={selected ? classes.weekDayText : ""}>
44
+ {name}
45
+ </Typography>
46
+ </Button>
47
+ );
48
+
49
+ export default withStyles(styles)(WeekDay);
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+
10
+ export * from './CalendarHeader';
11
+ export * from './CalendarDay';
12
+ export * from './CalendarWeekPanel';
13
+ export * from './WeekDay';
@@ -0,0 +1,17 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+
10
+ export const openInternalLink = link => {
11
+ if (link) {
12
+ window.open(
13
+ (link.includes('http') ? '' : window.location.origin) + link,
14
+ '_blank'
15
+ );
16
+ }
17
+ };
@@ -0,0 +1,122 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+ const properties = [
10
+ 'direction',
11
+ 'boxSizing',
12
+ 'width',
13
+ 'height',
14
+ 'overflowX',
15
+ 'overflowY',
16
+
17
+ 'borderTopWidth',
18
+ 'borderRightWidth',
19
+ 'borderBottomWidth',
20
+ 'borderLeftWidth',
21
+ 'borderStyle',
22
+
23
+ 'paddingTop',
24
+ 'paddingRight',
25
+ 'paddingBottom',
26
+ 'paddingLeft',
27
+
28
+ 'fontStyle',
29
+ 'fontVariant',
30
+ 'fontWeight',
31
+ 'fontStretch',
32
+ 'fontSize',
33
+ 'fontSizeAdjust',
34
+ 'lineHeight',
35
+ 'fontFamily',
36
+
37
+ 'textAlign',
38
+ 'textTransform',
39
+ 'textIndent',
40
+ 'textDecoration',
41
+
42
+ 'letterSpacing',
43
+ 'wordSpacing',
44
+
45
+ 'tabSize',
46
+ 'MozTabSize'
47
+ ];
48
+
49
+ const getCaretCoordinates = (element, position, options?) => {
50
+ if (!element) return null;
51
+ const debug = (options && options.debug) || false;
52
+ if (debug) {
53
+ const el = document.querySelector('#input-textarea-caret-position-mirror-div');
54
+ if (el) el.parentNode.removeChild(el);
55
+ }
56
+
57
+ const div = document.createElement('div');
58
+ div.id = 'input-textarea-caret-position-mirror-div';
59
+ document.body.appendChild(div);
60
+
61
+ const style = div.style;
62
+ const computed = window.getComputedStyle ? window.getComputedStyle(element) : element.currentStyle; // currentStyle for IE < 9
63
+ const isInput = element.nodeName === 'INPUT';
64
+
65
+ style.whiteSpace = 'pre-wrap';
66
+ if (!isInput) style.wordWrap = 'break-word';
67
+
68
+ style.position = 'absolute';
69
+ if (!debug) style.visibility = 'hidden';
70
+
71
+ properties.forEach(function(prop) {
72
+ if (isInput && prop === 'lineHeight') {
73
+ if (computed.boxSizing === 'border-box') {
74
+ const height = parseInt(computed.height);
75
+ const outerHeight =
76
+ parseInt(computed.paddingTop) +
77
+ parseInt(computed.paddingBottom) +
78
+ parseInt(computed.borderTopWidth) +
79
+ parseInt(computed.borderBottomWidth);
80
+ const targetHeight = outerHeight + parseInt(computed.lineHeight);
81
+ if (height > targetHeight) {
82
+ style.lineHeight = height - outerHeight + 'px';
83
+ } else if (height === targetHeight) {
84
+ style.lineHeight = computed.lineHeight;
85
+ } else {
86
+ style.lineHeight = '0';
87
+ }
88
+ } else {
89
+ style.lineHeight = computed.height;
90
+ }
91
+ } else {
92
+ style[prop] = computed[prop];
93
+ }
94
+ });
95
+
96
+ style.overflow = 'hidden';
97
+
98
+ div.textContent = element.value.substring(0, position);
99
+
100
+ if (isInput) div.textContent = div.textContent.replace(/\s/g, '\u00a0');
101
+
102
+ const span = document.createElement('span');
103
+
104
+ span.textContent = element.value.substring(position) || '.';
105
+ div.appendChild(span);
106
+
107
+ const coordinates = {
108
+ top: span.offsetTop + parseInt(computed['borderTopWidth']),
109
+ left: span.offsetLeft + parseInt(computed['borderLeftWidth']),
110
+ height: parseInt(computed['lineHeight'])
111
+ };
112
+
113
+ if (debug) {
114
+ span.style.backgroundColor = '#aaa';
115
+ } else {
116
+ document.body.removeChild(div);
117
+ }
118
+
119
+ return coordinates;
120
+ };
121
+
122
+ export default getCaretCoordinates;
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+ const getOS = () => {
10
+ const userAgent = window.navigator.userAgent;
11
+ const platform = window.navigator.platform;
12
+ const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'];
13
+ const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'];
14
+ const iosPlatforms = ['iPhone', 'iPad', 'iPod'];
15
+ let os = null;
16
+
17
+ if (macosPlatforms.indexOf(platform) !== -1) {
18
+ os = 'Mac OS';
19
+ } else if (iosPlatforms.indexOf(platform) !== -1) {
20
+ os = 'iOS';
21
+ } else if (windowsPlatforms.indexOf(platform) !== -1) {
22
+ os = 'Windows';
23
+ } else if (/Android/.test(userAgent)) {
24
+ os = 'Android';
25
+ } else if (!os && /Linux/.test(platform)) {
26
+ os = 'Linux';
27
+ }
28
+
29
+ return os;
30
+ };
31
+
32
+ export default getOS;
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+ export const countLines = (el: HTMLElement) => {
10
+ if (!el) return null;
11
+ const divHeight = el.offsetHeight;
12
+ const lineHeight = parseInt(getComputedStyle(el).lineHeight);
13
+ return Math.round(divHeight / lineHeight);
14
+ };
15
+
16
+ export const countWidth = (el: string, container: Element) => {
17
+ const testContainer = document.createElement('span');
18
+ const containerStyles = getComputedStyle(container);
19
+ testContainer.style['height'] = containerStyles['height'];
20
+ testContainer.style['fontSize'] = containerStyles['fontSize'];
21
+ testContainer.style['fontWeight'] = containerStyles['fontWeight'];
22
+ testContainer.style['fontFeatureSettings'] = containerStyles['fontFeatureSettings'];
23
+ testContainer.style.position = 'absolute';
24
+ testContainer.style.zIndex = '-10000';
25
+ testContainer.innerHTML = el;
26
+ document.body.appendChild(testContainer);
27
+ const width = testContainer.offsetWidth;
28
+ document.body.removeChild(testContainer);
29
+ return width;
30
+ };
31
+
32
+ export * from './getCaretCoordinates';
33
+ export * from './getOS';
34
+ export * from './Links';
@@ -0,0 +1,4 @@
1
+ import { format as formatDate } from 'date-fns';
2
+ import { YYYY_MM_DD_MINUSED } from './format';
3
+
4
+ export const formatToDateOnly = v => (v ? formatDate(new Date(v), YYYY_MM_DD_MINUSED) : v);
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright ish group pty ltd. All rights reserved. https://www.ish.com.au
3
+ * No copying or use of this code is allowed without permission in writing from ish.
4
+ */
5
+
6
+ export const YYYYMMDD_KKMMSS_MINUSED = 'yyyMMdd-kkmmss';
7
+
8
+ export const YYYY_MM_DD_MINUSED = 'yyyy-MM-dd';
9
+
10
+ export const D_III = 'd iii';
11
+
12
+ export const D_MMM = 'd MMM';
13
+
14
+ export const DD_MMM_YYYY_MINUSED = 'dd-MMM-yyyy';
15
+
16
+ export const III_DD_MMM_YYYY_HH_MM_SPECIAL = 'iii, dd MMM yyyy HH:mm';
17
+
18
+ export const III_DD_MMM_YYYY_HH_MM_AAAA_SPECIAL = 'iii, dd MMM yyyy hh:mm aaaa';
19
+
20
+ export const III_DD_MMM_YYYY = 'iii dd MMM yyyy';
21
+
22
+ export const III_DD_MMM_YYYY_HH_MM = 'iii dd MMM yyyy HH:mm';
23
+
24
+ export const III_DD_MMM_YYYY_HH_MM_SS = 'iii dd MMM yyyy HH:mm:ss';
25
+
26
+ export const EEE_D_MMM_YYYY = 'eee d MMM yyyy';
27
+
28
+ export const D_MMM_YYYY = 'd MMM yyyy';
29
+
30
+ export const DD_MMM_YYYY = 'dd MMM yyyy';
31
+
32
+ export const DD_MMM_YYYY_HH_MM = 'dd MMM yyyy HH:mm';
33
+
34
+ export const DD_MMM_YYYY_HH_MM_SS = 'dd MMM yyyy HH:mm:ss';
35
+
36
+ export const DD_MM_YYYY_SLASHED = 'dd/MM/yyyy';
37
+
38
+ export const HH_MM_COLONED = 'HH:mm';
39
+
40
+ export const HA = 'ha';
41
+
42
+ export const DD_MM_YYYY_HH_MM_SPECIAL = 'dd.MM.yyyy HH:mm';
43
+
44
+ export const KK_MM_AAAA_EEE_DD_MMM_YYYY_SPECIAL = 'kk:mmaaaa eee dd MMM yyyy';
45
+
46
+ export const DD_MMM_YYYY_AT_HH_MM_A_SPECIAL = 'dd MMM yyyy \'at\' hh:mm a';
47
+
48
+ export const DD_MMM_YYYY_AT_HH_MM_AAAA_SPECIAL = 'dd MMM yyyy \'at\' hh:mm aaaa';
49
+
50
+ export const III_DD_MMM_YYYY_HH_MM_AAAA = 'iii d MMM yyyy h:mm aaaa';
51
+
52
+ export const H_MMAAA = 'h:mmaaa';
@@ -0,0 +1,22 @@
1
+ import { formatRelative, formatDistanceStrict, format } from 'date-fns';
2
+
3
+ export const formatRelativeDate = (date: Date, baseDate: Date, formatString: string, excludeTime?: boolean, addDistance?: boolean) => {
4
+ let result = formatRelative(date, baseDate);
5
+
6
+ if (result.match(/\d\d\/\d\d\/\d\d\d\d/)) {
7
+ result = format(date, formatString).replace(/\./g, '');
8
+
9
+ if (addDistance) {
10
+ return formatDistanceStrict(
11
+ date,
12
+ baseDate
13
+ ) + ' ago';
14
+ }
15
+ }
16
+
17
+ if (excludeTime) {
18
+ result = result.replace(/at\s\d:\d\d\s([AP])M/, '');
19
+ }
20
+
21
+ return result;
22
+ };
@@ -0,0 +1,233 @@
1
+ /*
2
+ * Copyright ish group pty ltd. All rights reserved. https://www.ish.com.au
3
+ * No copying or use of this code is allowed without permission in writing from ish.
4
+ */
5
+
6
+ import { parse, addWeeks, addDays, subDays, addMonths, addYears, setHours, setMinutes } from 'date-fns';
7
+ import { DD_MMM_YYYY, DD_MMM_YYYY_HH_MM, HH_MM_COLONED } from './format';
8
+
9
+ const transitionDate = new Date(2000, 0, 1);
10
+
11
+ const formatsWithLetters = [
12
+ 'dMMMyy',
13
+ 'dMMMMyy',
14
+ 'ddMMMyy',
15
+ 'ddMMMMyy',
16
+ 'dMMMyyyy',
17
+ 'dMMMMyyyy',
18
+ 'ddMMMMyyyy',
19
+ 'ddMMMyyyy'
20
+ ];
21
+
22
+ const specialOptions = ['tm', 'yd', 'tomorrow', 'yesterday'];
23
+
24
+ const operatorsRegexp = /\s*[-+]\s*[0-9][0-9]?[dDmMyYwW]?/g;
25
+
26
+ const dividersRegexp = /[.\/\-]/g;
27
+
28
+ const timeRegexp = /(\s|^)[0-9][0-9]?:[0-9][0-9]?/;
29
+
30
+ const manageDatePart = (date: Date, part: string) => {
31
+ const numberPart = parseInt(part, 10);
32
+ switch (true) {
33
+ case /[mM]/.test(part): {
34
+ return addMonths(date, numberPart);
35
+ }
36
+ case /[yY]/.test(part): {
37
+ return addYears(date, numberPart);
38
+ }
39
+ case /[wW]/.test(part): {
40
+ return addWeeks(date, numberPart);
41
+ }
42
+ case /[dD]/.test(part):
43
+ default: {
44
+ return addDays(date, numberPart);
45
+ }
46
+ }
47
+ };
48
+
49
+ const checkInvalidDate = (date: Date) => date.toString() !== 'Invalid Date';
50
+
51
+ export const formatStringDate = (dateString: string, type: string, baseDate: Date, customFormat?: string) => {
52
+ let result;
53
+ let parsed;
54
+ let formatted = dateString;
55
+
56
+ if (type === 'date') {
57
+ baseDate.setHours(0, 0, 0, 0);
58
+ }
59
+
60
+ if (customFormat) {
61
+ parsed = parse(dateString.replace(/^\w{3}/, '').trim(), customFormat, baseDate);
62
+ if (checkInvalidDate(parsed)) {
63
+ return parsed;
64
+ }
65
+ parsed = null;
66
+ }
67
+
68
+ if (type === 'date') {
69
+ parsed = parse(dateString.replace(/^\w{3}/, '').trim(), DD_MMM_YYYY, baseDate);
70
+ if (checkInvalidDate(parsed)) {
71
+ return parsed;
72
+ }
73
+ parsed = null;
74
+ }
75
+
76
+ if (type === 'datetime') {
77
+ parsed = parse(dateString.replace(/^\w{3}/, '').trim(), DD_MMM_YYYY_HH_MM, baseDate);
78
+ if (checkInvalidDate(parsed)) {
79
+ return parsed;
80
+ }
81
+ parsed = null;
82
+ }
83
+
84
+ if (type === 'time') {
85
+ parsed = parse(dateString, HH_MM_COLONED, baseDate);
86
+ if (checkInvalidDate(parsed)) {
87
+ return parsed;
88
+ }
89
+ parsed = parse(dateString, 'HH', baseDate);
90
+ if (checkInvalidDate(parsed)) {
91
+ return parsed;
92
+ }
93
+ parsed = null;
94
+ }
95
+
96
+ const dividers = dateString.match(dividersRegexp);
97
+
98
+ const operators = dateString.match(operatorsRegexp);
99
+
100
+ const time = dateString.match(timeRegexp);
101
+
102
+ if (time) {
103
+ formatted = formatted.replace(timeRegexp, '');
104
+ }
105
+
106
+ if (operators) {
107
+ formatted = formatted.replace(operatorsRegexp, '');
108
+ }
109
+
110
+ const hasLetters = formatted.match(/[a-zA-Z]/);
111
+
112
+ if (hasLetters) {
113
+ for (const format of formatsWithLetters) {
114
+ parsed = parse(formatted.replace(/\s/g, ''), format, baseDate);
115
+ if (checkInvalidDate(parsed)) {
116
+ result = parsed;
117
+ break;
118
+ }
119
+ }
120
+ }
121
+
122
+ if (dividers && !hasLetters) {
123
+ const dateParts = formatted.trim().split(dividersRegexp);
124
+ formatted = formatted.replace(dividersRegexp, ' ');
125
+
126
+ let formatString = `${dateParts[0] ? dateParts[0].replace(/./g, 'd') : ''} ${
127
+ dateParts[1] ? dateParts[1].replace(/./g, 'M') : ''
128
+ } ${dateParts[2] ? dateParts[2].replace(/./g, 'y') : ''}`;
129
+
130
+ if (dateParts[2] && dateParts[2].length === 1) {
131
+ formatted = formatted.replace(new RegExp(dateParts[2] + '$'), `0${dateParts[2]}`);
132
+ formatString = formatString.replace(new RegExp('y$'), 'yy');
133
+ }
134
+
135
+ parsed = parse(formatted, formatString.trim(), baseDate);
136
+ if (checkInvalidDate(parsed)) {
137
+ result = parsed;
138
+ }
139
+ }
140
+
141
+ if (!dividers && !hasLetters) {
142
+ switch (formatted.length) {
143
+ case 1:
144
+ case 2: {
145
+ parsed = parse(formatted, 'dd', baseDate);
146
+ if (checkInvalidDate(parsed)) {
147
+ result = parsed;
148
+ }
149
+ break;
150
+ }
151
+ case 3: {
152
+ parsed = parse(formatted, 'ddM', baseDate);
153
+ if (checkInvalidDate(parsed)) {
154
+ result = parsed;
155
+ }
156
+ break;
157
+ }
158
+ case 4: {
159
+ parsed = parse(`${formatted[0]} ${formatted[1]} ${formatted[2] + formatted[3]}`, 'd M yy', transitionDate);
160
+ if (checkInvalidDate(parsed)) {
161
+ result = parsed;
162
+ }
163
+ break;
164
+ }
165
+ case 5: {
166
+ parsed = parse(formatted, 'ddMyy', transitionDate);
167
+ if (checkInvalidDate(parsed)) {
168
+ result = parsed;
169
+ }
170
+ break;
171
+ }
172
+ case 6: {
173
+ parsed = parse(formatted, 'ddMMyy', transitionDate);
174
+ if (checkInvalidDate(parsed)) {
175
+ result = parsed;
176
+ break;
177
+ }
178
+
179
+ break;
180
+ }
181
+ case 8: {
182
+ parsed = parse(formatted, 'ddMMyyyy', transitionDate);
183
+ if (checkInvalidDate(parsed)) {
184
+ result = parsed;
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ if (!(result instanceof Date)) {
191
+ result = baseDate;
192
+ for (const option of specialOptions) {
193
+ if (formatted === option) {
194
+ switch (option) {
195
+ case 'tomorrow':
196
+ case 'tm': {
197
+ result = addDays(result, 1);
198
+ break;
199
+ }
200
+ case 'yesterday':
201
+ case 'yd': {
202
+ result = subDays(result, 1);
203
+ }
204
+ }
205
+ break;
206
+ }
207
+ }
208
+ }
209
+
210
+ if (operators) {
211
+ operators.forEach(op => {
212
+ result = manageDatePart(result, op.trim());
213
+ });
214
+ }
215
+
216
+ if (time && (type === 'time' || type === 'datetime')) {
217
+ parsed = parse(time[0].trim(), 'HH:mm', baseDate);
218
+ if (checkInvalidDate(parsed)) {
219
+ result = setHours(result, parsed.getHours());
220
+ result = setMinutes(result, parsed.getMinutes());
221
+ }
222
+ }
223
+
224
+ return result;
225
+ };
226
+
227
+ export const formatDurationMinutes = (minutes: number): string => {
228
+ const duration = (minutes / 60).toString().split('.');
229
+
230
+ return `${duration[0] === '0' ? '' : duration[0] + 'h'} ${
231
+ duration[1] ? (parseFloat('0.' + duration[1]) * 60).toFixed() + 'min' : ''
232
+ }`.trim();
233
+ };
@@ -0,0 +1,37 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2020.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
5
+ * GNU Affero General Public License version 3 as published by the Free Software Foundation.
6
+ *
7
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9
+ * See the GNU Affero General Public License for more details.
10
+ */
11
+
12
+ import { utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz';
13
+
14
+ export const appendTimezone = (date: Date, timezone: string) => {
15
+ let result = date;
16
+ try {
17
+ result = utcToZonedTime(date, timezone);
18
+ } catch (e) {
19
+ // eslint-disable-next-line no-console
20
+ console.warn(e);
21
+ return date;
22
+ }
23
+ return result;
24
+ };
25
+
26
+ export const prependTimezone = (date: Date, timezone: string) => {
27
+ let result = date;
28
+
29
+ try {
30
+ result = zonedTimeToUtc(date, timezone);
31
+ } catch (e) {
32
+ // eslint-disable-next-line no-console
33
+ console.warn(e);
34
+ return date;
35
+ }
36
+ return result;
37
+ };
@@ -0,0 +1,15 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+
10
+ export * from './datesNormalizing';
11
+ export * from './format';
12
+ export * from './formatRelative';
13
+ export * from './formatString';
14
+ export * from './formatTimezone';
15
+ export * from './timetable';
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Copyright ish group pty ltd 2023.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
5
+ *
6
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
7
+ */
8
+
9
+ import { getDay, getDaysInMonth, lastDayOfMonth } from 'date-fns';
10
+
11
+ const generateOneMonth = (today, status) =>
12
+ Array(getDaysInMonth(today))
13
+ .fill(null)
14
+ .map((el, id) => ({
15
+ day: id + 1,
16
+ date: new Date(today.getFullYear(), today.getMonth(), id + 1),
17
+ status
18
+ }));
19
+
20
+ export const getCalendarDays = today => {
21
+ const currentMonth = generateOneMonth(today, 'current');
22
+ const previousMonth = generateOneMonth(new Date(today.getFullYear(), today.getMonth() - 1), 'previous');
23
+ const nextMonth = generateOneMonth(new Date(today.getFullYear(), today.getMonth() + 1), 'next');
24
+
25
+ const firstDayIndex = getDay(new Date(today.getFullYear(), today.getMonth(), 1));
26
+ const lastDayIndex = getDay(lastDayOfMonth(today));
27
+
28
+ const binaryCalendarState = (firstDayIndex, lastDayIndex) =>
29
+ parseInt(String(+!!firstDayIndex) + +(lastDayIndex < 6), 2);
30
+
31
+ switch (binaryCalendarState(firstDayIndex, lastDayIndex)) {
32
+ case 0:
33
+ return currentMonth;
34
+ case 1:
35
+ return currentMonth.concat(nextMonth.slice(0, 6 - lastDayIndex));
36
+ case 2:
37
+ return previousMonth.slice(previousMonth.length - firstDayIndex).concat(currentMonth);
38
+ case 3:
39
+ return previousMonth
40
+ .slice(previousMonth.length - firstDayIndex)
41
+ .concat(currentMonth)
42
+ .concat(nextMonth.slice(0, 6 - lastDayIndex));
43
+ default:
44
+ return currentMonth;
45
+ }
46
+ };