Skip to content

Commit

Permalink
feat(user): add password reset modal
Browse files Browse the repository at this point in the history
  • Loading branch information
RCVZ committed Jul 30, 2021
1 parent 9f48c2a commit 96048a1
Show file tree
Hide file tree
Showing 13 changed files with 164 additions and 10 deletions.
9 changes: 8 additions & 1 deletion src/components/Account/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import type { Consent, Customer, CustomerConsent, UpdateCustomerPayload } from 'types/account';
import type { CustomerFormValues, FormErrors, GenericFormValues } from 'types/form';
import { useHistory } from 'react-router-dom';

import { formatConsentsFromValues, formatConsentValues } from '../../utils/collection';
import Visibility from '../../icons/Visibility';
Expand All @@ -14,6 +15,7 @@ import IconButton from '../IconButton/IconButton';
import LoadingOverlay from '../LoadingOverlay/LoadingOverlay';
import TextField from '../TextField/TextField';
import Checkbox from '../Checkbox/Checkbox';
import { addQueryParam } from '../../utils/history';

import styles from './Account.module.scss';

Expand Down Expand Up @@ -51,6 +53,7 @@ const Account = ({
onReset,
}: Props): JSX.Element => {
const { t } = useTranslation('user');
const history = useHistory();
const [editing, setEditing] = useState<Editing>('none');
const [viewPassword, toggleViewPassword] = useToggle();
const consentValues = useMemo(() => formatConsentValues(publisherConsents, customerConsents), [publisherConsents, customerConsents]);
Expand All @@ -74,6 +77,10 @@ const Account = ({
onReset && onReset();
};

const editPasswordClickHandler = () => {
history.push(addQueryParam(history, 'u', 'reset-password'));
};

useEffect(() => {
!isLoading && setEditing('none');
}, [isLoading]);
Expand Down Expand Up @@ -143,7 +150,7 @@ const Account = ({
<div>
<strong>{t('account.password')}</strong>
<p>****************</p>
<Button label={t('account.edit_password')} type="button" onClick={() => setEditing('password')} />
<Button label={t('account.edit_password')} type="button" onClick={() => (customer ? editPasswordClickHandler() : null)} />
</div>
</div>
<div className={panelClassName}>
Expand Down
8 changes: 4 additions & 4 deletions src/components/Payment/__snapshots__/Payment.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exports[`<Payment> renders and matches snapshot 1`] = `
<br />
user:payment.next_billing_date_on
3/16/2021
16-3-2021
</p>
<p
class="price"
Expand Down Expand Up @@ -106,7 +106,7 @@ exports[`<Payment> renders and matches snapshot 1`] = `
<p>
T712014024
<br />
5/5/2021
5-5-2021
</p>
</div>
<div
Expand All @@ -123,7 +123,7 @@ exports[`<Payment> renders and matches snapshot 1`] = `
<p>
T177974068
<br />
5/5/2021
5-5-2021
</p>
</div>
<div
Expand All @@ -140,7 +140,7 @@ exports[`<Payment> renders and matches snapshot 1`] = `
<p>
T996601696
<br />
5/5/2021
5-5-2021
</p>
</div>
</div>
Expand Down
19 changes: 19 additions & 0 deletions src/components/ResetPasswordForm/ResetPasswordForm.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@use '../../styles/variables';
@use '../../styles/theme';

.title {
margin: 24px 0;
font-family: theme.$body-alt-font-family;
font-weight: 700;
font-size: 26px;
}

.text {
margin-bottom: 24px;
font-family: theme.$body-alt-font-family;
font-size: 16px;
}

.button {
margin-bottom: 8px;
}
12 changes: 12 additions & 0 deletions src/components/ResetPasswordForm/ResetPasswordForm.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { render } from '@testing-library/react';

import ResetPasswordForm from './ResetPasswordForm';

describe('<ResetPassword>', () => {
test('renders and matches snapshot', () => {
const { container } = render(<ResetPasswordForm onCancel={jest.fn()} onReset={jest.fn()} />);

expect(container).toMatchSnapshot();
});
});
25 changes: 25 additions & 0 deletions src/components/ResetPasswordForm/ResetPasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { useTranslation } from 'react-i18next';

import Button from '../Button/Button';

import styles from './ResetPasswordForm.module.scss';

type Props = {
onCancel: () => void;
onReset: () => void;
};

const ResetPasswordForm: React.FC<Props> = ({ onCancel, onReset }: Props) => {
const { t } = useTranslation('account');
return (
<div className={styles.resetPassword}>
<h5 className={styles.title}>{t('reset.reset_password')}</h5>
<p className={styles.text}>{t('reset.text')}</p>
<Button onClick={onCancel} className={styles.button} fullWidth color="primary" label={t('reset.yes')} />
<Button onClick={onReset} fullWidth label={t('reset.no')} />
</div>
);
};

export default ResetPasswordForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<ResetPassword> renders and matches snapshot 1`] = `
<div>
<div>
<h5
class="title"
>
reset.reset_password
</h5>
<p
class="text"
>
reset.text
</p>
<button
class="button button primary outlined fullWidth"
>
<span>
reset.yes
</span>
</button>
<button
class="button default outlined fullWidth"
>
<span>
reset.no
</span>
</button>
</div>
</div>
`;
2 changes: 2 additions & 0 deletions src/containers/AccountModal/AccountModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import styles from './AccountModal.module.scss';
import Login from './forms/Login';
import ChooseOffer from './forms/ChooseOffer';
import Checkout from './forms/Checkout';
import ResetPassword from './forms/ResetPassword';

const AccountModal = () => {
const history = useHistory();
Expand All @@ -29,6 +30,7 @@ const AccountModal = () => {
{view === 'login' ? <Login /> : null}
{view === 'choose-offer' ? <ChooseOffer /> : null}
{view === 'checkout' ? <Checkout /> : null}
{view === 'reset-password' ? <ResetPassword /> : null}
</Dialog>
);
};
Expand Down
35 changes: 35 additions & 0 deletions src/containers/AccountModal/forms/ResetPassword.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { useHistory } from 'react-router-dom';

import { resetPassword } from '../../../stores/AccountStore';
import { removeQueryParam } from '../../../utils/history';
import ResetPasswordForm from '../../../components/ResetPasswordForm/ResetPasswordForm';

const ResetPassword: React.FC = () => {
const history = useHistory();

const onCancelClickHandler = () => {
history.push(removeQueryParam(history, 'u'));
};

const onResetClickHandler = async () => {
const resetUrl = `${window.location.origin}/u/my-account?u=edit-password`;

try {
const response = await resetPassword(resetUrl);
if (response.errors.length > 0) throw new Error(response.errors[0]);

history.push('/u/logout');
} catch (error: unknown) {
if (error instanceof Error) {
if (error.message.toLowerCase().includes('invalid param email')) {
console.info(error.message);
}
}
}
};

return <ResetPasswordForm onCancel={onCancelClickHandler} onReset={onResetClickHandler} />;
};

export default ResetPassword;
6 changes: 6 additions & 0 deletions src/i18n/locales/en_US/account.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,11 @@
"week_plural": "weeks",
"month_plural": "months",
"year_plural": "years"
},
"reset": {
"no": "No, thanks",
"reset_password": "Edit Password",
"text": "If you want to edit your password, click 'YES, Reset' to receive password reset instruction on your mail",
"yes": "Yes, reset"
}
}
3 changes: 1 addition & 2 deletions src/i18n/locales/en_US/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
"live": "LIVE",
"play_item": "Play {{ title }}",
"slide_left": "Slide left",
"slide_right": "Slide right",
"show_page": "Show page {{ number }}"
"slide_right": "Slide right"
}
6 changes: 6 additions & 0 deletions src/i18n/locales/nl_NL/account.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,11 @@
"month": "",
"week": "",
"year": ""
},
"reset": {
"no": "",
"reset_password": "",
"text": "",
"yes": ""
}
}
3 changes: 1 addition & 2 deletions src/i18n/locales/nl_NL/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
"live": "",
"play_item": "",
"slide_left": "",
"slide_right": "",
"show_page": ""
"slide_right": ""
}
14 changes: 13 additions & 1 deletion src/stores/AccountStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const refreshJwtToken = async (sandbox: boolean, auth: AuthData) => {
const authData = await getFreshJwtToken(sandbox, auth);

if (authData) {
AccountStore.update(s => {
AccountStore.update((s) => {
s.auth = { ...s.auth, ...authData };
});
}
Expand Down Expand Up @@ -91,3 +91,15 @@ export const login = async (email: string, password: string) => {

return afterLogin(cleengSandbox, response.responseData);
};

export const resetPassword = async (resetUrl: string) => {
const {
config: { cleengId, cleengSandbox },
} = ConfigStore.getRawState();
const { user } = AccountStore.getRawState();

if (!cleengId) throw new Error('cleengId is not configured');
if (!user?.email) throw new Error('invalid param email');

return await accountService.resetPassword({ customerEmail: user.email, publisherId: cleengId, resetUrl }, cleengSandbox);
};

0 comments on commit 96048a1

Please sign in to comment.