-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(auth): implement renew subscription flow
- Loading branch information
1 parent
eb38820
commit ccd6e4d
Showing
18 changed files
with
358 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
src/components/RenewSubscriptionForm/RenewSubscriptionForm.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
@use '../../styles/variables'; | ||
@use '../../styles/theme'; | ||
|
||
.title { | ||
margin-bottom: 16px; | ||
font-family: theme.$body-alt-font-family; | ||
font-weight: 700; | ||
font-size: 24px; | ||
} | ||
|
||
.paragraph { | ||
font-family: theme.$body-font-family; | ||
} | ||
|
||
.infoBox { | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
margin-bottom: variables.$base-spacing; | ||
padding: variables.$base-spacing / 2 variables.$base-spacing; | ||
|
||
font-family: theme.$body-font-family; | ||
font-size: 14px; | ||
line-height: 18px; | ||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.14), 0 3px 4px rgba(0, 0, 0, 0.12), 0 1px 5px rgba(0, 0, 0, 0.2); | ||
background: theme.$panel-bg; | ||
border-radius: 4px; | ||
|
||
> strong { | ||
line-height: 16px; | ||
letter-spacing: 0.25px; | ||
} | ||
} | ||
|
||
.price { | ||
font-size: 14px; | ||
line-height: 18px; | ||
|
||
> strong { | ||
font-weight: bold; | ||
font-size: 24px; | ||
line-height: 26px; | ||
} | ||
} | ||
|
||
.confirmButton { | ||
margin-bottom: 8px; | ||
} |
19 changes: 19 additions & 0 deletions
19
src/components/RenewSubscriptionForm/RenewSubscriptionForm.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
|
||
import customer from '../../fixtures/customer.json'; | ||
import subscription from '../../fixtures/subscription.json'; | ||
import type { Subscription } from '../../../types/subscription'; | ||
import type { Customer } from '../../../types/account'; | ||
|
||
import RenewSubscriptionForm from './RenewSubscriptionForm'; | ||
|
||
describe('<RenewSubscriptionForm>', () => { | ||
test('renders and matches snapshot', () => { | ||
const { container } = render( | ||
<RenewSubscriptionForm customer={customer as Customer} subscription={subscription as Subscription} onConfirm={jest.fn()} onClose={jest.fn()} error={null}/>, | ||
); | ||
|
||
expect(container).toMatchSnapshot(); | ||
}); | ||
}); |
51 changes: 51 additions & 0 deletions
51
src/components/RenewSubscriptionForm/RenewSubscriptionForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
import type { Subscription } from '../../../types/subscription'; | ||
import Button from '../Button/Button'; | ||
import { formatDate, formatPrice } from '../../utils/formatting'; | ||
import type { Customer } from '../../../types/account'; | ||
import FormFeedback from '../FormFeedback/FormFeedback'; | ||
|
||
import styles from './RenewSubscriptionForm.module.scss'; | ||
|
||
type Props = { | ||
subscription: Subscription; | ||
customer: Customer; | ||
error: string | null; | ||
onConfirm: () => void; | ||
onClose: () => void; | ||
}; | ||
|
||
const RenewSubscriptionForm: React.FC<Props> = ({ subscription, customer, error, onConfirm, onClose }: Props) => { | ||
const { t } = useTranslation('account'); | ||
|
||
return ( | ||
<div> | ||
{error ? <FormFeedback variant="error">{error}</FormFeedback> : null} | ||
<h2 className={styles.title}>{t('renew_subscription.renew_your_subscription')}</h2> | ||
<p className={styles.paragraph}>{t('renew_subscription.explanation')}</p> | ||
<div className={styles.infoBox}> | ||
<p> | ||
<strong>{subscription.offerTitle}</strong> <br /> | ||
{t('renew_subscription.next_billing_date_on', { date: formatDate(subscription.expiresAt) })} | ||
</p> | ||
<p className={styles.price}> | ||
<strong>{formatPrice(subscription.nextPaymentPrice, subscription.nextPaymentCurrency, customer.country)}</strong> | ||
<small>/{t(`periods.${subscription.period}`)}</small> | ||
</p> | ||
</div> | ||
<Button | ||
className={styles.confirmButton} | ||
color="primary" | ||
variant="contained" | ||
label={t('renew_subscription.renew_subscription')} | ||
onClick={onConfirm} | ||
fullWidth | ||
/> | ||
<Button label={t('renew_subscription.no_thanks')} onClick={onClose} fullWidth /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default RenewSubscriptionForm; |
55 changes: 55 additions & 0 deletions
55
src/components/RenewSubscriptionForm/__snapshots__/RenewSubscriptionForm.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`<RenewSubscriptionForm> renders and matches snapshot 1`] = ` | ||
<div> | ||
<div> | ||
<h2 | ||
class="title" | ||
> | ||
renew_subscription.renew_your_subscription | ||
</h2> | ||
<p | ||
class="paragraph" | ||
> | ||
renew_subscription.explanation | ||
</p> | ||
<div | ||
class="infoBox" | ||
> | ||
<p> | ||
<strong> | ||
Annual subscription (recurring) | ||
</strong> | ||
<br /> | ||
renew_subscription.next_billing_date_on | ||
</p> | ||
<p | ||
class="price" | ||
> | ||
<strong> | ||
€ 22,15 | ||
</strong> | ||
<small> | ||
/ | ||
periods.year | ||
</small> | ||
</p> | ||
</div> | ||
<button | ||
class="button confirmButton primary fullWidth" | ||
> | ||
<span> | ||
renew_subscription.renew_subscription | ||
</span> | ||
</button> | ||
<button | ||
class="button default outlined fullWidth" | ||
> | ||
<span> | ||
renew_subscription.no_thanks | ||
</span> | ||
</button> | ||
</div> | ||
</div> | ||
`; |
13 changes: 13 additions & 0 deletions
13
src/components/SubscriptionRenewed/SubscriptionRenewed.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@use '../../styles/variables'; | ||
@use '../../styles/theme'; | ||
|
||
.title { | ||
margin-bottom: 16px; | ||
font-family: theme.$body-alt-font-family; | ||
font-weight: 700; | ||
font-size: 24px; | ||
} | ||
|
||
.paragraph { | ||
font-family: theme.$body-font-family; | ||
} |
17 changes: 17 additions & 0 deletions
17
src/components/SubscriptionRenewed/SubscriptionRenewed.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
|
||
import customer from '../../fixtures/customer.json'; | ||
import subscription from '../../fixtures/subscription.json'; | ||
import type { Subscription } from '../../../types/subscription'; | ||
import type { Customer } from '../../../types/account'; | ||
|
||
import SubscriptionRenewed from './SubscriptionRenewed'; | ||
|
||
describe('<SubscriptionRenewed>', () => { | ||
test('renders and matches snapshot', () => { | ||
const { container } = render(<SubscriptionRenewed customer={customer as Customer} subscription={subscription as Subscription} onClose={jest.fn()} />); | ||
|
||
expect(container).toMatchSnapshot(); | ||
}); | ||
}); |
31 changes: 31 additions & 0 deletions
31
src/components/SubscriptionRenewed/SubscriptionRenewed.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
import Button from '../Button/Button'; | ||
import type { Subscription } from '../../../types/subscription'; | ||
import { formatDate, formatPrice } from '../../utils/formatting'; | ||
import type { Customer } from '../../../types/account'; | ||
|
||
import styles from './SubscriptionRenewed.module.scss'; | ||
|
||
type Props = { | ||
customer: Customer; | ||
subscription: Subscription; | ||
onClose: () => void; | ||
}; | ||
|
||
const SubscriptionRenewed: React.FC<Props> = ({ onClose, customer, subscription }: Props) => { | ||
const { t } = useTranslation('account'); | ||
const date = formatDate(subscription.expiresAt); | ||
const price = formatPrice(subscription.nextPaymentPrice, subscription.nextPaymentCurrency, customer.country); | ||
|
||
return ( | ||
<div> | ||
<h2 className={styles.title}>{t('subscription_renewed.title')}</h2> | ||
<p className={styles.paragraph}>{t('subscription_renewed.message', { date, price })}</p> | ||
<Button label={t('subscription_renewed.back_to_profile')} onClick={onClose} fullWidth /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SubscriptionRenewed; |
25 changes: 25 additions & 0 deletions
25
src/components/SubscriptionRenewed/__snapshots__/SubscriptionRenewed.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`<SubscriptionRenewed> renders and matches snapshot 1`] = ` | ||
<div> | ||
<div> | ||
<h2 | ||
class="title" | ||
> | ||
subscription_renewed.title | ||
</h2> | ||
<p | ||
class="paragraph" | ||
> | ||
subscription_renewed.message | ||
</p> | ||
<button | ||
class="button default outlined fullWidth" | ||
> | ||
<span> | ||
subscription_renewed.back_to_profile | ||
</span> | ||
</button> | ||
</div> | ||
</div> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React, { useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { useHistory } from 'react-router'; | ||
|
||
import { removeQueryParam } from '../../../utils/history'; | ||
import LoadingOverlay from '../../../components/LoadingOverlay/LoadingOverlay'; | ||
import { AccountStore, updateSubscription } from '../../../stores/AccountStore'; | ||
import RenewSubscriptionForm from '../../../components/RenewSubscriptionForm/RenewSubscriptionForm'; | ||
import SubscriptionRenewed from '../../../components/SubscriptionRenewed/SubscriptionRenewed'; | ||
|
||
const RenewSubscription = () => { | ||
const { t } = useTranslation('account'); | ||
const history = useHistory(); | ||
const { subscription, user } = AccountStore.useState((s) => s); | ||
const [renewed, setRenewed] = useState(false); | ||
const [loading, setLoading] = useState(false); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
const renewSubscriptionConfirmHandler = async () => { | ||
setLoading(true); | ||
setError(null); | ||
|
||
try { | ||
await updateSubscription('active'); | ||
setRenewed(true); | ||
} catch (error: unknown) { | ||
setError(t('renew_subscription.unknown_error_occurred')); | ||
} | ||
|
||
setLoading(false); | ||
}; | ||
|
||
const closeHandler = () => { | ||
history.replace(removeQueryParam(history, 'u')); | ||
}; | ||
|
||
if (!subscription || !user) return null; | ||
|
||
return ( | ||
<React.Fragment> | ||
{renewed ? ( | ||
<SubscriptionRenewed onClose={closeHandler} subscription={subscription} customer={user} /> | ||
) : ( | ||
<RenewSubscriptionForm subscription={subscription} customer={user} error={error} onConfirm={renewSubscriptionConfirmHandler} onClose={closeHandler} /> | ||
)} | ||
{loading ? <LoadingOverlay inline /> : null} | ||
</React.Fragment> | ||
); | ||
}; | ||
export default RenewSubscription; |
Oops, something went wrong.