@griddo/ax 10.1.69 → 10.1.71
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/config/jest/setup.js +14 -4
- package/package.json +5 -2
- package/public/img/logos/logoSQY.svg +3 -0
- package/public/img/slider/analytics.png +0 -0
- package/public/img/slider/content.png +0 -0
- package/public/img/slider/editor.png +0 -0
- package/public/img/slider/gallery.png +0 -0
- package/public/img/slider/left-on.svg +4 -0
- package/public/img/slider/left.svg +4 -0
- package/public/img/slider/right-on.svg +4 -0
- package/public/img/slider/right.svg +4 -0
- package/src/__tests__/components/Login/Login.test.tsx +5 -7
- package/src/api/integrations.tsx +18 -1
- package/src/components/Fields/CheckField/index.tsx +6 -12
- package/src/components/Fields/CheckField/style.tsx +16 -6
- package/src/components/Fields/NoteField/style.tsx +8 -8
- package/src/components/Fields/TextField/index.tsx +3 -1
- package/src/components/Fields/TextField/style.tsx +6 -1
- package/src/components/Fields/UniqueCheck/index.tsx +3 -1
- package/src/components/FieldsBehavior/index.tsx +4 -3
- package/src/components/FieldsBehavior/style.tsx +35 -22
- package/src/components/Login/Circle/index.tsx +16 -0
- package/src/components/Login/Circle/style.tsx +30 -0
- package/src/components/Login/LoginSlider/index.tsx +63 -0
- package/src/components/Login/LoginSlider/style.tsx +68 -0
- package/src/components/Login/index.tsx +102 -58
- package/src/components/Login/style.tsx +121 -16
- package/src/components/MainWrapper/AppBar/index.tsx +5 -1
- package/src/components/MainWrapper/AppBar/style.tsx +17 -1
- package/src/components/MainWrapper/index.tsx +3 -1
- package/src/components/MainWrapper/style.tsx +35 -4
- package/src/components/TableList/index.tsx +3 -5
- package/src/containers/App/actions.tsx +23 -7
- package/src/containers/App/constants.tsx +2 -0
- package/src/containers/App/interfaces.tsx +6 -0
- package/src/containers/App/reducer.tsx +4 -0
- package/src/containers/Integrations/actions.tsx +32 -2
- package/src/modules/Login/index.tsx +16 -3
- package/src/modules/Settings/Integrations/BulkHeader/TableHeader/index.tsx +1 -1
- package/src/modules/Settings/Integrations/BulkHeader/TableHeader/style.tsx +2 -2
- package/src/modules/Settings/Integrations/IntegrationForm/index.tsx +2 -1
- package/src/modules/Settings/Integrations/IntegrationItem/index.tsx +27 -13
- package/src/modules/Settings/Integrations/IntegrationItem/style.tsx +32 -5
- package/src/modules/Settings/Integrations/index.tsx +114 -81
- package/src/modules/Settings/Integrations/style.tsx +20 -1
- package/src/modules/Sites/SitesList/index.tsx +18 -3
- package/src/modules/Sites/SitesList/style.tsx +28 -1
- package/src/modules/Sites/index.tsx +4 -1
- package/src/themes/theme.json +4 -0
- package/src/types/index.tsx +2 -0
|
@@ -12,6 +12,7 @@ const SET_GLOBAL_LANGUAGES = `${NAME}/SET_GLOBAL_LANGUAGES`;
|
|
|
12
12
|
const SET_GLOBAL_SETTINGS = `${NAME}/SET_GLOBAL_SETTINGS`;
|
|
13
13
|
const SET_USER = `${NAME}/SET_USER`;
|
|
14
14
|
const SET_SESSION_STARTED_AT = `${NAME}/SET_SESSION_STARTED_AT`;
|
|
15
|
+
const SET_HAS_ANIMATION = `${NAME}/SET_HAS_ANIMATION`;
|
|
15
16
|
|
|
16
17
|
export {
|
|
17
18
|
SET_ERROR,
|
|
@@ -26,4 +27,5 @@ export {
|
|
|
26
27
|
SET_GLOBAL_SETTINGS,
|
|
27
28
|
SET_USER,
|
|
28
29
|
SET_SESSION_STARTED_AT,
|
|
30
|
+
SET_HAS_ANIMATION,
|
|
29
31
|
};
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
SET_GLOBAL_SETTINGS,
|
|
11
11
|
SET_USER,
|
|
12
12
|
SET_SESSION_STARTED_AT,
|
|
13
|
+
SET_HAS_ANIMATION,
|
|
13
14
|
} from "./constants";
|
|
14
15
|
import { IUser } from "./reducer";
|
|
15
16
|
|
|
@@ -70,6 +71,11 @@ export interface ISetSessionStartedAtAction {
|
|
|
70
71
|
payload: { sessionStartedAt: null | Date };
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
export interface ISetHasAnimation {
|
|
75
|
+
type: typeof SET_HAS_ANIMATION;
|
|
76
|
+
payload: { hasAnimation: boolean };
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
export type AppActionsCreators = ISetIsLoading & ISetIsSaving;
|
|
74
80
|
|
|
75
81
|
export type AuthActionsCreators = ISetTokenAction &
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
SET_GLOBAL_SETTINGS,
|
|
13
13
|
SET_USER,
|
|
14
14
|
SET_SESSION_STARTED_AT,
|
|
15
|
+
SET_HAS_ANIMATION,
|
|
15
16
|
} from "./constants";
|
|
16
17
|
|
|
17
18
|
export interface IAppState {
|
|
@@ -26,6 +27,7 @@ export interface IAppState {
|
|
|
26
27
|
globalLangs: any;
|
|
27
28
|
globalSettings: IGlobalSettings;
|
|
28
29
|
sessionStartedAt: null | Date;
|
|
30
|
+
hasAnimation: boolean;
|
|
29
31
|
}
|
|
30
32
|
export interface IError {
|
|
31
33
|
code?: any;
|
|
@@ -83,6 +85,7 @@ export const initialState = {
|
|
|
83
85
|
autoTranslation: false,
|
|
84
86
|
},
|
|
85
87
|
sessionStartedAt: null,
|
|
88
|
+
hasAnimation: false,
|
|
86
89
|
};
|
|
87
90
|
|
|
88
91
|
export function reducer(state = initialState, action: any): IAppState {
|
|
@@ -99,6 +102,7 @@ export function reducer(state = initialState, action: any): IAppState {
|
|
|
99
102
|
case SET_GLOBAL_SETTINGS:
|
|
100
103
|
case SET_USER:
|
|
101
104
|
case SET_SESSION_STARTED_AT:
|
|
105
|
+
case SET_HAS_ANIMATION:
|
|
102
106
|
return { ...state, ...action.payload };
|
|
103
107
|
case SET_ERROR:
|
|
104
108
|
case RESET_ERROR:
|
|
@@ -31,7 +31,7 @@ function setCopyIntegration(
|
|
|
31
31
|
return { type: SET_COPY_INTEGRATION, payload: { integrationCopy } };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function getIntegrations(site: number, params?: any,
|
|
34
|
+
function getIntegrations(site: number, params?: any, skipLoading?: boolean): (dispatch: Dispatch) => Promise<void> {
|
|
35
35
|
return async (dispatch) => {
|
|
36
36
|
try {
|
|
37
37
|
const callback = async () => integrations.getIntegrations(site, params);
|
|
@@ -43,7 +43,7 @@ function getIntegrations(site: number, params?: any, isPage?: boolean): (dispatc
|
|
|
43
43
|
},
|
|
44
44
|
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
45
45
|
};
|
|
46
|
-
await handleRequest(callback, responseActions,
|
|
46
|
+
await handleRequest(callback, responseActions, skipLoading ? [] : [appActions.setIsLoading])(dispatch);
|
|
47
47
|
} catch (e) {
|
|
48
48
|
console.log(e);
|
|
49
49
|
}
|
|
@@ -177,6 +177,35 @@ function copyIntegration(integration: Partial<IIntegration>): (dispatch: Dispatc
|
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
function orderIntegration(
|
|
181
|
+
id: number,
|
|
182
|
+
newOrder: number,
|
|
183
|
+
currentParams?: any
|
|
184
|
+
): (dispatch: Dispatch, getState: any) => Promise<boolean> {
|
|
185
|
+
return async (dispatch, getState) => {
|
|
186
|
+
try {
|
|
187
|
+
const {
|
|
188
|
+
sites: { currentSiteInfo },
|
|
189
|
+
} = getState();
|
|
190
|
+
|
|
191
|
+
dispatch(appActions.setIsLoading(true));
|
|
192
|
+
|
|
193
|
+
const callback = async () => integrations.orderIntegration(id, newOrder);
|
|
194
|
+
const responseActions = {
|
|
195
|
+
handleSuccess: () => {
|
|
196
|
+
const params = { ...DEFAULT_PARAMS, ...currentParams };
|
|
197
|
+
getIntegrations(currentSiteInfo.id, params)(dispatch);
|
|
198
|
+
},
|
|
199
|
+
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
200
|
+
};
|
|
201
|
+
return await handleRequest(callback, responseActions, [])(dispatch);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
console.log(e);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
180
209
|
export {
|
|
181
210
|
getIntegrations,
|
|
182
211
|
resetIntegrations,
|
|
@@ -187,4 +216,5 @@ export {
|
|
|
187
216
|
updateIntegration,
|
|
188
217
|
setCurrentIntegration,
|
|
189
218
|
copyIntegration,
|
|
219
|
+
orderIntegration,
|
|
190
220
|
};
|
|
@@ -7,7 +7,7 @@ import { Login } from "@ax/components";
|
|
|
7
7
|
import { IGlobalSettings } from "@ax/containers/App/reducer";
|
|
8
8
|
|
|
9
9
|
const LoginModule = (props: IProps) => {
|
|
10
|
-
const { isLoggingIn, globalSettings, login, resetError, getGlobalSettings } = props;
|
|
10
|
+
const { isLoggingIn, globalSettings, login, resetError, getGlobalSettings, setHistoryPush } = props;
|
|
11
11
|
|
|
12
12
|
const initState = {
|
|
13
13
|
email: "",
|
|
@@ -16,6 +16,7 @@ const LoginModule = (props: IProps) => {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const [state, setState] = useState(initState);
|
|
19
|
+
const [isSuccess, setIsSuccess] = useState(false);
|
|
19
20
|
|
|
20
21
|
useEffect(() => {
|
|
21
22
|
const prefix = process.env.REACT_APP_SITE_TITLE ? process.env.REACT_APP_SITE_TITLE : "";
|
|
@@ -28,7 +29,10 @@ const LoginModule = (props: IProps) => {
|
|
|
28
29
|
|
|
29
30
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
30
31
|
e.preventDefault();
|
|
31
|
-
await login(state.email, state.password, state.rememberMe);
|
|
32
|
+
const isLogged = await login(state.email, state.password, state.rememberMe);
|
|
33
|
+
if(isLogged){
|
|
34
|
+
setIsSuccess(true);
|
|
35
|
+
}
|
|
32
36
|
};
|
|
33
37
|
|
|
34
38
|
const _handleEmail = (email: string) => {
|
|
@@ -41,6 +45,11 @@ const LoginModule = (props: IProps) => {
|
|
|
41
45
|
setState({ ...state, password });
|
|
42
46
|
};
|
|
43
47
|
|
|
48
|
+
const handleLoginSuccess = () => {
|
|
49
|
+
const welcomePageURI = "/sites";
|
|
50
|
+
setHistoryPush(welcomePageURI);
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
const _handleRememberMe = () => setState({ ...state, rememberMe: !state.rememberMe });
|
|
45
54
|
|
|
46
55
|
return (
|
|
@@ -54,6 +63,8 @@ const LoginModule = (props: IProps) => {
|
|
|
54
63
|
settings={globalSettings}
|
|
55
64
|
rememberMe={state.rememberMe}
|
|
56
65
|
handleRememberMe={_handleRememberMe}
|
|
66
|
+
isLoginSuccess={isSuccess}
|
|
67
|
+
handleLoginSuccess={handleLoginSuccess}
|
|
57
68
|
/>
|
|
58
69
|
);
|
|
59
70
|
};
|
|
@@ -63,15 +74,17 @@ interface IProps {
|
|
|
63
74
|
isLoggingIn: boolean;
|
|
64
75
|
children: any;
|
|
65
76
|
globalSettings: IGlobalSettings;
|
|
66
|
-
login(email: string, password: string, rememberMe: boolean): Promise<
|
|
77
|
+
login(email: string, password: string, rememberMe: boolean): Promise<boolean>;
|
|
67
78
|
resetError(): void;
|
|
68
79
|
getGlobalSettings(): void;
|
|
80
|
+
setHistoryPush(path: string): Promise<void>
|
|
69
81
|
}
|
|
70
82
|
|
|
71
83
|
const mapDispatchToProps = {
|
|
72
84
|
login: appActions.login,
|
|
73
85
|
resetError: appActions.resetError,
|
|
74
86
|
getGlobalSettings: appActions.getGlobalSettings,
|
|
87
|
+
setHistoryPush: appActions.setHistoryPush,
|
|
75
88
|
};
|
|
76
89
|
|
|
77
90
|
const mapStateToProps = (state: IRootState) => ({
|
|
@@ -45,7 +45,7 @@ const TableHeader = (props: IProps): JSX.Element => {
|
|
|
45
45
|
/>
|
|
46
46
|
</S.CheckHeader>
|
|
47
47
|
<S.NameHeader>
|
|
48
|
-
|
|
48
|
+
Name
|
|
49
49
|
</S.NameHeader>
|
|
50
50
|
<S.DescriptionHeader></S.DescriptionHeader>
|
|
51
51
|
<S.AppliedOnHeader>
|
|
@@ -30,6 +30,7 @@ const IntegrationForm = (props: IProps) => {
|
|
|
30
30
|
contentPresence: { presenceType: "all", relatedPages: [] },
|
|
31
31
|
active: true,
|
|
32
32
|
variables: [],
|
|
33
|
+
scriptOrder: 0,
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
const [form, setForm] = useState<IIntegration>(initState);
|
|
@@ -222,7 +223,7 @@ const IntegrationForm = (props: IProps) => {
|
|
|
222
223
|
value={form.contentBodyPosition}
|
|
223
224
|
options={bodyOptions}
|
|
224
225
|
onChange={handleContentBodyPositionChange}
|
|
225
|
-
disabled={!form.contentBody.trim().length}
|
|
226
|
+
disabled={!form.contentBody || !form.contentBody.trim().length}
|
|
226
227
|
/>
|
|
227
228
|
<FieldsBehavior
|
|
228
229
|
title="Add code to:"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
+
import { DraggableProvided } from "react-beautiful-dnd";
|
|
3
4
|
|
|
4
|
-
import { ICheck, IIntegration
|
|
5
|
-
import { CheckField, Modal, Toast, ToggleField } from "@ax/components";
|
|
5
|
+
import { ICheck, IIntegration } from "@ax/types";
|
|
6
|
+
import { CheckField, Icon, Modal, Toast, ToggleField } from "@ax/components";
|
|
6
7
|
import { useModal, useToast } from "@ax/hooks";
|
|
7
8
|
import { integrations } from "@ax/api";
|
|
8
9
|
import { integrationsActions } from "@ax/containers/Integrations";
|
|
@@ -21,6 +22,9 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
|
|
|
21
22
|
getParams,
|
|
22
23
|
changeState,
|
|
23
24
|
toggleToastChange,
|
|
25
|
+
innerRef,
|
|
26
|
+
provided,
|
|
27
|
+
listLength,
|
|
24
28
|
} = props;
|
|
25
29
|
|
|
26
30
|
const { isOpen: isOpenDelete, toggleModal: toggleModalDelete } = useModal();
|
|
@@ -113,12 +117,24 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
|
|
|
113
117
|
|
|
114
118
|
return (
|
|
115
119
|
<>
|
|
116
|
-
<S.ItemRow
|
|
117
|
-
|
|
120
|
+
<S.ItemRow
|
|
121
|
+
role="rowgroup"
|
|
122
|
+
selected={isSelected}
|
|
123
|
+
ref={innerRef}
|
|
124
|
+
data-testid="integration-item-row"
|
|
125
|
+
{...provided?.draggableProps}
|
|
126
|
+
>
|
|
127
|
+
<S.HandleWrapper {...provided?.dragHandleProps} hidden={listLength < 2} data-testid="handle-wrapper">
|
|
128
|
+
<S.IconHandleWrapper>
|
|
129
|
+
<Icon name="drag" size="16" />
|
|
130
|
+
</S.IconHandleWrapper>
|
|
131
|
+
</S.HandleWrapper>
|
|
132
|
+
<S.CheckCell role="cell" hasHandle={listLength >= 2}>
|
|
118
133
|
<CheckField name="check" value={integration.id ?? ""} checked={isSelected} onChange={handleOnChange} />
|
|
119
134
|
</S.CheckCell>
|
|
120
135
|
<S.NameCell role="cell" onClick={handleClick}>
|
|
121
|
-
{integration.
|
|
136
|
+
<S.Order>#{integration.correlativeScriptOrder}</S.Order>
|
|
137
|
+
<div>{integration.name}</div>
|
|
122
138
|
</S.NameCell>
|
|
123
139
|
<S.DescriptionCell role="cell" onClick={handleClick}>
|
|
124
140
|
{integration.description}
|
|
@@ -156,8 +172,8 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
|
|
|
156
172
|
>
|
|
157
173
|
<S.ModalContent>
|
|
158
174
|
Are you sure you want to {integration.active ? "disable" : "enable"}{" "}
|
|
159
|
-
<strong>{integration.name} add-on</strong>? This add-on will {integration.active ? "stop" : "start"}
|
|
160
|
-
|
|
175
|
+
<strong>{integration.name} add-on</strong>? This add-on will {integration.active ? "stop" : "start"} working
|
|
176
|
+
in the pages previously added.
|
|
161
177
|
</S.ModalContent>
|
|
162
178
|
</Modal>
|
|
163
179
|
<CopyModal isOpen={isOpenCopy} hide={toggleModalCopy} action={copyIntegration} />
|
|
@@ -175,13 +191,11 @@ interface IProps {
|
|
|
175
191
|
getParams: () => any;
|
|
176
192
|
changeState: (integrationId: number, active: boolean, params: any) => Promise<boolean>;
|
|
177
193
|
toggleToastChange: (state: { total: number; active: boolean }) => void;
|
|
178
|
-
|
|
194
|
+
innerRef: any;
|
|
195
|
+
provided: DraggableProvided;
|
|
196
|
+
listLength: number;
|
|
179
197
|
}
|
|
180
198
|
|
|
181
|
-
const mapStateToProps = (state: IRootState) => ({
|
|
182
|
-
currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
|
|
183
|
-
});
|
|
184
|
-
|
|
185
199
|
const mapDispatchToProps = {
|
|
186
200
|
setHistoryPush: appActions.setHistoryPush,
|
|
187
201
|
setCurrentIntegration: integrationsActions.setCurrentIntegration,
|
|
@@ -194,4 +208,4 @@ interface IDispatchProps {
|
|
|
194
208
|
|
|
195
209
|
export type IIntegrationItemProps = IProps & IDispatchProps;
|
|
196
210
|
|
|
197
|
-
export default connect(
|
|
211
|
+
export default connect(null, mapDispatchToProps)(IntegrationItem);
|
|
@@ -3,18 +3,26 @@ import styled from "styled-components";
|
|
|
3
3
|
import { Cell, Row } from "@ax/components/TableList/TableItem/style";
|
|
4
4
|
import { ActionMenu } from "@ax/components";
|
|
5
5
|
|
|
6
|
-
const CheckCell = styled(Cell)
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const CheckCell = styled(Cell)<{ hasHandle: boolean }>`
|
|
7
|
+
width: 24px;
|
|
8
|
+
padding: ${(p) => p.hasHandle ? `${p.theme.spacing.s} ${p.theme.spacing.xs}`: `0 ${p.theme.spacing.s} 0 ${p.theme.spacing.m}`};
|
|
9
9
|
label {
|
|
10
|
-
margin-bottom:
|
|
10
|
+
margin-bottom: 18px;
|
|
11
11
|
}
|
|
12
12
|
`;
|
|
13
13
|
|
|
14
14
|
const NameCell = styled(Cell)`
|
|
15
15
|
${(p) => p.theme.textStyle.uiM};
|
|
16
16
|
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
17
|
-
width:
|
|
17
|
+
width: 350px;
|
|
18
|
+
flex-flow: row wrap;
|
|
19
|
+
justify-content: flex-start;
|
|
20
|
+
align-items: center;
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const Order = styled.div`
|
|
24
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
25
|
+
margin-right: ${(p) => p.theme.spacing.xxs};
|
|
18
26
|
`;
|
|
19
27
|
|
|
20
28
|
const DescriptionCell = styled(Cell)`
|
|
@@ -67,6 +75,22 @@ const ItemRow = styled(Row)`
|
|
|
67
75
|
}
|
|
68
76
|
`;
|
|
69
77
|
|
|
78
|
+
const HandleWrapper = styled.div<{ hidden?: boolean }>`
|
|
79
|
+
padding-left: ${(p) => p.theme.spacing.xs};
|
|
80
|
+
display: ${(p) => (p.hidden ? "none" : "flex")};
|
|
81
|
+
align-items: center;
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
const IconHandleWrapper = styled.div`
|
|
85
|
+
width: ${(p) => p.theme.spacing.s};
|
|
86
|
+
height: ${(p) => p.theme.spacing.s};
|
|
87
|
+
svg {
|
|
88
|
+
path {
|
|
89
|
+
fill: ${(p) => p.theme.color.textLowEmphasis};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
|
|
70
94
|
export {
|
|
71
95
|
CheckCell,
|
|
72
96
|
NameCell,
|
|
@@ -78,4 +102,7 @@ export {
|
|
|
78
102
|
ContentPresence,
|
|
79
103
|
ModalContent,
|
|
80
104
|
StyledActionMenu,
|
|
105
|
+
HandleWrapper,
|
|
106
|
+
IconHandleWrapper,
|
|
107
|
+
Order,
|
|
81
108
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
+
import { DragDropContext, Droppable, Draggable, DropResult } from "react-beautiful-dnd";
|
|
3
4
|
|
|
4
5
|
import { IEmptyStateProps, IIntegration, IRootState } from "@ax/types";
|
|
5
6
|
import { MainWrapper, ErrorToast, TableList, EmptyState, Toast } from "@ax/components";
|
|
@@ -12,10 +13,8 @@ import IntegrationItem from "./IntegrationItem";
|
|
|
12
13
|
import { useFilterQuery, useSortedListStatus } from "./hooks";
|
|
13
14
|
import { getSortedListStatus } from "./utils";
|
|
14
15
|
import { DeactivateModal, DeleteModal } from "./atoms";
|
|
15
|
-
import * as S from "./style";
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
const firstPage = 1;
|
|
17
|
+
import * as S from "./style";
|
|
19
18
|
|
|
20
19
|
const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
21
20
|
const {
|
|
@@ -29,9 +28,13 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
29
28
|
changeIntegrationState,
|
|
30
29
|
setHistoryPush,
|
|
31
30
|
setCurrentIntegration,
|
|
31
|
+
orderIntegration,
|
|
32
32
|
} = props;
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
if (!currentSite) {
|
|
35
|
+
throw new Error(`ERROR: User reached Integrations with null site info`);
|
|
36
|
+
}
|
|
37
|
+
|
|
35
38
|
const [isScrolling, setIsScrolling] = useState(false);
|
|
36
39
|
const tableRef = useRef<HTMLDivElement>(null);
|
|
37
40
|
const [currentFilterQuery, setCurrentFilterQuery] = useState("");
|
|
@@ -64,14 +67,12 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
64
67
|
|
|
65
68
|
const getParams = useCallback(() => {
|
|
66
69
|
const params = {
|
|
67
|
-
|
|
68
|
-
itemsPerPage,
|
|
69
|
-
pagination: true,
|
|
70
|
+
pagination: false,
|
|
70
71
|
filter: currentFilterQuery,
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
return params;
|
|
74
|
-
}, [
|
|
75
|
+
}, [currentFilterQuery]);
|
|
75
76
|
|
|
76
77
|
useEffect(() => {
|
|
77
78
|
const params = getParams();
|
|
@@ -82,7 +83,7 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
82
83
|
resetIntegrations();
|
|
83
84
|
};
|
|
84
85
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
85
|
-
}, [
|
|
86
|
+
}, [currentSite, currentFilterQuery]);
|
|
86
87
|
|
|
87
88
|
const {
|
|
88
89
|
resetBulkSelection,
|
|
@@ -121,7 +122,6 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
121
122
|
const handleSelectAll = () => selectAllItems();
|
|
122
123
|
|
|
123
124
|
const sortItems = async (orderPointer: string, isAscending: boolean) => {
|
|
124
|
-
setPage(firstPage);
|
|
125
125
|
const sortedState = getSortedListStatus(orderPointer, isAscending);
|
|
126
126
|
setSortedListStatus(sortedState);
|
|
127
127
|
|
|
@@ -131,7 +131,6 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
const filterItems = async (filterPointer: string, filtersSelected: string) => {
|
|
134
|
-
setPage(firstPage);
|
|
135
134
|
const filtersSelection = setFiltersSelection(filterPointer, filtersSelected);
|
|
136
135
|
const filterQuery = setFilterQuery(filtersSelection);
|
|
137
136
|
setCurrentFilterQuery(filterQuery);
|
|
@@ -156,11 +155,22 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
156
155
|
|
|
157
156
|
const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
|
|
158
157
|
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
const onDragEnd = (result: DropResult) => {
|
|
159
|
+
if (!result.destination) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (result.destination.index === result.source.index) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const newScriptOrder = result.destination.index
|
|
168
|
+
? integrations[result.destination.index - (result.destination.index > result.source.index ? 0 : 1)].scriptOrder +
|
|
169
|
+
1
|
|
170
|
+
: 1;
|
|
171
|
+
|
|
172
|
+
const params = getParams();
|
|
173
|
+
orderIntegration(parseInt(result.draggableId), newScriptOrder, params);
|
|
164
174
|
};
|
|
165
175
|
|
|
166
176
|
const mainDeleteModalAction = {
|
|
@@ -192,70 +202,91 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
|
|
|
192
202
|
action: () => setHistoryPush(`/sites/settings/addons/new`),
|
|
193
203
|
};
|
|
194
204
|
|
|
205
|
+
const ComponentList = React.memo(function ComponentList({ components }: any) {
|
|
206
|
+
return components.map((integration: IIntegration, index: number) => {
|
|
207
|
+
const isItemSelected = isSelected(integration.id);
|
|
208
|
+
return (
|
|
209
|
+
<Draggable draggableId={`${integration.id}`} index={index} key={integration.id}>
|
|
210
|
+
{(provided) => (
|
|
211
|
+
<IntegrationItem
|
|
212
|
+
key={`${integration.name}${integration.id}`}
|
|
213
|
+
integration={integration}
|
|
214
|
+
isSelected={isItemSelected}
|
|
215
|
+
onChange={addToBulkSelection}
|
|
216
|
+
toggleToastDelete={toggleToastDelete}
|
|
217
|
+
getParams={getParams}
|
|
218
|
+
deleteIntegration={deleteIntegration}
|
|
219
|
+
changeState={changeIntegrationState}
|
|
220
|
+
toggleToastChange={toggleToastChange}
|
|
221
|
+
innerRef={provided.innerRef}
|
|
222
|
+
provided={provided}
|
|
223
|
+
listLength={integrations.length}
|
|
224
|
+
/>
|
|
225
|
+
)}
|
|
226
|
+
</Draggable>
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
195
231
|
return (
|
|
196
|
-
|
|
197
|
-
<
|
|
198
|
-
<S.
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
<S.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
integrations={integrations}
|
|
255
|
-
selectedIds={selectedItems.all}
|
|
256
|
-
/>
|
|
257
|
-
</MainWrapper>
|
|
258
|
-
</>
|
|
232
|
+
<MainWrapper backLink={false} title="Add-ons" rightButton={rightButtonProps}>
|
|
233
|
+
<S.Wrapper data-testid="integrations-main-wrapper">
|
|
234
|
+
<S.ContentWrapper>
|
|
235
|
+
<ErrorToast />
|
|
236
|
+
<S.TitleWrapper>
|
|
237
|
+
<S.Title>Custom Code</S.Title>
|
|
238
|
+
<S.Description>Add custom code to the head or body of your site's pages.</S.Description>
|
|
239
|
+
</S.TitleWrapper>
|
|
240
|
+
<S.TableWrapper>
|
|
241
|
+
<TableList tableHeader={TableHeader} onScroll={onScroll} hasFixedHeader={true} tableRef={tableRef}>
|
|
242
|
+
{isEmpty ? (
|
|
243
|
+
<S.EmptyWrapper>
|
|
244
|
+
<EmptyState {...emptyStateProps} />
|
|
245
|
+
</S.EmptyWrapper>
|
|
246
|
+
) : (
|
|
247
|
+
<>
|
|
248
|
+
{integrations.length >= 2 && (
|
|
249
|
+
<S.OrderNote>
|
|
250
|
+
You can easily <strong>reorder</strong> the list using <strong>drag and drop</strong>. The order{" "}
|
|
251
|
+
<strong>determines the priority of the add-on</strong>, and the code appears on the page
|
|
252
|
+
accordingly.
|
|
253
|
+
</S.OrderNote>
|
|
254
|
+
)}
|
|
255
|
+
<DragDropContext onDragEnd={onDragEnd}>
|
|
256
|
+
<Droppable droppableId="integrationsList">
|
|
257
|
+
{(provided) => (
|
|
258
|
+
<div ref={provided.innerRef} {...provided.droppableProps} data-testid="droppable">
|
|
259
|
+
<ComponentList components={integrations} />
|
|
260
|
+
{provided.placeholder}
|
|
261
|
+
</div>
|
|
262
|
+
)}
|
|
263
|
+
</Droppable>
|
|
264
|
+
</DragDropContext>
|
|
265
|
+
</>
|
|
266
|
+
)}
|
|
267
|
+
</TableList>
|
|
268
|
+
</S.TableWrapper>
|
|
269
|
+
{isVisibleDelete && <Toast {...deletedToastProps} />}
|
|
270
|
+
{isVisibleChange && <Toast {...changedToastProps} />}
|
|
271
|
+
</S.ContentWrapper>
|
|
272
|
+
</S.Wrapper>
|
|
273
|
+
<DeleteModal
|
|
274
|
+
isOpen={isOpenDelete}
|
|
275
|
+
toggleModal={toggleModalDelete}
|
|
276
|
+
secondaryModalAction={secondaryDeleteModalAction}
|
|
277
|
+
mainModalAction={mainDeleteModalAction}
|
|
278
|
+
integrations={integrations}
|
|
279
|
+
selectedIds={selectedItems.all}
|
|
280
|
+
/>
|
|
281
|
+
<DeactivateModal
|
|
282
|
+
isOpen={isOpenDeactivate}
|
|
283
|
+
toggleModal={toggleModalDeactivate}
|
|
284
|
+
secondaryModalAction={secondaryDeactivateModalAction}
|
|
285
|
+
mainModalAction={mainDeactivateModalAction}
|
|
286
|
+
integrations={integrations}
|
|
287
|
+
selectedIds={selectedItems.all}
|
|
288
|
+
/>
|
|
289
|
+
</MainWrapper>
|
|
259
290
|
);
|
|
260
291
|
};
|
|
261
292
|
|
|
@@ -273,13 +304,14 @@ const mapDispatchToProps = {
|
|
|
273
304
|
changeIntegrationState: integrationsActions.changeIntegrationState,
|
|
274
305
|
setHistoryPush: appActions.setHistoryPush,
|
|
275
306
|
setCurrentIntegration: integrationsActions.setCurrentIntegration,
|
|
307
|
+
orderIntegration: integrationsActions.orderIntegration,
|
|
276
308
|
};
|
|
277
309
|
|
|
278
310
|
interface IStateProps {
|
|
279
311
|
isLoading: boolean;
|
|
280
312
|
integrations: IIntegration[];
|
|
281
313
|
totalItems: number;
|
|
282
|
-
currentSite: number;
|
|
314
|
+
currentSite: number | null;
|
|
283
315
|
}
|
|
284
316
|
|
|
285
317
|
interface IDispatchProps {
|
|
@@ -287,11 +319,12 @@ interface IDispatchProps {
|
|
|
287
319
|
resetIntegrations: () => void;
|
|
288
320
|
deleteIntegration: (
|
|
289
321
|
integrationId: number | number[],
|
|
290
|
-
currentParams: {
|
|
322
|
+
currentParams: { pagination: boolean; filter: any }
|
|
291
323
|
) => Promise<boolean>;
|
|
292
324
|
changeIntegrationState: (integrationId: number | number[], active: boolean, currentParams?: any) => Promise<boolean>;
|
|
293
325
|
setHistoryPush: (path: string) => void;
|
|
294
326
|
setCurrentIntegration: (integration: IIntegration | null) => void;
|
|
327
|
+
orderIntegration(id: number, newOrder: number, currentParams?: any): Promise<boolean>;
|
|
295
328
|
}
|
|
296
329
|
|
|
297
330
|
export type IIntegrationsProps = IStateProps & IDispatchProps;
|