Skip to content

Commit 9e6201c

Browse files
authored
Merge pull request #88 from swiftss-org/feat/redesign-login
feat: redesign login
2 parents 0fa8b3c + 0e65998 commit 9e6201c

File tree

16 files changed

+248
-65
lines changed

16 files changed

+248
-65
lines changed

src/App.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { QueryClient, QueryClientProvider } from 'react-query';
55
import { BrowserRouter as Router } from 'react-router-dom';
66

77
import { AppWrapper } from './App.style';
8+
import NotificationsProvider from './providers/Notifications/NotificationProvider';
89
import Routes from './routing/Routes';
910
import { themeOverride } from './theme/globals';
1011

@@ -16,11 +17,13 @@ const App: React.FC = () => {
1617
return (
1718
<QueryClientProvider client={queryClient}>
1819
<ThemeProvider theme={themeOverride}>
19-
<Router>
20-
<AppWrapper>
21-
<Routes />
22-
</AppWrapper>
23-
</Router>
20+
<NotificationsProvider>
21+
<Router>
22+
<AppWrapper>
23+
<Routes />
24+
</AppWrapper>
25+
</Router>
26+
</NotificationsProvider>
2427
</ThemeProvider>
2528
</QueryClientProvider>
2629
);

src/common.style.tsx

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,10 @@ export const PageWrapper = styled.div`
1212
`;
1313

1414
export const CheckBoxContainer = styled.div<{ error?: boolean; checked?: boolean }>`
15-
&& * {
16-
color: black;
17-
}
18-
19-
//checked checkbox color
20-
label:after {
21-
box-shadow: 2px 0 0 black, 4px 0 0 black, 4px -2px 0 black, 4px -4px 0 black, 4px -6px 0 black,
22-
4px -8px 0 black, 4px -10px 0 black !important;
23-
background-color: black !important;
24-
}
25-
26-
label:before {
27-
box-shadow: inset 0px 0px 0px 0.125rem
28-
${(props) =>
29-
props.checked
30-
? props.theme.utils.getColor('lightGray', 400)
31-
: props.theme.utils.getColor('lightGray', 400)} !important;
32-
background-color: ${(props) =>
33-
props.checked ? props.theme.utils.getColor('lightGray', 400) : 'inherit'} !important;
34-
}
35-
36-
span {
37-
color: white;
38-
white-space: pre-line;
39-
}
15+
margin-left: -12px;
4016
4117
svg path {
42-
fill: black;
18+
fill: white;
4319
}
4420
`;
4521

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import styled from '@emotion/styled';
2+
import { NotificationTypes } from '@orfium/ictinus/dist/components/Notification/Notification';
3+
4+
export const NotificationStyle = styled.div<{ type: NotificationTypes }>`
5+
div:first-of-type:first-of-type {
6+
div:first-of-type {
7+
svg {
8+
fill: ${(props) =>
9+
props.type === 'error' ? props.theme.utils.getColor('red', 200) : ''} !important;
10+
path {
11+
fill: ${(props) =>
12+
props.type === 'error' ? props.theme.utils.getColor('red', 200) : ''} !important;
13+
}
14+
}
15+
}
16+
}
17+
div {
18+
background: #343645;
19+
border-color: ${(props) =>
20+
props.type === 'error' ? props.theme.utils.getColor('red', 200) : ''} !important;
21+
}
22+
23+
& > div {
24+
height: auto;
25+
min-height: 56px;
26+
27+
& > div:nth-of-type(1) {
28+
align-items: stretch;
29+
30+
& > div:nth-of-type(1) {
31+
margin-top: 13px;
32+
}
33+
34+
& > div:nth-of-type(2) {
35+
margin: 16px 0;
36+
}
37+
}
38+
39+
& > div:nth-of-type(2) {
40+
align-items: stretch;
41+
margin-top: 13px;
42+
}
43+
}
44+
`;
45+
46+
export const NotificationWrapper = styled.div`
47+
border-radius: 8px;
48+
scroll-margin: 40px;
49+
`;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/** @jsxImportSource @emotion/react */
2+
import React from 'react';
3+
4+
import { InlineNotification } from '@orfium/ictinus';
5+
import { NotificationTypes } from '@orfium/ictinus/dist/components/Notification/Notification';
6+
7+
import { resetNotifications } from '../../providers/Notifications/actions';
8+
import { useNotifications } from '../../providers/Notifications/NotificationProvider';
9+
import { NotificationWrapper } from './Notifications.styles';
10+
11+
export interface NotificationType {
12+
message: string;
13+
type: NotificationTypes;
14+
isGlobal: boolean;
15+
isPreview?: boolean;
16+
id: number;
17+
}
18+
19+
const Notifications: React.FC = () => {
20+
const [notification, dispatch] = useNotifications();
21+
const ref = React.useRef<HTMLDivElement>(null);
22+
23+
const removeNotification = () => {
24+
dispatch(resetNotifications());
25+
};
26+
27+
React.useEffect(() => {
28+
if (notification && ref.current) {
29+
ref.current?.scrollIntoView?.({ behavior: 'smooth', block: 'start', inline: 'nearest' });
30+
}
31+
}, [notification]);
32+
33+
return (
34+
<>
35+
{notification && (
36+
<NotificationWrapper ref={ref}>
37+
<InlineNotification
38+
styleType={'outlined'}
39+
withIcon
40+
message={notification.message}
41+
type={notification.type}
42+
primaryCTALabel="Action"
43+
closeCTA={() => removeNotification()}
44+
/>
45+
</NotificationWrapper>
46+
)}
47+
</>
48+
);
49+
};
50+
51+
export default Notifications;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Notifications from './Notifications';
2+
3+
export default Notifications;

src/hooks/api/userHooks.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2+
import { setAxiosToken } from 'api/axiosInstances';
3+
import userAPI from 'api/userAPI';
24
import { AxiosError } from 'axios';
5+
import { useSetNotification } from 'hooks/useSetNotification';
6+
import { LoginFormType, LoginResponse } from 'models/apiTypes';
7+
import { resetNotifications } from 'providers/Notifications/actions';
8+
import { useNotifications } from 'providers/Notifications/NotificationProvider';
39
import { useMutation } from 'react-query';
410
import { useHistory } from 'react-router-dom';
11+
import urls from 'routing/urls';
512
import { __TOKEN__ } from 'utils/constants';
6-
7-
import { setAxiosToken } from '../../api/axiosInstances';
8-
import userAPI from '../../api/userAPI';
9-
import { LoginFormType, LoginResponse } from '../../models/apiTypes';
10-
import urls from '../../routing/urls';
11-
import { setUserStorageItem } from '../../utils/storage';
12-
13+
import { setUserStorageItem } from 'utils/storage';
1314

1415
export const useSignIn = () => {
1516
const history = useHistory();
17+
const setNotification = useSetNotification();
18+
const [, notificationDispatch] = useNotifications();
1619

1720
return useMutation<LoginResponse, AxiosError, LoginFormType>(
1821
(params) => {
@@ -24,12 +27,14 @@ export const useSignIn = () => {
2427
},
2528
{
2629
onSuccess: async (data, variables) => {
30+
notificationDispatch(resetNotifications());
2731
setUserStorageItem(__TOKEN__, data?.token ?? '', !variables.rememberMe);
2832
setAxiosToken(data?.token ?? '');
2933

3034
history.replace(urls.patients());
3135
},
3236
onError: (errors) => {
37+
setNotification('Invalid credential combination.', 'error');
3338
console.log(errors);
3439
},
3540
}

src/hooks/useSetNotification.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { NotificationTypes } from '@orfium/ictinus/dist/components/Notification/Notification';
2+
3+
import { NotificationType } from '../components/Notifications/Notifications';
4+
import { addNotification } from '../providers/Notifications/actions';
5+
import { useNotifications } from '../providers/Notifications/NotificationProvider';
6+
7+
export const useSetNotification = () => {
8+
const [, dispatch] = useNotifications();
9+
10+
return (message: string, type: NotificationTypes, isGlobal = false, isPreview = false) => {
11+
const newNotification: NotificationType = {
12+
isGlobal,
13+
isPreview,
14+
message: message,
15+
type: type,
16+
id: 0,
17+
};
18+
19+
dispatch(addNotification(newNotification));
20+
};
21+
};

src/pages/Layout/Layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import React from 'react';
33

44
import { Drawer, IconButton } from '@orfium/ictinus';
5+
import { TopBar } from 'App.style';
6+
import { useResponsiveLayout } from 'hooks/useResponsiveSidebar';
57

6-
import { TopBar } from '../../App.style';
7-
import { useResponsiveLayout } from '../../hooks/useResponsiveSidebar';
88
import { Header, Main, MainContainer, SideNav } from './Layout.style';
99

1010
interface Props {

src/pages/Login/Login.style.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ export const TextContainer = styled.div`
1010
export const Title = styled.span`
1111
font-size: 24px;
1212
font-weight: 700;
13+
margin-bottom: 8px;
1314
`;
1415

1516
export const Subtitle = styled.span`
1617
font-size: 16px;
1718
font-weight: 400;
18-
margin-top: 8px;
19+
margin-bottom: 24px;
20+
`;
21+
22+
export const Wrapper = styled.div`
23+
padding: 32px;
1924
`;

src/pages/Login/Login.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
/** @jsxImportSource @emotion/react */
22
import React from 'react';
33

4+
import Notifications from 'components/Notifications';
5+
46
import LoginForm from './components/LoginForm';
5-
import { Subtitle, TextContainer, Title } from './Login.style';
7+
import { Subtitle, TextContainer, Title, Wrapper } from './Login.style';
68

79
const Login: React.FC = () => {
810
return (
9-
<div css={{ padding: '18px' }}>
11+
<Wrapper>
12+
<Notifications />
1013
<TextContainer>
11-
<Title>Welcome back!</Title>
12-
<Subtitle>Please sign in</Subtitle>
14+
<Title>Welcome!</Title>
15+
<Subtitle>Please sign in using your credentials to access your account.</Subtitle>
1316
</TextContainer>
1417
<LoginForm />
15-
</div>
18+
</Wrapper>
1619
);
1720
};
1821

0 commit comments

Comments
 (0)