@griddo/ax 11.7.13 → 11.8.0-rc.1

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 +3 -2
  2. package/src/GlobalStore.tsx +3 -0
  3. package/src/api/index.tsx +4 -0
  4. package/src/api/logs.tsx +97 -0
  5. package/src/api/navigation.tsx +1 -1
  6. package/src/api/pages.tsx +1 -1
  7. package/src/api/schemas.tsx +18 -0
  8. package/src/api/users.tsx +17 -0
  9. package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +3 -2
  10. package/src/components/ConfigPanel/Form/index.tsx +3 -1
  11. package/src/components/ConfigPanel/index.tsx +3 -0
  12. package/src/components/Fields/SummaryButton/index.tsx +6 -4
  13. package/src/components/Fields/TimeField/style.tsx +0 -1
  14. package/src/components/Fields/TranslateButton/index.tsx +3 -0
  15. package/src/components/FloatingMenu/index.tsx +25 -1
  16. package/src/components/FloatingMenu/style.tsx +3 -2
  17. package/src/components/LanguageMenu/index.tsx +1 -1
  18. package/src/components/MainWrapper/AppBar/index.tsx +4 -3
  19. package/src/components/RestoreModal/index.tsx +51 -0
  20. package/src/components/RestoreModal/style.tsx +7 -0
  21. package/src/components/SearchField/index.tsx +1 -1
  22. package/src/components/SearchField/style.tsx +4 -4
  23. package/src/components/TableFilters/CheckGroupFilter/index.tsx +42 -5
  24. package/src/components/TableFilters/CheckGroupFilter/style.tsx +8 -1
  25. package/src/components/TableFilters/SiteFilter/index.tsx +26 -57
  26. package/src/components/Tag/index.tsx +6 -3
  27. package/src/components/Tag/style.tsx +2 -2
  28. package/src/components/index.tsx +2 -0
  29. package/src/containers/ActivityLog/actions.tsx +262 -0
  30. package/src/containers/ActivityLog/constants.tsx +6 -0
  31. package/src/containers/ActivityLog/index.tsx +4 -0
  32. package/src/containers/ActivityLog/interfaces.tsx +12 -0
  33. package/src/containers/ActivityLog/reducer.tsx +25 -0
  34. package/src/containers/Navigation/Defaults/actions.tsx +4 -3
  35. package/src/containers/StructuredData/actions.tsx +7 -4
  36. package/src/containers/StructuredData/interfaces.tsx +2 -8
  37. package/src/containers/StructuredData/reducer.tsx +2 -8
  38. package/src/containers/Users/actions.tsx +22 -19
  39. package/src/modules/ActivityLog/DetailModal/index.tsx +108 -0
  40. package/src/modules/ActivityLog/DetailModal/style.tsx +52 -0
  41. package/src/modules/ActivityLog/DownloadModal/index.tsx +104 -0
  42. package/src/modules/ActivityLog/DownloadModal/style.tsx +12 -0
  43. package/src/modules/ActivityLog/ItemGroup/index.tsx +27 -0
  44. package/src/modules/ActivityLog/ItemGroup/style.tsx +39 -0
  45. package/src/modules/ActivityLog/ItemLog/EventItem/index.tsx +167 -0
  46. package/src/modules/ActivityLog/ItemLog/EventItem/style.tsx +79 -0
  47. package/src/modules/ActivityLog/ItemLog/index.tsx +24 -0
  48. package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/index.tsx +170 -0
  49. package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/style.tsx +79 -0
  50. package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +46 -0
  51. package/src/modules/ActivityLog/ItemLogUser/UserItem/style.tsx +60 -0
  52. package/src/modules/ActivityLog/ItemLogUser/index.tsx +25 -0
  53. package/src/modules/ActivityLog/LogFilters/ContentFilter/index.tsx +79 -0
  54. package/src/modules/ActivityLog/LogFilters/DateFilter/index.tsx +91 -0
  55. package/src/modules/ActivityLog/LogFilters/DateFilter/style.tsx +208 -0
  56. package/src/modules/ActivityLog/LogFilters/EventFilter/index.tsx +80 -0
  57. package/src/modules/ActivityLog/LogFilters/OrderFilter/index.tsx +49 -0
  58. package/src/modules/ActivityLog/LogFilters/OrderFilter/style.tsx +35 -0
  59. package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +79 -0
  60. package/src/modules/ActivityLog/TableHeader/index.tsx +72 -0
  61. package/src/modules/ActivityLog/TableHeader/style.tsx +73 -0
  62. package/src/modules/ActivityLog/constants.tsx +10 -0
  63. package/src/modules/ActivityLog/hooks.tsx +53 -0
  64. package/src/modules/ActivityLog/index.tsx +313 -0
  65. package/src/modules/ActivityLog/style.tsx +57 -0
  66. package/src/modules/ActivityLog/utils.tsx +31 -0
  67. package/src/modules/Categories/CategoriesList/index.tsx +1 -1
  68. package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/Form/index.tsx +3 -0
  69. package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/index.tsx +3 -0
  70. package/src/modules/Forms/FormEditor/Editor/index.tsx +5 -2
  71. package/src/modules/Forms/FormEditor/index.tsx +20 -3
  72. package/src/modules/GlobalEditor/Editor/index.tsx +3 -0
  73. package/src/modules/GlobalEditor/index.tsx +48 -9
  74. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -1
  75. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +4 -1
  76. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +45 -6
  77. package/src/modules/PageEditor/Editor/index.tsx +4 -1
  78. package/src/modules/PageEditor/index.tsx +46 -7
  79. package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +1 -7
  80. package/src/modules/StructuredData/Form/index.tsx +56 -7
  81. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +2 -2
  82. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +2 -8
  83. package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -9
  84. package/src/modules/StructuredData/StructuredDataList/index.tsx +3 -4
  85. package/src/modules/Users/Roles/index.tsx +0 -2
  86. package/src/modules/Users/UserEdit/index.tsx +12 -28
  87. package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +1 -0
  88. package/src/modules/Users/UserList/UserItem/index.tsx +10 -25
  89. package/src/modules/Users/UserList/index.tsx +8 -10
  90. package/src/routes/multisite.tsx +9 -0
  91. package/src/themes/theme.json +2 -1
  92. package/src/types/forms.tsx +1 -0
  93. package/src/types/index.tsx +8 -0
  94. package/src/types/logs.tsx +12 -0
  95. package/src/components/TableFilters/SiteFilter/style.tsx +0 -28
