@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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import styled, { keyframes } from "styled-components";
|
|
2
|
+
|
|
3
|
+
const PrevAnimation = keyframes`
|
|
4
|
+
to {
|
|
5
|
+
opacity: 0;
|
|
6
|
+
}
|
|
7
|
+
}`;
|
|
8
|
+
|
|
9
|
+
const Wrapper = styled.div`
|
|
10
|
+
position: relative;
|
|
11
|
+
bottom: 0;
|
|
12
|
+
|
|
13
|
+
.prev-slide-anim {
|
|
14
|
+
opacity: 1;
|
|
15
|
+
animation: ${PrevAnimation} 0.8s ease-out;
|
|
16
|
+
animation-fill-mode: forwards;
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
const BannerWrapper = styled.div`
|
|
21
|
+
position: relative;
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 100vh;
|
|
24
|
+
padding-left: 100px;
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const Title = styled.div`
|
|
28
|
+
color: ${(p) => p.theme.color.textHighEmphasisInverse};
|
|
29
|
+
font-family: Source Sans Pro;
|
|
30
|
+
font-size: 36px;
|
|
31
|
+
font-weight: 300;
|
|
32
|
+
line-height: 48px;
|
|
33
|
+
letter-spacing: 0px;
|
|
34
|
+
text-align: left;
|
|
35
|
+
padding-top: 140px;
|
|
36
|
+
width: 450px;
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const Image = styled.div<{ image: string }>`
|
|
40
|
+
background: no-repeat top left url(${(p) => p.image});
|
|
41
|
+
background-size: 130%;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
margin-top: ${(p) => p.theme.spacing.l};
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const Buttons = styled.div`
|
|
48
|
+
display: flex;
|
|
49
|
+
position: absolute;
|
|
50
|
+
left: 100px;
|
|
51
|
+
top: 64px;
|
|
52
|
+
z-index: 10;
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const Arrow = styled.div<{ direction: string }>`
|
|
56
|
+
background: ${(p) => `no-repeat url("/img/slider/${p.direction}.svg")`};
|
|
57
|
+
width: 40px;
|
|
58
|
+
height: 40px;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
&:last-child {
|
|
61
|
+
margin-left: ${(p) => p.theme.spacing.s};
|
|
62
|
+
}
|
|
63
|
+
&:hover {
|
|
64
|
+
background: ${(p) => `no-repeat url("/img/slider/${p.direction}-on.svg")`};
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
export { Wrapper, BannerWrapper, Title, Image, Buttons, Arrow };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { IGlobalSettings } from "@ax/containers/App/reducer";
|
|
4
4
|
import { useModal } from "@ax/hooks";
|
|
5
5
|
import { Button, FieldsBehavior, ErrorToast } from "@ax/components";
|
|
6
6
|
import RecoveryModal from "./RecoveryModal";
|
|
7
|
+
import Circle from "./Circle";
|
|
7
8
|
|
|
8
9
|
import * as S from "./style";
|
|
9
10
|
|
|
@@ -24,78 +25,119 @@ const Login = (props: ILoginProps): JSX.Element => {
|
|
|
24
25
|
settings,
|
|
25
26
|
rememberMe,
|
|
26
27
|
handleRememberMe,
|
|
28
|
+
isLoginSuccess,
|
|
29
|
+
handleLoginSuccess,
|
|
27
30
|
} = props;
|
|
28
31
|
|
|
29
32
|
const [viewPass, setViewPass] = useState(false);
|
|
33
|
+
const [wrapperWidth, setWrapperWidth] = useState<number>(0);
|
|
30
34
|
const { isOpen, toggleModal } = useModal();
|
|
35
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const handleResize = () => wrapperRef.current && setWrapperWidth(wrapperRef.current.clientWidth);
|
|
39
|
+
|
|
40
|
+
window.addEventListener("resize", handleResize, false);
|
|
41
|
+
|
|
42
|
+
if (wrapperRef.current) {
|
|
43
|
+
setWrapperWidth(wrapperRef.current.clientWidth);
|
|
44
|
+
}
|
|
45
|
+
}, [wrapperRef.current]);
|
|
46
|
+
|
|
31
47
|
window.handleErrorClick = toggleModal;
|
|
32
|
-
const _handleEmail = (e: string) => handleEmail(e);
|
|
33
48
|
|
|
34
|
-
const
|
|
35
|
-
const textName = settings.welcomeText2 ? settings.welcomeText2 : "";
|
|
49
|
+
const _handleEmail = (e: string) => handleEmail(e);
|
|
36
50
|
|
|
37
51
|
const _handlePwd = (e: string) => handlePassword(e);
|
|
38
|
-
const btnText = isLoggingIn ? "Sending" : "Log in";
|
|
39
52
|
|
|
40
53
|
const _togglePassword = () => setViewPass(!viewPass);
|
|
54
|
+
|
|
55
|
+
const _handleAnimationEnd = () => handleLoginSuccess();
|
|
56
|
+
|
|
57
|
+
const btnText = isLoggingIn ? "Sending" : "Login";
|
|
58
|
+
|
|
41
59
|
const inputType = viewPass ? "text" : "password";
|
|
42
60
|
const icon = viewPass ? "hide" : "view";
|
|
43
61
|
|
|
62
|
+
const textName = settings.welcomeText2 ? settings.welcomeText2 : "Griddo";
|
|
63
|
+
const nameLogo =
|
|
64
|
+
textName === "Griddo" ? <img src="/img/logos/logoGriddoExtended@3x.svg" alt="Griddo Logo" /> : textName;
|
|
65
|
+
|
|
44
66
|
return (
|
|
45
67
|
<S.Wrapper data-testid="login-wrapper">
|
|
46
|
-
<S.
|
|
47
|
-
<S.
|
|
48
|
-
<S.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
68
|
+
<S.LeftWrapper className={isLoginSuccess ? "animate" : ""} onAnimationEnd={_handleAnimationEnd} ref={wrapperRef}>
|
|
69
|
+
<S.LoginWrapper className={isLoginSuccess ? "animate" : ""} width={wrapperWidth}>
|
|
70
|
+
<S.Main>
|
|
71
|
+
<S.Header>
|
|
72
|
+
<S.Title>
|
|
73
|
+
<div>Welcome to</div>
|
|
74
|
+
<div>{nameLogo}</div>
|
|
75
|
+
</S.Title>
|
|
76
|
+
<S.Subtitle>To start using {textName}, introduce your email and password.</S.Subtitle>
|
|
77
|
+
</S.Header>
|
|
78
|
+
<ErrorToast />
|
|
79
|
+
<S.Form onSubmit={handleSubmit}>
|
|
80
|
+
<FieldsBehavior
|
|
81
|
+
fieldType="TextField"
|
|
82
|
+
title="Email"
|
|
83
|
+
autoComplete="email"
|
|
84
|
+
value={email}
|
|
85
|
+
onChange={_handleEmail}
|
|
86
|
+
name="email"
|
|
87
|
+
inversed={true}
|
|
88
|
+
placeholder="Type your email"
|
|
89
|
+
/>
|
|
90
|
+
<FieldsBehavior
|
|
91
|
+
fieldType="TextField"
|
|
92
|
+
title="Password"
|
|
93
|
+
inputType={inputType}
|
|
94
|
+
value={password}
|
|
95
|
+
onChange={_handlePwd}
|
|
96
|
+
autoComplete="current-password"
|
|
97
|
+
icon={icon}
|
|
98
|
+
onClickIcon={_togglePassword}
|
|
99
|
+
iconPosition="in"
|
|
100
|
+
name="password"
|
|
101
|
+
inversed={true}
|
|
102
|
+
/>
|
|
103
|
+
<S.Actions>
|
|
104
|
+
<FieldsBehavior
|
|
105
|
+
fieldType="UniqueCheck"
|
|
106
|
+
title=""
|
|
107
|
+
value={rememberMe}
|
|
108
|
+
onChange={handleRememberMe}
|
|
109
|
+
options={[{ title: "Remember me" }]}
|
|
110
|
+
name="rememberMe"
|
|
111
|
+
inversed={true}
|
|
112
|
+
/>
|
|
113
|
+
<S.Password>
|
|
114
|
+
<span
|
|
115
|
+
onClick={toggleModal}
|
|
116
|
+
role="checkbox"
|
|
117
|
+
aria-checked="false"
|
|
118
|
+
tabIndex={0}
|
|
119
|
+
data-testid="forgot-button"
|
|
120
|
+
>
|
|
121
|
+
Lost your password?
|
|
122
|
+
</span>
|
|
123
|
+
</S.Password>
|
|
124
|
+
</S.Actions>
|
|
125
|
+
<Button type="submit" disabled={isLoggingIn ? true : false}>
|
|
126
|
+
{btnText}
|
|
127
|
+
</Button>
|
|
128
|
+
<RecoveryModal isOpen={isOpen} toggleModal={toggleModal} />
|
|
129
|
+
</S.Form>
|
|
130
|
+
</S.Main>
|
|
131
|
+
<S.Secuoyas width={wrapperWidth}>
|
|
132
|
+
Made with care at <img src="/img/logos/logoSQY.svg" alt="Secuoyas logo" />
|
|
133
|
+
</S.Secuoyas>
|
|
134
|
+
</S.LoginWrapper>
|
|
135
|
+
</S.LeftWrapper>
|
|
136
|
+
<S.RightWrapper>
|
|
137
|
+
<Circle animation={1} />
|
|
138
|
+
<Circle animation={2} />
|
|
139
|
+
<S.AnimatedLoginSlider className={isLoginSuccess ? "animate" : ""} />
|
|
140
|
+
</S.RightWrapper>
|
|
99
141
|
</S.Wrapper>
|
|
100
142
|
);
|
|
101
143
|
};
|
|
@@ -110,6 +152,8 @@ export interface ILoginProps {
|
|
|
110
152
|
settings: IGlobalSettings;
|
|
111
153
|
rememberMe: boolean;
|
|
112
154
|
handleRememberMe: () => void;
|
|
155
|
+
isLoginSuccess: boolean;
|
|
156
|
+
handleLoginSuccess: () => void;
|
|
113
157
|
}
|
|
114
158
|
|
|
115
159
|
export default Login;
|
|
@@ -1,33 +1,103 @@
|
|
|
1
|
-
import styled from "styled-components";
|
|
1
|
+
import styled, { keyframes } from "styled-components";
|
|
2
|
+
import LoginSlider from "./LoginSlider";
|
|
2
3
|
|
|
3
4
|
const Wrapper = styled.section`
|
|
5
|
+
position: relative;
|
|
6
|
+
display: flex;
|
|
4
7
|
height: 100vh;
|
|
5
|
-
|
|
8
|
+
background: ${(p) => p.theme.color.uiBackground04};
|
|
9
|
+
flex-direction: row;
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
const LoginAnimation = keyframes`
|
|
13
|
+
to {
|
|
14
|
+
width: 100%;
|
|
15
|
+
}
|
|
16
|
+
}`;
|
|
17
|
+
|
|
18
|
+
const OpacityAnimation = keyframes`
|
|
19
|
+
to {
|
|
20
|
+
opacity: 0;
|
|
21
|
+
}
|
|
22
|
+
}`;
|
|
23
|
+
|
|
24
|
+
const LeftWrapper = styled.div`
|
|
25
|
+
position: relative;
|
|
26
|
+
display: flex;
|
|
27
|
+
width: 45%;
|
|
28
|
+
background: ${(p) => p.theme.color.uiBackground04};
|
|
29
|
+
|
|
30
|
+
&.animate {
|
|
31
|
+
position: absolute;
|
|
32
|
+
top: 0;
|
|
33
|
+
left: 0;
|
|
34
|
+
bottom: 0;
|
|
35
|
+
z-index: 2;
|
|
36
|
+
animation: ${LoginAnimation} 1.2s ease-in;
|
|
37
|
+
animation-fill-mode: forwards;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const LoginWrapper = styled.div<{ width: number }>`
|
|
42
|
+
width: ${(p) => p.width > 0 ? `${p.width}px` : "100%"};
|
|
6
43
|
display: flex;
|
|
7
44
|
align-items: center;
|
|
8
45
|
justify-content: center;
|
|
9
|
-
|
|
46
|
+
|
|
47
|
+
&.animate {
|
|
48
|
+
opacity: 1;
|
|
49
|
+
margin-right: auto;
|
|
50
|
+
animation: ${OpacityAnimation} 1.2s ease-in;
|
|
51
|
+
animation-fill-mode: forwards;
|
|
52
|
+
}
|
|
10
53
|
`;
|
|
11
54
|
|
|
12
|
-
const
|
|
13
|
-
|
|
55
|
+
const RightWrapper = styled.div`
|
|
56
|
+
background-color: #001B3C;
|
|
57
|
+
position: relative;
|
|
58
|
+
width: 55%;
|
|
59
|
+
height: 100%;
|
|
60
|
+
color: ${(p) => p.theme.color.textHighEmphasisInverse};
|
|
61
|
+
margin-left: auto;
|
|
62
|
+
z-index: 1;
|
|
63
|
+
overflow: hidden;
|
|
14
64
|
`;
|
|
15
65
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
66
|
+
const AnimatedLoginSlider = styled(LoginSlider)`
|
|
67
|
+
&.animate {
|
|
68
|
+
opacity: 1;
|
|
69
|
+
animation: ${OpacityAnimation} 1.2s ease-in;
|
|
70
|
+
animation-fill-mode: forwards;
|
|
71
|
+
}
|
|
20
72
|
`;
|
|
21
73
|
|
|
74
|
+
const Main = styled.div`
|
|
75
|
+
width: 368px;
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const Header = styled.header``;
|
|
79
|
+
|
|
22
80
|
const Subtitle = styled.p`
|
|
23
|
-
${(p) => p.theme.textStyle.
|
|
24
|
-
color: ${(p) => p.theme.color.
|
|
81
|
+
${(p) => p.theme.textStyle.uiM};
|
|
82
|
+
color: ${(p) => p.theme.color.textMediumEmphasisInverse};
|
|
25
83
|
font-weight: normal;
|
|
26
84
|
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
85
|
+
width: 280px;
|
|
27
86
|
`;
|
|
28
87
|
|
|
29
|
-
const Title = styled.
|
|
88
|
+
const Title = styled.div`
|
|
30
89
|
${(p) => p.theme.textStyle.headingM};
|
|
90
|
+
color: ${(p) => p.theme.color.textHighEmphasisInverse};
|
|
91
|
+
display: flex;
|
|
92
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
93
|
+
align-items: center;
|
|
94
|
+
div:last-child {
|
|
95
|
+
margin-left: ${(p) => p.theme.spacing.xxs};
|
|
96
|
+
}
|
|
97
|
+
img {
|
|
98
|
+
height: 24px;
|
|
99
|
+
margin-top: ${(p) => p.theme.spacing.xxs};
|
|
100
|
+
}
|
|
31
101
|
`;
|
|
32
102
|
|
|
33
103
|
const Form = styled.form`
|
|
@@ -38,14 +108,49 @@ const Form = styled.form`
|
|
|
38
108
|
|
|
39
109
|
const Password = styled.div`
|
|
40
110
|
${(p) => p.theme.textStyle.uiS};
|
|
41
|
-
color: ${(p) => p.theme.color.
|
|
42
|
-
margin-top: ${(p) => p.theme.spacing.m};
|
|
111
|
+
color: ${(p) => p.theme.color.interactiveInverse};
|
|
43
112
|
width: 100%;
|
|
44
|
-
text-align:
|
|
113
|
+
text-align: right;
|
|
45
114
|
|
|
46
115
|
span {
|
|
47
116
|
cursor: pointer;
|
|
48
117
|
}
|
|
49
118
|
`;
|
|
50
119
|
|
|
51
|
-
|
|
120
|
+
const Actions = styled.div`
|
|
121
|
+
display: flex;
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
const Secuoyas = styled.div<{ width: number }>`
|
|
125
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
126
|
+
position: absolute;
|
|
127
|
+
display: flex;
|
|
128
|
+
color: ${(p) => p.theme.color.textMediumEmphasisInverse};
|
|
129
|
+
width: ${(p) => p.width > 0 ? `${p.width}px` : "100%"};
|
|
130
|
+
justify-content: center;
|
|
131
|
+
align-items: center;
|
|
132
|
+
left: 0;
|
|
133
|
+
bottom: ${(p) => p.theme.spacing.m};
|
|
134
|
+
padding-bottom: ${(p) => p.theme.spacing.xs};
|
|
135
|
+
img {
|
|
136
|
+
width: 20px;
|
|
137
|
+
height: 20px;
|
|
138
|
+
margin-left: ${(p) => p.theme.spacing.xs};
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
export {
|
|
143
|
+
Wrapper,
|
|
144
|
+
Main,
|
|
145
|
+
Header,
|
|
146
|
+
Subtitle,
|
|
147
|
+
Title,
|
|
148
|
+
Form,
|
|
149
|
+
Password,
|
|
150
|
+
Actions,
|
|
151
|
+
Secuoyas,
|
|
152
|
+
LeftWrapper,
|
|
153
|
+
RightWrapper,
|
|
154
|
+
LoginWrapper,
|
|
155
|
+
AnimatedLoginSlider,
|
|
156
|
+
};
|
|
@@ -45,6 +45,7 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
45
45
|
pageStatusActions,
|
|
46
46
|
filterSearchAction,
|
|
47
47
|
searchFilters,
|
|
48
|
+
hasAnimation,
|
|
48
49
|
} = props;
|
|
49
50
|
|
|
50
51
|
const publishedTooltip: any = {
|
|
@@ -152,8 +153,10 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
152
153
|
|
|
153
154
|
const languageTooltip = typeof currentPageID === "number" && "Add language";
|
|
154
155
|
|
|
156
|
+
const classes = hasAnimation ? `${fixedClass} ${additionalClass} animate` : `${fixedClass} ${additionalClass}`
|
|
157
|
+
|
|
155
158
|
return (
|
|
156
|
-
<S.Header className={
|
|
159
|
+
<S.Header className={classes} inversed={inversed} data-testid="appbar-header">
|
|
157
160
|
<S.WrapperTitle>
|
|
158
161
|
{backLink && (
|
|
159
162
|
<span data-testid="back-button-wrapper">
|
|
@@ -288,6 +291,7 @@ export interface IAppBarProps {
|
|
|
288
291
|
};
|
|
289
292
|
isFromEditor?: boolean;
|
|
290
293
|
pageStatusActions?: any[];
|
|
294
|
+
hasAnimation?: boolean;
|
|
291
295
|
}
|
|
292
296
|
|
|
293
297
|
type IProps = IAppBarProps & RouteComponentProps;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import styled from "styled-components";
|
|
1
|
+
import styled, { keyframes } from "styled-components";
|
|
2
|
+
|
|
3
|
+
const OpacityAnimation = keyframes`
|
|
4
|
+
from {
|
|
5
|
+
opacity: 0;
|
|
6
|
+
}
|
|
7
|
+
to {
|
|
8
|
+
opacity: 1;
|
|
9
|
+
}
|
|
10
|
+
}`;
|
|
2
11
|
|
|
3
12
|
const ActionMenu = styled.ul``;
|
|
4
13
|
|
|
@@ -131,6 +140,7 @@ const Header = styled.section<{ inversed?: boolean }>`
|
|
|
131
140
|
background: ${(p) => (p.inversed ? p.theme.color.uiMainMenuBackground : p.theme.color.uiBackground02)};
|
|
132
141
|
display: flex;
|
|
133
142
|
padding-right: ${(p) => p.theme.spacing.s};
|
|
143
|
+
border-bottom: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
134
144
|
|
|
135
145
|
button:first-child {
|
|
136
146
|
margin-left: ${(p) => p.theme.spacing.m};
|
|
@@ -152,6 +162,12 @@ const Header = styled.section<{ inversed?: boolean }>`
|
|
|
152
162
|
z-index: 999;
|
|
153
163
|
}
|
|
154
164
|
|
|
165
|
+
&.animate {
|
|
166
|
+
opacity: 0;
|
|
167
|
+
animation: ${OpacityAnimation} 1s ease-in 1.2s;
|
|
168
|
+
animation-fill-mode: forwards;
|
|
169
|
+
}
|
|
170
|
+
|
|
155
171
|
${Title} {
|
|
156
172
|
color: ${(p) => (p.inversed ? p.theme.color.textHighEmphasisInverse : p.theme.color.textHighEmphasis)};
|
|
157
173
|
}
|
|
@@ -6,10 +6,11 @@ import AppBar from "./AppBar";
|
|
|
6
6
|
import * as S from "./style";
|
|
7
7
|
|
|
8
8
|
const MainWrapper = (props: IWrapperProps): JSX.Element => {
|
|
9
|
-
const { children, fixedAppBar, fullWidth } = props;
|
|
9
|
+
const { children, fixedAppBar, fullWidth, hasAnimation } = props;
|
|
10
10
|
|
|
11
11
|
return (
|
|
12
12
|
<S.Wrapper fixedAppBar={fixedAppBar} data-testid="main-wrapper">
|
|
13
|
+
{hasAnimation && <S.BackgroundAnimation />}
|
|
13
14
|
<AppBar {...props} />
|
|
14
15
|
<S.Main fullWidth={fullWidth} data-testid="main-component" id="main-component">
|
|
15
16
|
{children}
|
|
@@ -52,6 +53,7 @@ export interface IWrapperProps {
|
|
|
52
53
|
goToPackage(): void;
|
|
53
54
|
};
|
|
54
55
|
pageStatusActions?: any[];
|
|
56
|
+
hasAnimation?: boolean;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
export default MainWrapper;
|
|
@@ -1,17 +1,48 @@
|
|
|
1
|
-
import styled from "styled-components";
|
|
1
|
+
import styled, { keyframes } from "styled-components";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const Wrapper = styled.section<{ fixedAppBar: boolean | undefined }>`
|
|
4
4
|
height: 100%;
|
|
5
5
|
display: flex;
|
|
6
6
|
flex-direction: column;
|
|
7
7
|
padding-top: ${(p) => (p.fixedAppBar ? p.theme.spacing.xl : "0")};
|
|
8
8
|
`;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const Main = styled.article<{ fullWidth: boolean | undefined }>`
|
|
11
11
|
position: relative;
|
|
12
12
|
overflow: ${(p) => (p.fullWidth ? "visible" : "auto")};
|
|
13
13
|
background: ${(p) => p.theme.color.uiBackground01};
|
|
14
|
-
border-top: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
15
14
|
margin-top: -1px;
|
|
16
15
|
flex-grow: 1;
|
|
17
16
|
`;
|
|
17
|
+
|
|
18
|
+
const LoginAnimation = keyframes`
|
|
19
|
+
from {
|
|
20
|
+
width: 100%;
|
|
21
|
+
}
|
|
22
|
+
to {
|
|
23
|
+
width: 72px;
|
|
24
|
+
}
|
|
25
|
+
}`;
|
|
26
|
+
|
|
27
|
+
const OpacityAnimation = keyframes`
|
|
28
|
+
from {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
}
|
|
31
|
+
to {
|
|
32
|
+
opacity: 0;
|
|
33
|
+
}
|
|
34
|
+
}`;
|
|
35
|
+
|
|
36
|
+
const BackgroundAnimation = styled.div`
|
|
37
|
+
position: absolute;
|
|
38
|
+
top: 0;
|
|
39
|
+
left: 0;
|
|
40
|
+
bottom: 0;
|
|
41
|
+
width: 100%;
|
|
42
|
+
background-color: ${(p) => p.theme.color.uiMainMenuBackground};
|
|
43
|
+
z-index: 10;
|
|
44
|
+
animation: ${LoginAnimation} 1.2s ease-in, ${OpacityAnimation} 1s ease-in 1.2s;
|
|
45
|
+
animation-fill-mode: forwards;
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
export { Wrapper, Main, BackgroundAnimation };
|
|
@@ -8,9 +8,7 @@ import * as S from "./style";
|
|
|
8
8
|
const TableList = (props: ITableListProps): JSX.Element => {
|
|
9
9
|
const { tableHeader, children, pagination, isLoading, onScroll, hasFixedHeader, tableRef } = props;
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const showPagination = totalItems > itemsPerPage;
|
|
11
|
+
const showPagination = pagination && pagination.totalItems > pagination.itemsPerPage;
|
|
14
12
|
|
|
15
13
|
return (
|
|
16
14
|
<S.TableList onScroll={onScroll} ref={tableRef} data-testid="table-list">
|
|
@@ -24,7 +22,7 @@ const TableList = (props: ITableListProps): JSX.Element => {
|
|
|
24
22
|
</S.Table>
|
|
25
23
|
<S.PaginationWrapper>
|
|
26
24
|
{showPagination && (
|
|
27
|
-
<Pagination totalItems={totalItems} setPage={setPage} itemsPerPage={itemsPerPage} currPage={currPage} />
|
|
25
|
+
<Pagination totalItems={pagination.totalItems} setPage={pagination.setPage} itemsPerPage={pagination.itemsPerPage} currPage={pagination.currPage} />
|
|
28
26
|
)}
|
|
29
27
|
</S.PaginationWrapper>
|
|
30
28
|
</S.TableList>
|
|
@@ -38,7 +36,7 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
38
36
|
export interface ITableListProps {
|
|
39
37
|
tableHeader: JSX.Element | JSX.Element[];
|
|
40
38
|
children: JSX.Element | JSX.Element[];
|
|
41
|
-
pagination
|
|
39
|
+
pagination?: {
|
|
42
40
|
totalItems: number;
|
|
43
41
|
setPage: any;
|
|
44
42
|
itemsPerPage: number;
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
SET_GLOBAL_SETTINGS,
|
|
21
21
|
SET_USER,
|
|
22
22
|
SET_SESSION_STARTED_AT,
|
|
23
|
+
SET_HAS_ANIMATION,
|
|
23
24
|
} from "./constants";
|
|
24
25
|
|
|
25
26
|
import {
|
|
@@ -34,6 +35,7 @@ import {
|
|
|
34
35
|
ISetGlobalSettings,
|
|
35
36
|
ISetUserAction,
|
|
36
37
|
ISetSessionStartedAtAction,
|
|
38
|
+
ISetHasAnimation,
|
|
37
39
|
} from "./interfaces";
|
|
38
40
|
import { IError, IUser } from "./reducer";
|
|
39
41
|
|
|
@@ -45,6 +47,10 @@ function setIsSaving(isSaving: boolean): ISetIsSaving {
|
|
|
45
47
|
return { type: SET_IS_SAVING, payload: { isSaving } };
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
function setHasAnimation(hasAnimation: boolean): ISetHasAnimation {
|
|
51
|
+
return { type: SET_HAS_ANIMATION, payload: { hasAnimation } };
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
const resetStateValues = (dispatch: Dispatch) => {
|
|
49
55
|
dispatch(setIsLoading(true));
|
|
50
56
|
dispatch(setIsSaving(false));
|
|
@@ -138,13 +144,12 @@ function handleError(response: any, isMultiple = false, msg?: string): (dispatch
|
|
|
138
144
|
};
|
|
139
145
|
}
|
|
140
146
|
|
|
141
|
-
function login(email: string, password: string, rememberMe: boolean): (dispatch: Dispatch) => Promise<
|
|
142
|
-
const welcomePageURI = "/sites";
|
|
147
|
+
function login(email: string, password: string, rememberMe: boolean): (dispatch: Dispatch) => Promise<boolean> {
|
|
143
148
|
return async (dispatch) => {
|
|
144
149
|
dispatch(setIsLogging(true));
|
|
145
150
|
const loginResponse: any = await global.login(email, password);
|
|
146
151
|
dispatch(setIsLogging(false));
|
|
147
|
-
switch (loginResponse
|
|
152
|
+
switch (loginResponse?.status) {
|
|
148
153
|
case 200: {
|
|
149
154
|
const {
|
|
150
155
|
data: { token },
|
|
@@ -153,12 +158,12 @@ function login(email: string, password: string, rememberMe: boolean): (dispatch:
|
|
|
153
158
|
isReqOk(langResponse.status) && dispatch(setGlobalLanguages(langResponse.data.items));
|
|
154
159
|
dispatch(setToken(loginResponse.data.token));
|
|
155
160
|
dispatch(setSessionStartedAt(new Date()));
|
|
156
|
-
|
|
161
|
+
dispatch(setHasAnimation(true));
|
|
157
162
|
if (rememberMe) {
|
|
158
163
|
const user: any = { token: loginResponse.data.token };
|
|
159
164
|
localStorage.setItem("user", JSON.stringify(user));
|
|
160
165
|
}
|
|
161
|
-
|
|
166
|
+
return true;
|
|
162
167
|
}
|
|
163
168
|
case 403: {
|
|
164
169
|
const error = {
|
|
@@ -167,11 +172,21 @@ function login(email: string, password: string, rememberMe: boolean): (dispatch:
|
|
|
167
172
|
actionsBelow: true,
|
|
168
173
|
};
|
|
169
174
|
handleError(error)(dispatch);
|
|
170
|
-
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
case undefined: {
|
|
178
|
+
const error = {
|
|
179
|
+
data: {
|
|
180
|
+
code: 500,
|
|
181
|
+
message: "An error has occurred. Please contact your system administrator.",
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
handleError(error)(dispatch);
|
|
185
|
+
return false;
|
|
171
186
|
}
|
|
172
187
|
default:
|
|
173
188
|
handleError(loginResponse)(dispatch);
|
|
174
|
-
|
|
189
|
+
return false;
|
|
175
190
|
}
|
|
176
191
|
};
|
|
177
192
|
}
|
|
@@ -225,4 +240,5 @@ export {
|
|
|
225
240
|
getGlobalSettings,
|
|
226
241
|
setUser,
|
|
227
242
|
checkUserSession,
|
|
243
|
+
setHasAnimation,
|
|
228
244
|
};
|