Skip to content

Commit

Permalink
Merge pull request #43473 from pasyukevich/feature/card-billing-banne…
Browse files Browse the repository at this point in the history
…r-api-integration
  • Loading branch information
blimpich authored Jun 21, 2024
2 parents 50f1822 + 134e433 commit 9817d3c
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3236,7 +3236,7 @@ export default {
title: 'Payment',
subtitle: 'Add a payment card to pay for your Expensify subscription.',
addCardButton: 'Add payment card',
cardNextPayment: 'Your next payment date is',
cardNextPayment: ({nextPaymentDate}) => `Your next payment date is ${nextPaymentDate}.`,
cardEnding: ({cardNumber}) => `Card ending in ${cardNumber}`,
cardInfo: ({name, expiration, currency}) => `Name: ${name}, Expiration: ${expiration}, Currency: ${currency}`,
changeCard: 'Change payment card',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3740,7 +3740,7 @@ export default {
title: 'Pago',
subtitle: 'Añade una tarjeta de pago para abonar tu suscripción a Expensify',
addCardButton: 'Añade tarjeta de pago',
cardNextPayment: 'Your next payment date is',
cardNextPayment: ({nextPaymentDate}) => `Tu próxima fecha de pago es ${nextPaymentDate}.`,
cardEnding: ({cardNumber}) => `Tarjeta terminada en ${cardNumber}`,
cardInfo: ({name, expiration, currency}) => `Nombre: ${name}, Expiración: ${expiration}, Moneda: ${currency}`,
changeCard: 'Cambiar tarjeta de pago',
Expand Down
7 changes: 6 additions & 1 deletion src/pages/settings/Subscription/CardSection/CardSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,28 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import PreTrialBillingBanner from './BillingBanner/PreTrialBillingBanner';
import CardSectionActions from './CardSectionActions';
import CardSectionDataEmpty from './CardSectionDataEmpty';
import CardSectionUtils from './utils';

function CardSection() {
const {translate, preferredLocale} = useLocalize();
const styles = useThemeStyles();
const theme = useTheme();
const [fundList] = useOnyx(ONYXKEYS.FUND_LIST);
const [privateSubscription] = useOnyx(ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION);

const defaultCard = useMemo(() => Object.values(fundList ?? {}).find((card) => card.isDefault), [fundList]);

const cardMonth = useMemo(() => DateUtils.getMonthNames(preferredLocale)[(defaultCard?.accountData?.cardMonth ?? 1) - 1], [defaultCard?.accountData?.cardMonth, preferredLocale]);

const nextPaymentDate = !isEmptyObject(privateSubscription) ? CardSectionUtils.getNextBillingDate() : undefined;

const sectionSubtitle = defaultCard && !!nextPaymentDate ? translate('subscription.cardSection.cardNextPayment', {nextPaymentDate}) : translate('subscription.cardSection.subtitle');
const BillingBanner = <PreTrialBillingBanner />;

return (
<Section
title={translate('subscription.cardSection.title')}
subtitle={translate('subscription.cardSection.subtitle')}
subtitle={sectionSubtitle}
isCentralPane
titleStyles={styles.textStrong}
subtitleMuted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import ThreeDotsMenu from '@components/ThreeDotsMenu';
import type ThreeDotsMenuProps from '@components/ThreeDotsMenu/types';
import useLocalize from '@hooks/useLocalize';
import useWindowDimensions from '@hooks/useWindowDimensions';
import Navigation from '@navigation/Navigation';
import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';

const anchorAlignment = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
Expand All @@ -24,12 +26,12 @@ function CardSectionActions() {
{
icon: Expensicons.CreditCard,
text: translate('subscription.cardSection.changeCard'),
onSelected: () => {}, // TODO: update with navigation to "add card" screen (https://github.com/Expensify/App/issues/38621)
onSelected: () => Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION_ADD_PAYMENT_CARD),
},
{
icon: Expensicons.MoneyCircle,
text: translate('subscription.cardSection.changeCurrency'),
onSelected: () => {}, // TODO: update with navigation to "change currency" screen (https://github.com/Expensify/App/issues/38621)
onSelected: () => {}, // TODO: update with navigation to "change currency" screen (https://github.com/Expensify/App/issues/38629)
},
],
[translate],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import Button from '@components/Button';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@navigation/Navigation';
import ROUTES from '@src/ROUTES';

function CardSectionDataEmpty() {
const {translate} = useLocalize();
Expand All @@ -10,7 +12,7 @@ function CardSectionDataEmpty() {
return (
<Button
text={translate('subscription.cardSection.addCardButton')}
onPress={() => {}} // TODO: update with navigation to "add card" screen (https://github.com/Expensify/App/issues/38621)
onPress={() => Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION_ADD_PAYMENT_CARD)}
style={styles.w100}
success
large
Expand Down
16 changes: 16 additions & 0 deletions src/pages/settings/Subscription/CardSection/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import {addMonths, format, startOfMonth} from 'date-fns';
import * as SubscriptionUtils from '@libs/SubscriptionUtils';
import CONST from '@src/CONST';

/**
* Get the next billing date.
*
* @returns - The next billing date in 'yyyy-MM-dd' format.
*/
function getNextBillingDate(): string {
const today = new Date();

const nextBillingDate = startOfMonth(addMonths(today, 1));

return format(nextBillingDate, CONST.DATE.MONTH_DAY_YEAR_FORMAT);
}

function shouldShowPreTrialBillingBanner(): boolean {
return !SubscriptionUtils.isUserOnFreeTrial() && !SubscriptionUtils.hasUserFreeTrialEnded();
}

export default {
shouldShowPreTrialBillingBanner,
getNextBillingDate,
};
37 changes: 37 additions & 0 deletions tests/unit/CardsSectionUtilsTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import CardSectionUtils from '@src/pages/settings/Subscription/CardSection/utils';

describe('getNextBillingDate', () => {
beforeAll(() => {
jest.useFakeTimers();
// Month is zero indexed, so this is July 5th 2024
jest.setSystemTime(new Date(2024, 6, 5));
});

afterAll(() => {
jest.useRealTimers();
});

it('should return the next billing date when initial date is valid', () => {
const expectedNextBillingDate = 'August 1, 2024';

expect(CardSectionUtils.getNextBillingDate()).toEqual(expectedNextBillingDate);
});

it('should handle end-of-month edge cases correctly', () => {
const nextBillingDate = CardSectionUtils.getNextBillingDate();
const expectedNextBillingDate = 'August 1, 2024';
expect(nextBillingDate).toBe(expectedNextBillingDate);
});

it('should handle date when it at the current month', () => {
const nextBillingDate = CardSectionUtils.getNextBillingDate();
const expectedNextBillingDate = 'August 1, 2024';
expect(nextBillingDate).toBe(expectedNextBillingDate);
});

it('should return the next billing date when initial date is invalid', () => {
const expectedNextBillingDate = 'August 1, 2024';

expect(CardSectionUtils.getNextBillingDate()).toEqual(expectedNextBillingDate);
});
});

0 comments on commit 9817d3c

Please sign in to comment.