From 124306d7ac5742bd581ad201fdc325bad8b69b8c Mon Sep 17 00:00:00 2001 From: Jessica Lawshe Date: Tue, 21 Feb 2023 09:24:49 -0600 Subject: [PATCH] Merge pull request #11819 from overleaf/jel-subscription-dash-change-to-group-prices [web] Show price in change to group plan modal on React subscription dash GitOrigin-RevId: 6a1a4be3a7d008cd9e26186c2d97bc0bdc2f82ed --- package-lock.json | 38 +++- .../web/frontend/extracted-translations.json | 2 + .../dashboard/generic-error-alert.tsx | 18 ++ .../modals/change-to-group-modal.tsx | 97 ++++++++- .../subscription-dashboard-context.tsx | 66 +++++- ...ecurly-loaded.tsx => is-recurly-loaded.ts} | 0 ...recurly-pricing.tsx => recurly-pricing.ts} | 43 +++- services/web/locales/en.json | 2 + services/web/package.json | 1 + .../active/change-plan/change-plan.test.tsx | 157 +++++++++++--- .../features/subscription/fixtures/plans.tsx | 199 ++++++++++++++++++ .../subscription/fixtures/subscriptions.tsx | 77 +++++++ .../helpers/render-active-subscription.tsx | 6 +- .../render-with-subscription-dash-context.tsx | 19 +- services/web/types/subscription/plan.ts | 9 + 15 files changed, 685 insertions(+), 49 deletions(-) create mode 100644 services/web/frontend/js/features/subscription/components/dashboard/generic-error-alert.tsx rename services/web/frontend/js/features/subscription/util/{is-recurly-loaded.tsx => is-recurly-loaded.ts} (100%) rename services/web/frontend/js/features/subscription/util/{recurly-pricing.tsx => recurly-pricing.ts} (61%) diff --git a/package-lock.json b/package-lock.json index 5103f8d50d..c16d16ce08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7441,6 +7441,16 @@ "url-parse": "^1.4.7" } }, + "node_modules/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -8108,6 +8118,15 @@ "@types/node": "*" } }, + "node_modules/@types/bootstrap": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.6.tgz", + "integrity": "sha512-BlAc3YATdasbHoxMoBWODrSF6qwQO/E9X8wVxCCSa6rWjnaZfpkr2N6pUMCY6jj2+wf0muUtLySbvU9etX6YqA==", + "dev": true, + "dependencies": { + "@popperjs/core": "^2.9.2" + } + }, "node_modules/@types/bson": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", @@ -34569,6 +34588,7 @@ "@testing-library/react": "^12.1.5", "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.2.0", + "@types/bootstrap": "^5.2.6", "@types/chai": "^4.3.0", "@types/events": "^3.0.0", "@types/express": "^4.17.13", @@ -43579,6 +43599,7 @@ "@testing-library/react": "^12.1.5", "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.2.0", + "@types/bootstrap": "*", "@types/chai": "^4.3.0", "@types/events": "^3.0.0", "@types/express": "^4.17.13", @@ -43732,7 +43753,7 @@ "passport-local": "^1.0.0", "passport-oauth2": "^1.5.0", "passport-orcid": "0.0.4", - "passport-saml": "3.2.3", + "passport-saml": "^3.2.3", "passport-twitter": "^1.0.4", "pdfjs-dist213": "npm:pdfjs-dist@2.13.216", "pdfjs-dist31": "npm:pdfjs-dist@3.1.81", @@ -45576,6 +45597,12 @@ "url-parse": "^1.4.7" } }, + "@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "dev": true + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -46120,6 +46147,15 @@ "@types/node": "*" } }, + "@types/bootstrap": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.6.tgz", + "integrity": "sha512-BlAc3YATdasbHoxMoBWODrSF6qwQO/E9X8wVxCCSa6rWjnaZfpkr2N6pUMCY6jj2+wf0muUtLySbvU9etX6YqA==", + "dev": true, + "requires": { + "@popperjs/core": "^2.9.2" + } + }, "@types/bson": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index fc82cffcff..8206d91c5e 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -432,6 +432,7 @@ "linked_file": "", "loading": "", "loading_github_repositories": "", + "loading_prices": "", "loading_recent_github_commits": "", "log_entry_description": "", "log_entry_maximum_entries": "", @@ -820,6 +821,7 @@ "toolbar_undo": "", "total_per_month": "", "total_per_year": "", + "total_with_subtotal_and_tax": "", "total_words": "", "track_changes": "", "trash": "", diff --git a/services/web/frontend/js/features/subscription/components/dashboard/generic-error-alert.tsx b/services/web/frontend/js/features/subscription/components/dashboard/generic-error-alert.tsx new file mode 100644 index 0000000000..57921c67c1 --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/dashboard/generic-error-alert.tsx @@ -0,0 +1,18 @@ +import classNames from 'classnames' +import { useTranslation } from 'react-i18next' + +export default function GenericErrorAlert({ + className, +}: { + className?: string +}) { + const { t } = useTranslation() + const alertClassName = classNames('alert', 'alert-danger', className) + + return ( +
+ {t('generic_something_went_wrong')}. {t('try_again')}.{' '} + {t('generic_if_problem_continues_contact_us')}. +
+ ) +} diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx index 4002b72c75..14bee2fb20 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx @@ -3,9 +3,11 @@ import { Modal } from 'react-bootstrap' import { useTranslation, Trans } from 'react-i18next' import { GroupPlans } from '../../../../../../../../../../types/subscription/dashboard/group-plans' import { Subscription } from '../../../../../../../../../../types/subscription/dashboard/subscription' +import { PriceForDisplayData } from '../../../../../../../../../../types/subscription/plan' import AccessibleModal from '../../../../../../../../shared/components/accessible-modal' import getMeta from '../../../../../../../../utils/meta' import { useSubscriptionDashboardContext } from '../../../../../../context/subscription-dashboard-context' +import GenericErrorAlert from '../../../../generic-error-alert' const educationalPercentDiscount = 40 const groupSizeForEducationalDiscount = 10 @@ -53,21 +55,66 @@ function EducationDiscountAppliedOrNot({ groupSize }: { groupSize: string }) { ) } -function GroupPrice() { +function GroupPrice({ + groupPlanToChangeToPrice, + queryingGroupPlanToChangeToPrice, +}: { + groupPlanToChangeToPrice?: PriceForDisplayData + queryingGroupPlanToChangeToPrice: boolean +}) { const { t } = useTranslation() + + const totalPrice = + !queryingGroupPlanToChangeToPrice && + groupPlanToChangeToPrice?.totalForDisplay + ? groupPlanToChangeToPrice.totalForDisplay + : '…' + + const perUserPrice = + !queryingGroupPlanToChangeToPrice && + groupPlanToChangeToPrice?.perUserDisplayPrice + ? groupPlanToChangeToPrice.perUserDisplayPrice + : '…' + return ( <> - X / {t('year')} + {totalPrice} / {t('year')} - {/* TODO: price */} - + {queryingGroupPlanToChangeToPrice ? ( + t('loading_prices') + ) : ( + + )} +
+ - {/* TODO: price */} - + + + + + {queryingGroupPlanToChangeToPrice ? ( + t('loading_prices') + ) : ( + + )} + ) @@ -78,10 +125,13 @@ export function ChangeToGroupModal() { const { t } = useTranslation() const { groupPlanToChangeToCode, + groupPlanToChangeToPrice, + groupPlanToChangeToPriceError, groupPlanToChangeToSize, groupPlanToChangeToUsage, handleCloseModal, modalIdShown, + queryingGroupPlanToChangeToPrice, setGroupPlanToChangeToCode, setGroupPlanToChangeToSize, setGroupPlanToChangeToUsage, @@ -100,8 +150,6 @@ export function ChangeToGroupModal() { function handleGetInTouchButton() { handleCloseModal() - - // @ts-ignore $('[data-ol-contact-form-modal="contact-us"]').modal() } @@ -142,10 +190,16 @@ export function ChangeToGroupModal() {
+ {groupPlanToChangeToPriceError && }
- +

{t('each_user_will_have_access_to')}:

    @@ -257,11 +311,34 @@ export function ChangeToGroupModal() {
    + {groupPlanToChangeToPrice?.includesTax && ( +

    + , + ]} + /> +

    + )}

    {t('new_subscription_will_be_billed_immediately')}


    - +