@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.
- package/package.json +3 -2
- package/src/GlobalStore.tsx +3 -0
- package/src/api/index.tsx +4 -0
- package/src/api/logs.tsx +97 -0
- package/src/api/navigation.tsx +1 -1
- package/src/api/pages.tsx +1 -1
- package/src/api/schemas.tsx +18 -0
- package/src/api/users.tsx +17 -0
- package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +3 -2
- package/src/components/ConfigPanel/Form/index.tsx +3 -1
- package/src/components/ConfigPanel/index.tsx +3 -0
- package/src/components/Fields/SummaryButton/index.tsx +6 -4
- package/src/components/Fields/TimeField/style.tsx +0 -1
- package/src/components/Fields/TranslateButton/index.tsx +3 -0
- package/src/components/FloatingMenu/index.tsx +25 -1
- package/src/components/FloatingMenu/style.tsx +3 -2
- package/src/components/LanguageMenu/index.tsx +1 -1
- package/src/components/MainWrapper/AppBar/index.tsx +4 -3
- package/src/components/RestoreModal/index.tsx +51 -0
- package/src/components/RestoreModal/style.tsx +7 -0
- package/src/components/SearchField/index.tsx +1 -1
- package/src/components/SearchField/style.tsx +4 -4
- package/src/components/TableFilters/CheckGroupFilter/index.tsx +42 -5
- package/src/components/TableFilters/CheckGroupFilter/style.tsx +8 -1
- package/src/components/TableFilters/SiteFilter/index.tsx +26 -57
- package/src/components/Tag/index.tsx +6 -3
- package/src/components/Tag/style.tsx +2 -2
- package/src/components/index.tsx +2 -0
- package/src/containers/ActivityLog/actions.tsx +262 -0
- package/src/containers/ActivityLog/constants.tsx +6 -0
- package/src/containers/ActivityLog/index.tsx +4 -0
- package/src/containers/ActivityLog/interfaces.tsx +12 -0
- package/src/containers/ActivityLog/reducer.tsx +25 -0
- package/src/containers/Navigation/Defaults/actions.tsx +4 -3
- package/src/containers/StructuredData/actions.tsx +7 -4
- package/src/containers/StructuredData/interfaces.tsx +2 -8
- package/src/containers/StructuredData/reducer.tsx +2 -8
- package/src/containers/Users/actions.tsx +22 -19
- package/src/modules/ActivityLog/DetailModal/index.tsx +108 -0
- package/src/modules/ActivityLog/DetailModal/style.tsx +52 -0
- package/src/modules/ActivityLog/DownloadModal/index.tsx +104 -0
- package/src/modules/ActivityLog/DownloadModal/style.tsx +12 -0
- package/src/modules/ActivityLog/ItemGroup/index.tsx +27 -0
- package/src/modules/ActivityLog/ItemGroup/style.tsx +39 -0
- package/src/modules/ActivityLog/ItemLog/EventItem/index.tsx +167 -0
- package/src/modules/ActivityLog/ItemLog/EventItem/style.tsx +79 -0
- package/src/modules/ActivityLog/ItemLog/index.tsx +24 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/index.tsx +170 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/style.tsx +79 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +46 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/style.tsx +60 -0
- package/src/modules/ActivityLog/ItemLogUser/index.tsx +25 -0
- package/src/modules/ActivityLog/LogFilters/ContentFilter/index.tsx +79 -0
- package/src/modules/ActivityLog/LogFilters/DateFilter/index.tsx +91 -0
- package/src/modules/ActivityLog/LogFilters/DateFilter/style.tsx +208 -0
- package/src/modules/ActivityLog/LogFilters/EventFilter/index.tsx +80 -0
- package/src/modules/ActivityLog/LogFilters/OrderFilter/index.tsx +49 -0
- package/src/modules/ActivityLog/LogFilters/OrderFilter/style.tsx +35 -0
- package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +79 -0
- package/src/modules/ActivityLog/TableHeader/index.tsx +72 -0
- package/src/modules/ActivityLog/TableHeader/style.tsx +73 -0
- package/src/modules/ActivityLog/constants.tsx +10 -0
- package/src/modules/ActivityLog/hooks.tsx +53 -0
- package/src/modules/ActivityLog/index.tsx +313 -0
- package/src/modules/ActivityLog/style.tsx +57 -0
- package/src/modules/ActivityLog/utils.tsx +31 -0
- package/src/modules/Categories/CategoriesList/index.tsx +1 -1
- package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/Form/index.tsx +3 -0
- package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/index.tsx +3 -0
- package/src/modules/Forms/FormEditor/Editor/index.tsx +5 -2
- package/src/modules/Forms/FormEditor/index.tsx +20 -3
- package/src/modules/GlobalEditor/Editor/index.tsx +3 -0
- package/src/modules/GlobalEditor/index.tsx +48 -9
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -1
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +4 -1
- package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +45 -6
- package/src/modules/PageEditor/Editor/index.tsx +4 -1
- package/src/modules/PageEditor/index.tsx +46 -7
- package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +1 -7
- package/src/modules/StructuredData/Form/index.tsx +56 -7
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +2 -2
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +2 -8
- package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -9
- package/src/modules/StructuredData/StructuredDataList/index.tsx +3 -4
- package/src/modules/Users/Roles/index.tsx +0 -2
- package/src/modules/Users/UserEdit/index.tsx +12 -28
- package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +1 -0
- package/src/modules/Users/UserList/UserItem/index.tsx +10 -25
- package/src/modules/Users/UserList/index.tsx +8 -10
- package/src/routes/multisite.tsx +9 -0
- package/src/themes/theme.json +2 -1
- package/src/types/forms.tsx +1 -0
- package/src/types/index.tsx +8 -0
- package/src/types/logs.tsx +12 -0
- 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,
|
|
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(
|
|
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,
|
|
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,
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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);
|
|
226
|
+
console.log(e);
|
|
227
227
|
return false;
|
|
228
228
|
}
|
|
229
229
|
};
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
function
|
|
233
|
-
return (dispatch
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
239
|
-
Object.keys(userData).forEach((key: string) => {
|
|
240
|
-
userData[key] = "";
|
|
241
|
-
});
|
|
240
|
+
const callback = async () => users.resendInvitation(id);
|
|
242
241
|
|
|
243
|
-
|
|
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
|
|
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.
|
|
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);
|
|
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 };
|