diff --git a/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.test.tsx b/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.test.tsx index e8f2f4802e3..658dd460bc4 100644 --- a/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.test.tsx +++ b/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.test.tsx @@ -260,7 +260,7 @@ describe('CancelSubscriptionPanel', () => { ); expect(queryByText('$20.00 fooly')).toBeInTheDocument(); - expect(queryByText('quuz 09/13/2019')).toBeInTheDocument(); + expect(queryByText('quuz 13/09/2019')).toBeInTheDocument(); expect(queryByText('blee')).toBeInTheDocument(); }); @@ -311,7 +311,7 @@ describe('CancelSubscriptionPanel', () => { '$20.00 + $3.00 tax fooly' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $5.00 + $1.23 taxes is due due 09/13/2019' + 'Your next bill of $5.00 + $1.23 taxes is due due 13/09/2019' ); expect(queryByText('blee')).toBeInTheDocument(); }); @@ -342,7 +342,7 @@ describe('CancelSubscriptionPanel', () => { '$20.00 + $3.00 tax barly 8 24hrs' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $5.00 + $1.23 taxes is due due 08/14/2019' + 'Your next bill of $5.00 + $1.23 taxes is due due 14/08/2019' ); }); @@ -371,7 +371,7 @@ describe('CancelSubscriptionPanel', () => { '$19.50 + $3.00 tax barly 8 24hrs' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $4.50 + $1.23 taxes is due due 08/14/2019' + 'Your next bill of $4.50 + $1.23 taxes is due due 14/08/2019' ); }); @@ -385,6 +385,7 @@ describe('CancelSubscriptionPanel', () => { 'payment-cancel-btn = blee', `price-details-tax = { $priceAmount } + { $taxAmount } taxes`, `sub-next-bill-tax = Your next bill of { $priceAmount } + { $taxAmount } taxes is due due { $date }`, + `sub-next-bill-no-tax = Your next bill of { $priceAmount } prices is due due { $date }`, ].forEach((x) => bundle.addResource(new FluentResource(x))); const plan = findMockPlan('plan_daily'); render( @@ -404,7 +405,7 @@ describe('CancelSubscriptionPanel', () => { '$20.00 daily' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $5.00 is due 09/13/2019' + 'Your next bill of $5.00 prices is due due 13/09/2019' ); expect(queryByText('blee')).toBeInTheDocument(); }); @@ -437,7 +438,7 @@ describe('CancelSubscriptionPanel', () => { '$20.00 fooly' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $5.00 prices is due due 09/13/2019' + 'Your next bill of $5.00 prices is due due 13/09/2019' ); expect(queryByText('blee')).toBeInTheDocument(); }); @@ -467,7 +468,7 @@ describe('CancelSubscriptionPanel', () => { '$20.00 barly 8 24hrs' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $5.00 prices is due due 08/14/2019' + 'Your next bill of $5.00 prices is due due 14/08/2019' ); }); @@ -496,7 +497,7 @@ describe('CancelSubscriptionPanel', () => { '$19.50 barly 8 24hrs' ); expect(queryByTestId('sub-next-bill')).toHaveTextContent( - 'Your next bill of $4.50 prices is due due 08/14/2019' + 'Your next bill of $4.50 prices is due due 14/08/2019' ); }); diff --git a/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.tsx b/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.tsx index 6fadd339e41..cc365c26102 100644 --- a/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.tsx +++ b/packages/fxa-payments-server/src/routes/Subscriptions/Cancel/CancelSubscriptionPanel.tsx @@ -73,7 +73,7 @@ const getNextBillData = ( const nextBillDate = getLocalizedDateString(subsequentInvoiceDate, true); const nextBillL10nVarsDefault = { priceAmount: getLocalizedCurrency(invoiceDisplayTotal, plan.currency), - date: nextBillDate, + date: getLocalizedDate(subsequentInvoiceDate, true), }; const nextBillL10nVars = showInvoiceTax ? { diff --git a/packages/fxa-payments-server/src/routes/Subscriptions/SubscriptionIapItem/SubscriptionIapItem.tsx b/packages/fxa-payments-server/src/routes/Subscriptions/SubscriptionIapItem/SubscriptionIapItem.tsx index 5f0a42b6e1d..91e0d04d0ad 100644 --- a/packages/fxa-payments-server/src/routes/Subscriptions/SubscriptionIapItem/SubscriptionIapItem.tsx +++ b/packages/fxa-payments-server/src/routes/Subscriptions/SubscriptionIapItem/SubscriptionIapItem.tsx @@ -18,6 +18,7 @@ import { } from 'fxa-shared/subscriptions/type-guards'; import { getIapSubscriptionManagementUrl, + getLocalizedDate, getLocalizedDateString, } from '../../../lib/formats'; @@ -48,6 +49,7 @@ const GooglePlaySubscriptionIapItem = ( const { auto_renewing, expiry_time_millis } = customerSubscription; const nextBillDate = getLocalizedDateString(expiry_time_millis / 1000, true); + const nextBillDateL10n = getLocalizedDate(expiry_time_millis / 1000, true); const nextBill = `Next billed on ${nextBillDate}`; const expiresOn = `Expires on ${nextBillDate}`; @@ -65,17 +67,11 @@ const GooglePlaySubscriptionIapItem = (
Google: In-App purchase
{auto_renewing ? ( - +
{nextBill}
) : ( - +
{expiresOn}
)} @@ -103,10 +99,11 @@ const AppleSubscriptionIapItem = ( ) => { const { auto_renewing, expiry_time_millis } = customerSubscription; - let nextBill, expiresOn, nextBillDate; + let nextBill, expiresOn, nextBillDate, nextBillDateL10n; // TODO - Remove expiry_time_millis check pending https://developer.apple.com/forums/thread/705730 if (expiry_time_millis) { nextBillDate = getLocalizedDateString(expiry_time_millis / 1000, true); + nextBillDateL10n = getLocalizedDate(expiry_time_millis / 1000, true); nextBill = `Next billed on ${nextBillDate}`; expiresOn = `Expires on ${nextBillDate}`; } @@ -126,16 +123,13 @@ const AppleSubscriptionIapItem = (
{!!expiry_time_millis && (auto_renewing ? ( - +
{nextBill}
) : (
{expiresOn}
diff --git a/packages/fxa-react/lib/utils.tsx b/packages/fxa-react/lib/utils.tsx index a691fdbeda7..650ab874a25 100644 --- a/packages/fxa-react/lib/utils.tsx +++ b/packages/fxa-react/lib/utils.tsx @@ -2,15 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { FluentBundle, FluentVariable } from '@fluent/bundle'; +import { FluentBundle, FluentDateTime, FluentVariable } from '@fluent/bundle'; import { Message, Pattern } from '@fluent/bundle/esm/ast'; import { Localized, LocalizedProps, ReactLocalization } from '@fluent/react'; import React from 'react'; -export type FtlMsgProps = { - children: React.ReactNode; -} & LocalizedProps; - // Going from react page to non-react page requires a hard navigate. This temporary // function is an easy way to reference what needs updating when applicable flows have // been fully converted - we should remove references to this function as we go and use @@ -19,6 +15,51 @@ export function hardNavigateToContentServer(href: string) { window.location.href = href; } +export enum LocalizedDateOptions { + NumericDate, + NumericDateAndTime, +} + +/** + * This method is used to provide Fluent with a localizable value that can be formatted per .ftl file based on localization requirements + * + * @param milliseconds + * @param numericDate + */ +export const getLocalizedDate = ( + milliseconds: number, + dateOptions: LocalizedDateOptions +): FluentDateTime => { + let options: Intl.DateTimeFormatOptions | undefined; + + switch (dateOptions) { + case LocalizedDateOptions.NumericDate: + options = { + day: 'numeric', + month: 'numeric', + year: 'numeric', + }; + break; + case LocalizedDateOptions.NumericDateAndTime: + options = { + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + }; + break; + default: + options = undefined; + } + + return new FluentDateTime(milliseconds, options); +}; + +export type FtlMsgProps = { + children: React.ReactNode; +} & LocalizedProps; + export const FtlMsg = (props: FtlMsgProps) => ( {props.children} ); diff --git a/packages/fxa-settings/src/components/Settings/PageRecentActivity/SecurityEvent.tsx b/packages/fxa-settings/src/components/Settings/PageRecentActivity/SecurityEvent.tsx index 7ae461b29bd..9095c416de8 100644 --- a/packages/fxa-settings/src/components/Settings/PageRecentActivity/SecurityEvent.tsx +++ b/packages/fxa-settings/src/components/Settings/PageRecentActivity/SecurityEvent.tsx @@ -3,7 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import React from 'react'; -import { FtlMsg } from 'fxa-react/lib/utils'; +import { + FtlMsg, + LocalizedDateOptions, + getLocalizedDate, +} from 'fxa-react/lib/utils'; enum SecurityEventName { Create = 'account.create', @@ -77,12 +81,22 @@ export function SecurityEvent({ minute: 'numeric', }).format(new Date(createdAt)); + const createdAtDateFluent = getLocalizedDate( + createdAt, + LocalizedDateOptions.NumericDateAndTime + ); + const l10nName = getSecurityEventNameL10n(name); return (
  • - {createdAtDateText} + + {createdAtDateText} +

    diff --git a/packages/fxa-settings/src/components/Settings/PageRecentActivity/en.ftl b/packages/fxa-settings/src/components/Settings/PageRecentActivity/en.ftl index befe2bbd68d..c581c822066 100644 --- a/packages/fxa-settings/src/components/Settings/PageRecentActivity/en.ftl +++ b/packages/fxa-settings/src/components/Settings/PageRecentActivity/en.ftl @@ -9,3 +9,5 @@ recent-activity-account-login = Account initiated login recent-activity-account-reset = Account initiated password reset recent-activity-emails-clearBounces = Account cleared email bounces +## $date (Date) - Date recent activity was created +recent-activity-created-at = from here { $date } diff --git a/packages/fxa-settings/src/components/Settings/Security/index.tsx b/packages/fxa-settings/src/components/Settings/Security/index.tsx index 050b721aaf4..63094a0a2ea 100644 --- a/packages/fxa-settings/src/components/Settings/Security/index.tsx +++ b/packages/fxa-settings/src/components/Settings/Security/index.tsx @@ -8,7 +8,11 @@ import UnitRowRecoveryKey from '../UnitRowRecoveryKey'; import UnitRowTwoStepAuth from '../UnitRowTwoStepAuth'; import { UnitRow } from '../UnitRow'; import { useAccount } from '../../../models'; -import { FtlMsg } from 'fxa-react/lib/utils'; +import { + FtlMsg, + getLocalizedDate, + LocalizedDateOptions, +} from 'fxa-react/lib/utils'; import { Link } from '@reach/router'; const PwdDate = ({ passwordCreated }: { passwordCreated: number }) => { @@ -18,8 +22,13 @@ const PwdDate = ({ passwordCreated }: { passwordCreated: number }) => { day: 'numeric', }).format(new Date(passwordCreated)); + const pwdDateFluent = getLocalizedDate( + passwordCreated, + LocalizedDateOptions.NumericDate + ); + return ( - +

    Created {pwdDateText}