Skip to content

Commit

Permalink
feat: add functionality to open and view invoices
Browse files Browse the repository at this point in the history
chore: pr rework
  • Loading branch information
MelissaDTH authored and ChristiaanScheermeijer committed May 30, 2023
1 parent 2f01739 commit 79b6fc7
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 51 deletions.
9 changes: 9 additions & 0 deletions src/components/Payment/Payment.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
}
}

.transactionDetails {
display: flex;
justify-content: center;
align-items: center;
> div {
margin-left: variables.$base-spacing;
}
}

.price {
font-size: 14px;
line-height: 18px;
Expand Down
9 changes: 1 addition & 8 deletions src/components/Payment/Payment.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,9 @@ import subscription from '#test/fixtures/subscription.json';
import type { Customer } from '#types/account';
import type { PaymentDetail, Subscription, Transaction } from '#types/subscription';
import { renderWithRouter } from '#test/testUtils';
import * as checkoutController from '#src/stores/CheckoutController';

describe('<Payment>', () => {
afterEach(() => {
vi.clearAllMocks();
});

test('renders and matches snapshot', () => {
const spy = vi.spyOn(checkoutController, 'getSubscriptionSwitches');
spy.mockResolvedValue(undefined);

const { container } = renderWithRouter(
<Payment
accessModel="AVOD"
Expand All @@ -31,6 +23,7 @@ describe('<Payment>', () => {
showAllTransactions={false}
isLoading={false}
offerSwitchesAvailable={false}
onShowReceiptClick={vi.fn()}
/>,
);

Expand Down
30 changes: 19 additions & 11 deletions src/components/Payment/Payment.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useEffect } from 'react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';

import useBreakpoint, { Breakpoint } from '../../hooks/useBreakpoint';
import { getSubscriptionSwitches } from '../../stores/CheckoutController';
import IconButton from '../IconButton/IconButton';
import ExternalLink from '../../icons/ExternalLink';

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

Expand All @@ -27,13 +28,15 @@ type Props = {
customer: Customer;
isLoading: boolean;
offerSwitchesAvailable: boolean;
onShowReceiptClick: (transactionId: string) => void;
panelClassName?: string;
panelHeaderClassName?: string;
onShowAllTransactionsClick?: () => void;
onUpgradeSubscriptionClick?: () => void;
showAllTransactions: boolean;
canUpdatePaymentMethod: boolean;
canRenewSubscription?: boolean;
canShowReceipts?: boolean;
};

const Payment = ({
Expand All @@ -47,7 +50,9 @@ const Payment = ({
panelHeaderClassName,
onShowAllTransactionsClick,
showAllTransactions,
onShowReceiptClick,
canRenewSubscription = false,
canShowReceipts = false,
canUpdatePaymentMethod,
onUpgradeSubscriptionClick,
offerSwitchesAvailable,
Expand Down Expand Up @@ -90,10 +95,6 @@ const Payment = ({
}
}

useEffect(() => {
getSubscriptionSwitches();
}, []);

return (
<>
{accessModel === 'SVOD' && (
Expand Down Expand Up @@ -188,11 +189,18 @@ const Payment = ({
method: transaction.paymentMethod,
})}
</p>
<p>
{transaction.transactionId}
<br />
{formatDate(transaction.transactionDate)}
</p>
<div className={styles.transactionDetails}>
<p>
{transaction.transactionId}
<br />
{formatDate(transaction.transactionDate)}
</p>
{canShowReceipts && (
<IconButton aria-label={t('user:payment.show_receipt')} onClick={() => !isLoading && onShowReceiptClick(transaction.transactionId)}>
<ExternalLink />
</IconButton>
)}
</div>
</div>
))}
{!showAllTransactions && hasMoreTransactions ? (
Expand Down
42 changes: 27 additions & 15 deletions src/components/Payment/__snapshots__/Payment.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,15 @@ exports[`<Payment> > renders and matches snapshot 1`] = `
<br />
user:payment.price_payed_with
</p>
<p>
T712014024
<br />
5/5/2021
</p>
<div
class="_transactionDetails_c57ff5"
>
<p>
T712014024
<br />
5/5/2021
</p>
</div>
</div>
<div
class="_infoBox_c57ff5"
Expand All @@ -92,11 +96,15 @@ exports[`<Payment> > renders and matches snapshot 1`] = `
<br />
user:payment.price_payed_with
</p>
<p>
T177974068
<br />
5/5/2021
</p>
<div
class="_transactionDetails_c57ff5"
>
<p>
T177974068
<br />
5/5/2021
</p>
</div>
</div>
<div
class="_infoBox_c57ff5"
Expand All @@ -111,11 +119,15 @@ exports[`<Payment> > renders and matches snapshot 1`] = `
<br />
user:payment.price_payed_with
</p>
<p>
T996601696
<br />
5/5/2021
</p>
<div
class="_transactionDetails_c57ff5"
>
<p>
T996601696
<br />
5/5/2021
</p>
</div>
</div>
</div>
</div>
Expand Down
10 changes: 10 additions & 0 deletions src/icons/ExternalLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

import createIcon from './Icon';

export default createIcon(
'0 0 24 24',
<g>
<path d="M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z" />
</g>,
);
44 changes: 39 additions & 5 deletions src/pages/User/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-
import { useTranslation } from 'react-i18next';
import shallow from 'zustand/shallow';

import { useCheckoutStore } from '../../stores/CheckoutStore';
import { addQueryParam } from '../../utils/location';

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

import PlaylistContainer from '#src/containers/PlaylistContainer/PlaylistContainer';
Expand All @@ -24,8 +21,11 @@ import AccountComponent from '#components/Account/Account';
import Button from '#components/Button/Button';
import Favorites from '#components/Favorites/Favorites';
import type { PlaylistItem } from '#types/playlist';
import { logout } from '#src/stores/AccountController';
import { getReceipt, logout } from '#src/stores/AccountController';
import { clear as clearFavorites } from '#src/stores/FavoritesController';
import { getSubscriptionSwitches } from '#src/stores/CheckoutController';
import { useCheckoutStore } from '#src/stores/CheckoutStore';
import { addQueryParam } from '#src/utils/location';

const User = (): JSX.Element => {
const { accessModel, favoritesList } = useConfigStore(
Expand All @@ -40,6 +40,8 @@ const User = (): JSX.Element => {
const breakpoint = useBreakpoint();
const [clearFavoritesOpen, setClearFavoritesOpen] = useState(false);
const [showAllTransactions, setShowAllTransactions] = useState(false);
const [isLoadingReceipt, setIsLoadingReceipt] = useState(false);

const isLargeScreen = breakpoint > Breakpoint.md;
const {
user: customer,
Expand All @@ -50,6 +52,7 @@ const User = (): JSX.Element => {
canUpdateEmail,
canRenewSubscription,
canUpdatePaymentMethod,
canShowReceipts,
} = useAccountStore();
const offerSwitches = useCheckoutStore((state) => state.offerSwitches);
const location = useLocation();
Expand All @@ -64,6 +67,35 @@ const User = (): JSX.Element => {
navigate(addQueryParam(location, 'u', 'upgrade-subscription'));
};

const handleShowReceiptClick = async (transactionId: string) => {
setIsLoadingReceipt(true);

try {
const receipt = await getReceipt(transactionId);

if (receipt) {
const newWindow = window.open('', `Receipt ${transactionId}`, '');
const htmlString = window.atob(receipt);

if (newWindow) {
newWindow.opener = null;
newWindow.document.write(htmlString);
newWindow.document.close();
}
}
} catch (error: unknown) {
throw new Error("Couldn't parse receipt. " + (error instanceof Error ? error.message : ''));
}

setIsLoadingReceipt(false);
};

useEffect(() => {
if (accessModel !== 'AVOD') {
getSubscriptionSwitches();
}
}, [accessModel]);

useEffect(() => {
if (!loading && !customer) {
navigate('/', { replace: true });
Expand Down Expand Up @@ -152,7 +184,7 @@ const User = (): JSX.Element => {
activePaymentDetail={activePayment}
transactions={transactions}
customer={customer}
isLoading={loading}
isLoading={loading || isLoadingReceipt}
panelClassName={styles.panel}
panelHeaderClassName={styles.panelHeader}
onShowAllTransactionsClick={() => setShowAllTransactions(true)}
Expand All @@ -161,6 +193,8 @@ const User = (): JSX.Element => {
canRenewSubscription={canRenewSubscription}
onUpgradeSubscriptionClick={handleUpgradeSubscriptionClick}
offerSwitchesAvailable={!!offerSwitches.length}
canShowReceipts={canShowReceipts}
onShowReceiptClick={handleShowReceiptClick}
/>
) : (
<Navigate to="my-account" />
Expand Down
28 changes: 18 additions & 10 deletions src/pages/User/__snapshots__/User.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -743,11 +743,15 @@ exports[`User Component tests > Payments Page 1`] = `
<br />
user:payment.price_payed_with
</p>
<p>
11232
<br />
7/16/2022
</p>
<div
class="_transactionDetails_c57ff5"
>
<p>
11232
<br />
7/16/2022
</p>
</div>
</div>
<div
class="_infoBox_c57ff5"
Expand All @@ -762,11 +766,15 @@ exports[`User Component tests > Payments Page 1`] = `
<br />
user:payment.price_payed_with
</p>
<p>
11234
<br />
11/9/2022
</p>
<div
class="_transactionDetails_c57ff5"
>
<p>
11234
<br />
11/9/2022
</p>
</div>
</div>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/services/cleeng.account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,5 @@ export const canRenewSubscription = true;
export const canExportAccountData = false;

export const canUpdatePaymentMethod = true;

export const canShowReceipts = true;
6 changes: 5 additions & 1 deletion src/services/cleeng.subscription.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { patch, get } from './cleeng.service';

import { addQueryParams } from '#src/utils/formatting';
import type { GetPaymentDetails, GetSubscriptions, GetTransactions, UpdateSubscription } from '#types/subscription';
import type { FetchReceipt, GetPaymentDetails, GetSubscriptions, GetTransactions, UpdateSubscription } from '#types/subscription';

export async function getActiveSubscription({ sandbox, customerId, jwt }: { sandbox: boolean; customerId: string; jwt: string }) {
const response = await getSubscriptions({ customerId }, sandbox, jwt);
Expand Down Expand Up @@ -42,3 +42,7 @@ export const getPaymentDetails: GetPaymentDetails = async (payload, sandbox, jwt
export const getTransactions: GetTransactions = async ({ customerId, limit, offset }, sandbox, jwt) => {
return get(sandbox, addQueryParams(`/customers/${customerId}/transactions`, { limit, offset }), jwt);
};

export const fetchReceipt: FetchReceipt = async ({ transactionId }, sandbox, jwt) => {
return get(sandbox, `/receipt/${transactionId}`, jwt);
};
2 changes: 2 additions & 0 deletions src/services/inplayer.account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,5 @@ export const canRenewSubscription = false;
export const canExportAccountData = true;

export const canUpdatePaymentMethod = false;

export const canShowReceipts = false;
22 changes: 21 additions & 1 deletion src/stores/AccountController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const initializeAccount = async () => {
canUpdatePaymentMethod: accountService.canUpdatePaymentMethod,
canChangePasswordWithOldPassword: accountService.canChangePasswordWithOldPassword,
canExportAccountData: accountService.canExportAccountData,
canShowReceipts: accountService.canShowReceipts,
});
accountService.setEnvironment(config);

Expand Down Expand Up @@ -368,7 +369,14 @@ export const resetPassword = async (email: string, resetUrl: string) => {

export const changePasswordWithOldPassword = async (oldPassword: string, newPassword: string, newPasswordConfirmation: string) => {
return await useService(async ({ accountService, sandbox = true }) => {
const response = await accountService.changePasswordWithOldPassword({ oldPassword, newPassword, newPasswordConfirmation }, sandbox);
const response = await accountService.changePasswordWithOldPassword(
{
oldPassword,
newPassword,
newPasswordConfirmation,
},
sandbox,
);
if (response?.errors?.length > 0) throw new Error(response.errors[0]);

return response?.responseData;
Expand Down Expand Up @@ -470,6 +478,18 @@ export async function exportAccountData() {
});
}

export const getReceipt = async (transactionId: string) => {
return await useAccount(async ({ auth: { jwt } }) => {
return await useService(async ({ subscriptionService, sandbox = true }) => {
if (!subscriptionService || !('fetchReceipt' in subscriptionService)) return null;

const { responseData } = await subscriptionService.fetchReceipt({ transactionId }, sandbox, jwt);

return responseData;
});
});
};

/**
* Get multiple media items for the given IDs. This function uses watchlists to get several medias via just one request.
*
Expand Down
Loading

0 comments on commit 79b6fc7

Please sign in to comment.