@@ -49,12 +49,12 @@ import {
49
49
  IStructuredDataContent,
50
50
  IGetStructuredDataParams,
51
51
  IErrorItem,
52
- IStructuredDataQueryValues,
53
52
  IStructuredDataCategory,
54
53
  ICategoryGroupParams,
55
54
  IRootState,
56
55
  IOrderCategoryParams,
57
56
  IExportDataParams,
57
+ IQueryValue,
58
58
  } from "@ax/types";
59
59
  import { structuredData } from "@ax/api";
60
60
  import { setTotalItems } from "@ax/containers/Sites/actions";
@@ -125,7 +125,7 @@ function setValidated(validated: boolean): ISetValidated {
125
125
  return { type: SET_VALIDATED, payload: { validated } };
126
126
  }
127
127
 
128
- function setContentFilters(contentFilters: Record<string, IStructuredDataQueryValues> | null): ISetContentFilters {
128
+ function setContentFilters(contentFilters: Record<string, Record<string, IQueryValue[]>> | null): ISetContentFilters {
129
129
  return { type: SET_CONTENT_FILTERS, payload: { contentFilters } };
130
130
  }
131
131
 
@@ -435,7 +435,9 @@ function deleteStructuredDataContent(
435
435
  };
436
436
  }
437
437
 
