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')}


    - +