Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { QueryClient, QueryClientProvider } from 'react-query';
import { BrowserRouter as Router } from 'react-router-dom';

import { AppWrapper } from './App.style';
import NotificationsProvider from './providers/Notifications/NotificationProvider';
import Routes from './routing/Routes';
import { themeOverride } from './theme/globals';

Expand All @@ -16,11 +17,13 @@ const App: React.FC = () => {
return (
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={themeOverride}>
<Router>
<AppWrapper>
<Routes />
</AppWrapper>
</Router>
<NotificationsProvider>
<Router>
<AppWrapper>
<Routes />
</AppWrapper>
</Router>
</NotificationsProvider>
</ThemeProvider>
</QueryClientProvider>
);
Expand Down
28 changes: 2 additions & 26 deletions src/common.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,10 @@ export const PageWrapper = styled.div`
`;

export const CheckBoxContainer = styled.div<{ error?: boolean; checked?: boolean }>`
&& * {
color: black;
}

//checked checkbox color
label:after {
box-shadow: 2px 0 0 black, 4px 0 0 black, 4px -2px 0 black, 4px -4px 0 black, 4px -6px 0 black,
4px -8px 0 black, 4px -10px 0 black !important;
background-color: black !important;
}

label:before {
box-shadow: inset 0px 0px 0px 0.125rem
${(props) =>
props.checked
? props.theme.utils.getColor('lightGray', 400)
: props.theme.utils.getColor('lightGray', 400)} !important;
background-color: ${(props) =>
props.checked ? props.theme.utils.getColor('lightGray', 400) : 'inherit'} !important;
}

span {
color: white;
white-space: pre-line;
}
margin-left: -12px;

svg path {
fill: black;
fill: white;
}
`;

Expand Down
49 changes: 49 additions & 0 deletions src/components/Notifications/Notifications.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import styled from '@emotion/styled';
import { NotificationTypes } from '@orfium/ictinus/dist/components/Notification/Notification';

export const NotificationStyle = styled.div<{ type: NotificationTypes }>`
div:first-of-type:first-of-type {
div:first-of-type {
svg {
fill: ${(props) =>
props.type === 'error' ? props.theme.utils.getColor('red', 200) : ''} !important;
path {
fill: ${(props) =>
props.type === 'error' ? props.theme.utils.getColor('red', 200) : ''} !important;
}
}
}
}
div {
background: #343645;
border-color: ${(props) =>
props.type === 'error' ? props.theme.utils.getColor('red', 200) : ''} !important;
}

& > div {
height: auto;
min-height: 56px;

& > div:nth-of-type(1) {
align-items: stretch;

& > div:nth-of-type(1) {
margin-top: 13px;
}

& > div:nth-of-type(2) {
margin: 16px 0;
}
}

& > div:nth-of-type(2) {
align-items: stretch;
margin-top: 13px;
}
}
`;

export const NotificationWrapper = styled.div`
border-radius: 8px;
scroll-margin: 40px;
`;
51 changes: 51 additions & 0 deletions src/components/Notifications/Notifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/** @jsxImportSource @emotion/react */
import React from 'react';

import { InlineNotification } from '@orfium/ictinus';
import { NotificationTypes } from '@orfium/ictinus/dist/components/Notification/Notification';

import { resetNotifications } from '../../providers/Notifications/actions';
import { useNotifications } from '../../providers/Notifications/NotificationProvider';
import { NotificationWrapper } from './Notifications.styles';

export interface NotificationType {
message: string;
type: NotificationTypes;
isGlobal: boolean;
isPreview?: boolean;
id: number;
}

const Notifications: React.FC = () => {
const [notification, dispatch] = useNotifications();
const ref = React.useRef<HTMLDivElement>(null);

const removeNotification = () => {
dispatch(resetNotifications());
};

React.useEffect(() => {
if (notification && ref.current) {
ref.current?.scrollIntoView?.({ behavior: 'smooth', block: 'start', inline: 'nearest' });
}
}, [notification]);

return (
<>
{notification && (
<NotificationWrapper ref={ref}>
<InlineNotification
styleType={'outlined'}
withIcon
message={notification.message}
type={notification.type}
primaryCTALabel="Action"
closeCTA={() => removeNotification()}
/>
</NotificationWrapper>
)}
</>
);
};

export default Notifications;
3 changes: 3 additions & 0 deletions src/components/Notifications/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Notifications from './Notifications';

export default Notifications;
19 changes: 12 additions & 7 deletions src/hooks/api/userHooks.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { setAxiosToken } from 'api/axiosInstances';
import userAPI from 'api/userAPI';
import { AxiosError } from 'axios';
import { useSetNotification } from 'hooks/useSetNotification';
import { LoginFormType, LoginResponse } from 'models/apiTypes';
import { resetNotifications } from 'providers/Notifications/actions';
import { useNotifications } from 'providers/Notifications/NotificationProvider';
import { useMutation } from 'react-query';
import { useHistory } from 'react-router-dom';
import urls from 'routing/urls';
import { __TOKEN__ } from 'utils/constants';

import { setAxiosToken } from '../../api/axiosInstances';
import userAPI from '../../api/userAPI';
import { LoginFormType, LoginResponse } from '../../models/apiTypes';
import urls from '../../routing/urls';
import { setUserStorageItem } from '../../utils/storage';

import { setUserStorageItem } from 'utils/storage';

export const useSignIn = () => {
const history = useHistory();
const setNotification = useSetNotification();
const [, notificationDispatch] = useNotifications();

return useMutation<LoginResponse, AxiosError, LoginFormType>(
(params) => {
Expand All @@ -24,12 +27,14 @@ export const useSignIn = () => {
},
{
onSuccess: async (data, variables) => {
notificationDispatch(resetNotifications());
setUserStorageItem(__TOKEN__, data?.token ?? '', !variables.rememberMe);
setAxiosToken(data?.token ?? '');

history.replace(urls.patients());
},
onError: (errors) => {
setNotification('Invalid credential combination.', 'error');
console.log(errors);
},
}
Expand Down
21 changes: 21 additions & 0 deletions src/hooks/useSetNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { NotificationTypes } from '@orfium/ictinus/dist/components/Notification/Notification';

import { NotificationType } from '../components/Notifications/Notifications';
import { addNotification } from '../providers/Notifications/actions';
import { useNotifications } from '../providers/Notifications/NotificationProvider';

export const useSetNotification = () => {
const [, dispatch] = useNotifications();

return (message: string, type: NotificationTypes, isGlobal = false, isPreview = false) => {
const newNotification: NotificationType = {
isGlobal,
isPreview,
message: message,
type: type,
id: 0,
};

dispatch(addNotification(newNotification));
};
};
4 changes: 2 additions & 2 deletions src/pages/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import React from 'react';

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

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

interface Props {
Expand Down
7 changes: 6 additions & 1 deletion src/pages/Login/Login.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ export const TextContainer = styled.div`
export const Title = styled.span`
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
`;

export const Subtitle = styled.span`
font-size: 16px;
font-weight: 400;
margin-top: 8px;
margin-bottom: 24px;
`;

export const Wrapper = styled.div`
padding: 32px;
`;
13 changes: 8 additions & 5 deletions src/pages/Login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
/** @jsxImportSource @emotion/react */
import React from 'react';

import Notifications from 'components/Notifications';

import LoginForm from './components/LoginForm';
import { Subtitle, TextContainer, Title } from './Login.style';
import { Subtitle, TextContainer, Title, Wrapper } from './Login.style';

const Login: React.FC = () => {
return (
<div css={{ padding: '18px' }}>
<Wrapper>
<Notifications />
<TextContainer>
<Title>Welcome back!</Title>
<Subtitle>Please sign in</Subtitle>
<Title>Welcome!</Title>
<Subtitle>Please sign in using your credentials to access your account.</Subtitle>
</TextContainer>
<LoginForm />
</div>
</Wrapper>
);
};

Expand Down
17 changes: 5 additions & 12 deletions src/pages/Login/components/LoginForm/LoginForm.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import styled from '@emotion/styled';
import { flexCenter } from '@orfium/ictinus/dist/theme/functions';

export const FormContainer = styled.div`
height: 100%;
margin-top: 10px;
`;

Expand All @@ -12,16 +13,8 @@ export const FormBottom = styled.div`
`;

export const ButtonContainer = styled.div`
width: 100%;

&& button {
text-align: center;
width: 100%;

span {
font-size: 16px;
font-weight: 700;
justify-content: center;
}
}
bottom: 32px;
left: 32px;
position: fixed;
right: 32px;
`;
10 changes: 5 additions & 5 deletions src/pages/Login/components/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import React from 'react';

import { Button, CheckBox, TextField } from '@orfium/ictinus';
import { CheckBoxContainer, FieldsContainer, FieldWrapper, LongFieldWrapper } from 'common.style';
import { useSignIn } from 'hooks/api/userHooks';
import { LoginFormType } from 'models/apiTypes';
import { Field, Form } from 'react-final-form';

import { useSignIn } from '../../../../hooks/api/userHooks';
import { LoginFormType } from '../../../../models/apiTypes';
import { ButtonContainer, FormBottom, FormContainer } from './LoginForm.style';

const SignIn: React.FC = () => {
Expand All @@ -20,7 +20,7 @@ const SignIn: React.FC = () => {
<FormContainer>
<Form initialValues={{ rememberMe: false }} onSubmit={handleSubmit}>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<form style={{ height: '100%' }} onSubmit={handleSubmit}>
<FieldsContainer withMargin>
<LongFieldWrapper>
<FieldWrapper>
Expand Down Expand Up @@ -69,7 +69,7 @@ const SignIn: React.FC = () => {
<Field name="rememberMe">
{(props) => {
return (
<CheckBoxContainer checked={props.input.value}>
<CheckBoxContainer>
<CheckBox
{...props.input}
filled={true}
Expand All @@ -84,7 +84,7 @@ const SignIn: React.FC = () => {
</FormBottom>

<ButtonContainer>
<Button color={'neutralBlack-700'} filled size="lg" buttonType="submit">
<Button block color={'blue-500'} filled size="lg" buttonType="submit">
Sign In
</Button>
</ButtonContainer>
Expand Down
Loading