438
- function restoreStructuredDataContent(dataID: number | number[]): (dispatch: Dispatch, getState: any) => Promise<void> {
438
+ function restoreStructuredDataContent(
439
+ dataID: number | number[]
440
+ ): (dispatch: Dispatch, getState: () => IRootState) => Promise<boolean> {
439
441
  return async (dispatch, getState) => {
440
442
  try {
441
443
  dispatch(setIsLoading(true));
@@ -466,9 +468,10 @@ function restoreStructuredDataContent(dataID: number | number[]): (dispatch: Dis
466
468
  ? structuredData.restoreDataContentBulk(dataID)
467
469
  : structuredData.restoreDataContent(dataID);
468
470
 
469
- await handleRequest(callback, responseActions, [])(dispatch);
471
+ return await handleRequest(callback, responseActions, [])(dispatch);
470
472
  } catch (e) {
471
473
  console.log(e);
474
+ return false;
472
475
  }
473
476
  };
474
477
  }
@@ -17,13 +17,7 @@ import {
17
17
  SET_CURRENT_SEARCH,
18
18
  } from "./constants";
19
19
 
20
- import {
21
- IStructuredData,
22
- IStructuredDataContent,
23
- IErrorItem,
24
- IStructuredDataQueryValues,
25
- IStructuredDataCategory,
26
- } from "@ax/types";
20
+ import { IStructuredData, IStructuredDataContent, IErrorItem, IStructuredDataCategory, IQueryValue } from "@ax/types";
27
21
 
28
22
  export interface ISetCategories {
29
23
  type: typeof SET_CATEGORIES;
@@ -91,7 +85,7 @@ export interface ISetValidated {
91
85
 
92
86
  export interface ISetContentFilters {
93
87
  type: typeof SET_CONTENT_FILTERS;
94
- payload: { contentFilters: Record<string, IStructuredDataQueryValues> | null };
88
+ payload: { contentFilters: Record<string, Record<string, IQueryValue[]>> | null };
95
89
  }
96
90
 
97
91
  export interface ISetIsIATranslated {
@@ -1,10 +1,4 @@
1
- import {
2
- IStructuredData,
3
- IStructuredDataContent,
4
- IErrorItem,
5
- IStructuredDataQueryValues,
6
- IStructuredDataCategory,
7
- } from "@ax/types";
1
+ import { IStructuredData, IStructuredDataContent, IErrorItem, IStructuredDataCategory, IQueryValue } from "@ax/types";
8
2
  import {
9
3
  SET_CATEGORIES,
10
4
  SET_STRUCTURED_DATA,
@@ -41,7 +35,7 @@ export interface IStructuredDataState {
41
35
  schemaVersion: string;
42
36
  errors: IErrorItem[];
43
37
  validated: boolean;
44
- contentFilters: Record<string, IStructuredDataQueryValues> | null;
38
+ contentFilters: Record<string, Record<string, IQueryValue[]>> | null;
45
39
  isIATranslated: boolean;
46
40
  currentSearch: string;
47
41
  }
@@ -68,7 +68,7 @@ function getUser(
68
68
  id: string | number,
69
69
  token?: string,
70
70
  hasLoading = true
71
- ): (dispatch: Dispatch, getState: any) => Promise<void> {
71
+ ): (dispatch: Dispatch, getState: () => IRootState) => Promise<void> {
72
72
  return async (dispatch, getState) => {
73
73
  try {
74
74
  const callback = async () => users.getUser(id, token);
@@ -102,7 +102,7 @@ function updateUser(
102
102
  data: IUser,
103
103
  isProfile: boolean,
104
104
  isList?: boolean
105
- ): (dispatch: Dispatch, getState: any) => Promise<boolean> {
105
+ ): (dispatch: Dispatch, getState: () => IRootState) => Promise<boolean> {
106
106
  return async (dispatch, getState) => {
107
107
  try {
108
108
  const {
@@ -174,7 +174,7 @@ function createUser(data: { name: string; email: string }): (dispatch: Dispatch)
174
174
  function createPassword(
175
175
  id: string,
176
176
  params: ICreatePasswordParams
177
- ): (dispatch: Dispatch, getState: any) => Promise<boolean> {
177
+ ): (dispatch: Dispatch, getState: () => IRootState) => Promise<boolean> {
178
178
  return async (dispatch, getState) => {
179
179
  try {
180
180
  const callback = async () => global.createPassword(id, params);
@@ -195,7 +195,7 @@ function createPassword(
195
195
  };
196
196
  }
197
197
 
198
- function deleteUser(id: number | number[]): (dispatch: Dispatch, getState: any) => Promise<boolean> {
198
+ function deleteUser(id: number | number[]): (dispatch: Dispatch, getState: () => IRootState) => Promise<boolean> {
199
199
  return async (dispatch, getState) => {
200
200
  try {
201
201
  const {
@@ -223,28 +223,31 @@ function deleteUser(id: number | number[]): (dispatch: Dispatch, getState: any)
223
223
 
224
224
  return await handleRequest(callback, responseActions, [])(dispatch);
225
225
  } catch (e) {
226
- console.log(e); // TODO: capturar error bien
226
+ console.log(e);
227
227
  return false;
228
228
  }
229
229
  };
230
230
  }
231
231
 
232
- function resetUserData(): (dispatch: Dispatch, getState: any) => void {
233
- return (dispatch, getState) => {
234
- const {
235
- users: { userData },
236
- } = getState();
232
+ function resendInvitation(id: number): (dispatch: Dispatch) => Promise<boolean> {
233
+ return async (dispatch) => {
234
+ try {
235
+ const responseActions = {
236
+ handleSuccess: () => null,
237
+ handleError: (response: any) => appActions.handleError(response)(dispatch),
238
+ };
237
239
 
238
- userData &&
239
- Object.keys(userData).forEach((key: string) => {
240
- userData[key] = "";
241
- });
240
+ const callback = async () => users.resendInvitation(id);
242
241
 
243
- dispatch(setUserForm(userData));
242
+ return await handleRequest(callback, responseActions, [])(dispatch);
243
+ } catch (e) {
244
+ console.log(e);
245
+ return false;
246
+ }
244
247
  };
245
248
  }
246
249
 
247
- function resendInvitation(id: number): (dispatch: Dispatch) => Promise<boolean> {
250
+ function removeUserFromSite(userID: number, siteID: number): (dispatch: Dispatch) => Promise<boolean> {
248
251
  return async (dispatch) => {
249
252
  try {
250
253
  const responseActions = {
@@ -252,11 +255,11 @@ function resendInvitation(id: number): (dispatch: Dispatch) => Promise<boolean>
252
255
  handleError: (response: any) => appActions.handleError(response)(dispatch),
253
256
  };
254
257
 
255
- const callback = async () => users.resendInvitation(id);
258
+ const callback = async () => users.removeUserFromSite(userID, siteID);
256
259
 
257
260
  return await handleRequest(callback, responseActions, [])(dispatch);
258
261
  } catch (e) {
259
- console.log(e); // TODO: capturar error bien
262
+ console.log(e);
260
263
  return false;
261
264
  }
262
265
  };
@@ -358,7 +361,6 @@ export {
358
361
  getUser,
359
362
  setUserForm,
360
363
  createUser,
361
- resetUserData,
362
364
  setCurrentUser,
363
365
  deleteUser,
364
366
  resendInvitation,
@@ -366,4 +368,5 @@ export {
366
368
  activateRoles,
367
369
  createPassword,
368
370
  getUserCurrentPermissions,
371
+ removeUserFromSite,
369
372
  };
@@ -0,0 +1,108 @@
1
+ import React from "react";
2
+ import { format } from "date-fns";
3
+
4
+ import { LogActivityDTO } from "@griddo/api-types";
5
+
6
+ import { IModal } from "@ax/types";
7
+ import { Button, Modal } from "@ax/components";
8
+ import { eventKey } from "../constants";
9
+
10
+ import * as S from "./style";
11
+
12
+ const DetailModal = (props: IDetailModalProps) => {
13
+ const { isOpen, toggleModal, restorePage, onClick, onKeyDown, itemLog } = props;
14
+
15
+ const { id, created, eventType, user, contentType, content } = itemLog;
16
+
17
+ const isDeleteEventWithRestore =
18
+ eventType && eventType.internal_key ? Object.values(eventKey).includes(eventType.internal_key) : false;
19
+
20
+ const isDeleteEvent = eventType?.internal_key ? eventType.internal_key.includes("DELETED") : false;
21
+
22
+ const getButtonText = (type: string | undefined | null) => {
23
+ if (!type) return "";
24
+
25
+ switch (type) {
26
+ case eventKey.DELETED_PAGE:
27
+ case eventKey.DELETED_CONTENT_TYPE_PAGE:
28
+ return "Restore page";
29
+ case eventKey.DELETED_FOOTER:
30
+ return "Restore footer";
31
+ case eventKey.DELETED_HEADER:
32
+ return "Restore header";
33
+ case eventKey.DELETED_CATEGORY:
34
+ return "Restore category";
35
+ case eventKey.DELETED_CONTENT_TYPE:
36
+ return "Restore content type";
37
+ default:
38
+ return "Restore";
39
+ }
40
+ };
41
+
42
+ return (
43
+ <Modal isOpen={isOpen} hide={toggleModal} title="Log detail" size="S" height={465}>
44
+ <S.ModalContent>
45
+ <S.ItemRow>
46
+ <S.ItemTitle>Action ID</S.ItemTitle>
47
+ <S.ItemContent>{id}</S.ItemContent>
48
+ </S.ItemRow>
49
+ <S.ItemRow>
50
+ <S.ItemTitle>Event</S.ItemTitle>
51
+ <S.ItemContent>
52
+ <S.Event>
53
+ <span>{eventType?.name || ""}</span>
54
+ <S.EventContent
55
+ onClick={!isDeleteEvent ? onClick : undefined}
56
+ role="button"
57
+ tabIndex={0}
58
+ onKeyDown={!isDeleteEvent ? onKeyDown : undefined}
59
+ >
60
+ {content?.title || contentType?.title || ""}
61
+ </S.EventContent>
62
+ </S.Event>
63
+ </S.ItemContent>
64
+ </S.ItemRow>
65
+ <S.ItemRow>
66
+ <S.ItemTitle>Date</S.ItemTitle>
67
+ <S.ItemContent>{`${format(new Date(created.date), "MMMM d, yyyy")} ${created.hour}`}</S.ItemContent>
68
+ </S.ItemRow>
69
+ <S.ItemRow>
70
+ <S.ItemTitle>User</S.ItemTitle>
71
+ <S.ItemContent>{user.name}</S.ItemContent>
72
+ </S.ItemRow>
73
+ <S.ItemRow>
74
+ <S.ItemTitle>Email</S.ItemTitle>
75
+ <S.ItemContent>{user.email}</S.ItemContent>
76
+ </S.ItemRow>
77
+ <S.ItemRow>
78
+ <S.ItemTitle>Role</S.ItemTitle>
79
+ <S.ItemContent>{user.role}</S.ItemContent>
80
+ </S.ItemRow>
81
+ <S.ItemRow>
82
+ <S.ItemTitle>IP Address</S.ItemTitle>
83
+ <S.ItemContent>{user.ip}</S.ItemContent>
84
+ </S.ItemRow>
85
+ {/*<S.ItemRow removeBorder={true}>
86
+ <S.ItemTitle>Country</S.ItemTitle>
87
+ <S.ItemContent>{user.country}</S.ItemContent>
88
+ </S.ItemRow>*/}
89
+ {eventType && isDeleteEventWithRestore && (
90
+ <S.ActionWrapper>
91
+ <Button type="button" buttonStyle="line" icon="back" onClick={restorePage}>
92
+ {getButtonText(eventType.internal_key)}
93
+ </Button>
94
+ </S.ActionWrapper>
95
+ )}
96
+ </S.ModalContent>
97
+ </Modal>
98
+ );
99
+ };
100
+
101
+ interface IDetailModalProps extends IModal {
102
+ itemLog: LogActivityDTO;
103
+ restorePage(): void;
104
+ onClick(e: React.MouseEvent<HTMLDivElement>): void;
105
+ onKeyDown(): void;
106
+ }
107
+
108
+ export default DetailModal;
@@ -0,0 +1,52 @@
1
+ import styled from "styled-components";
2
+
3
+ const ModalContent = styled.div`
4
+ padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.m}`};
5
+ `;
6
+
7
+ const ItemRow = styled.div<{ removeBorder?: boolean }>`
8
+ display: flex;
9
+ ${(p) => p.theme.textStyle.uiM};
10
+ color: ${(p) => p.theme.color.textHighEmphasis};
11
+ height: ${(p) => p.theme.spacing.l};
12
+ border-bottom: ${(p) => (p.removeBorder ? "none" : `1px solid ${p.theme.color.uiLine}`)};
13
+ `;
14
+
15
+ const ItemTitle = styled.div`
16
+ display: flex;
17
+ font-weight: 600;
18
+ align-items: center;
19
+ width: 110px;
20
+ flex-shrink: 0;
21
+ `;
22
+
23
+ const ItemContent = styled.div`
24
+ display: flex;
25
+ align-items: center;
26
+ `;
27
+
28
+ const Event = styled.div`
29
+ align-items: center;
30
+ font-weight: 600;
31
+ color: ${(p) => p.theme.colors.textMediumEmphasis};
32
+ `;
33
+
34
+ const EventContent = styled.span`
35
+ margin-left: ${(p) => p.theme.spacing.xxs};
36
+ color: ${(p) => p.theme.colors.interactive01};
37
+ flex-basis: 100%;
38
+ `;
39
+
40
+ const ActionWrapper = styled.div`
41
+ margin-top: ${(p) => p.theme.spacing.xs};
42
+ margin-bottom: ${(p) => p.theme.spacing.xs};
43
+ button {
44
+ background-color: transparent;
45
+ width: 100%;
46
+ svg {
47
+ left: 0;
48
+ }
49
+ }
50
+ `;
51
+
52
+ export { ModalContent, ItemRow, ItemTitle, ItemContent, ActionWrapper, Event, EventContent };
@@ -0,0 +1,104 @@
1
+ import React from "react";
2
+
3
+ import { IModal } from "@ax/types";
4
+ import { FieldsBehavior, Modal } from "@ax/components";
5
+ import { IDownloadFormState } from "..";
6
+
7
+ import * as S from "./style";
8
+
9
+ const DownloadModal = (props: IDownloadModalProps) => {
10
+ const { isOpen, toggleModal, mainModalAction, form, setForm } = props;
11
+
12
+ const setDateRange = (dateRange: string) => setForm((state) => ({ ...state, dateRange }));
13
+ const setStartDate = (startDate: string) => setForm((state) => ({ ...state, startDate }));
14
+ const setEndDate = (endDate: string) => setForm((state) => ({ ...state, endDate }));
15
+ const setStartTime = (startTime: string) => setForm((state) => ({ ...state, startTime }));
16
+ const setMaxEvents = (maxEvents: number) => setForm((state) => ({ ...state, maxEvents }));
17
+ const setFormat = (format: string) => setForm((state) => ({ ...state, format }));
18
+
19
+ const secondaryModalAction = { title: "Cancel", onClick: toggleModal };
20
+
21
+ const rangeOptions = [
22
+ { name: "7days", value: "7", title: "Last 7 days" },
23
+ { name: "30days", value: "30", title: "Last 30 days" },
24
+ { name: "custom", value: "custom", title: "Custom date" },
25
+ ];
26
+
27
+ const formatOptions = [
28
+ { name: "csv", value: "csv", title: ".csv" },
29
+ { name: "xlsx", value: "xlsx", title: ".xlsx" },
30
+ ];
31
+
32
+ return (
33
+ <Modal
34
+ isOpen={isOpen}
35
+ hide={toggleModal}
36
+ title="Download User activity log"
37
+ secondaryAction={secondaryModalAction}
38
+ mainAction={mainModalAction}
39
+ size="S"
40
+ height={573}
41
+ >
42
+ <S.ModalContent>
43
+ <FieldsBehavior
44
+ title="Range"
45
+ name="dateRange"
46
+ fieldType="RadioGroup"
47
+ options={rangeOptions}
48
+ value={form.dateRange}
49
+ onChange={setDateRange}
50
+ />
51
+ {form.dateRange === "custom" && (
52
+ <S.CustomDateWrapper>
53
+ <FieldsBehavior
54
+ title="Start date"
55
+ name="startDate"
56
+ fieldType="DateField"
57
+ value={form.startDate}
58
+ onChange={setStartDate}
59
+ pastDate={true}
60
+ />
61
+ <FieldsBehavior
62
+ title="End date"
63
+ name="endDate"
64
+ fieldType="DateField"
65
+ value={form.endDate}
66
+ onChange={setEndDate}
67
+ pastDate={true}
68
+ />
69
+ </S.CustomDateWrapper>
70
+ )}
71
+ <FieldsBehavior
72
+ title="Start time"
73
+ name="startTime"
74
+ fieldType="TimeField"
75
+ value={form.startTime}
76
+ onChange={setStartTime}
77
+ helptext="12 hour time format"
78
+ />
79
+ <FieldsBehavior
80
+ title="Max Events number"
81
+ name="maxEvents"
82
+ fieldType="NumberField"
83
+ value={form.maxEvents}
84
+ onChange={setMaxEvents}
85
+ />
86
+ <FieldsBehavior
87
+ title="Format"
88
+ name="format"
89
+ fieldType="RadioGroup"
90
+ options={formatOptions}
91
+ value={form.format}
92
+ onChange={setFormat}
93
+ />
94
+ </S.ModalContent>
95
+ </Modal>
96
+ );
97
+ };
98
+
99
+ interface IDownloadModalProps extends IModal {
100
+ form: IDownloadFormState;
101
+ setForm: React.Dispatch<React.SetStateAction<IDownloadFormState>>;
102
+ }
103
+
104
+ export default DownloadModal;
@@ -0,0 +1,12 @@
1
+ import styled from "styled-components";
2
+
3
+ const ModalContent = styled.div`
4
+ padding: ${(p) => `${p.theme.spacing.m} ${p.theme.spacing.m} ${p.theme.spacing.l} ${p.theme.spacing.m}`};
5
+ `;
6
+
7
+ const CustomDateWrapper = styled.div`
8
+ display: flex;
9
+ gap: ${(p) => p.theme.spacing.m};
10
+ `;
11
+
12
+ export { ModalContent, CustomDateWrapper };
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import { dateToString } from "@ax/helpers";
3
+
4
+ import * as S from "./style";
5
+
6
+ const ItemGroup = (props: IItemGroupProps) => {
7
+ const { date, children, count } = props;
8
+ const dateTitle = dateToString(new Date(date), "MMM d yyyy");
9
+
10
+ return (
11
+ <S.Wrapper>
12
+ <S.Header>
13
+ <S.DateWrapper>{dateTitle}</S.DateWrapper>
14
+ <S.CounterWrapper>{count} events</S.CounterWrapper>
15
+ </S.Header>
16
+ <S.ItemList>{children}</S.ItemList>
17
+ </S.Wrapper>
18
+ );
19
+ };
20
+
21
+ interface IItemGroupProps {
22
+ children: JSX.Element[];
23
+ date: string;
24
+ count: number;
25
+ }
26
+
27
+ export default ItemGroup;
@@ -0,0 +1,39 @@
1
+ import styled from "styled-components";
2
+
3
+ const Wrapper = styled.div`
4
+ display: flex;
5
+ position: relative;
6
+ flex-direction: column;
7
+ background-color: ${(p) => p.theme.color.uiBackground03};
8
+ border-radius: ${(p) => p.theme.radii.m};
9
+ padding: ${(p) => `0 ${p.theme.spacing.xs} ${p.theme.spacing.xs} ${p.theme.spacing.xs}`};
10
+ margin-bottom: ${(p) => p.theme.spacing.m};
11
+ `;
12
+
13
+ const Header = styled.div`
14
+ position: sticky;
15
+ background-color: ${(p) => p.theme.color.uiBackground03};
16
+ top: 34px;
17
+ display: flex;
18
+ color: ${(p) => p.theme.colors.textHighEmphasis};
19
+ align-items: center;
20
+ padding: ${(p) => `${p.theme.spacing.xs} 0`};
21
+ z-index: 1;
22
+ `;
23
+
24
+ const DateWrapper = styled.div`
25
+ ${(p) => p.theme.textStyle.uiM};
26
+ `;
27
+
28
+ const CounterWrapper = styled.div`
29
+ ${(p) => p.theme.textStyle.uiXS};
30
+ margin-left: auto;
31
+ `;
32
+
33
+ const ItemList = styled.div`
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: ${(p) => p.theme.spacing.xxs};
37
+ `;
38
+
39
+ export { Wrapper, Header, DateWrapper, CounterWrapper, ItemList };