1- import React from 'react' ;
1+ import React , { useContext } from 'react' ;
22import PropTypes from 'prop-types' ;
3+ import { connect } from 'react-redux' ;
34import dayjs from 'dayjs' ;
45import { Link } from 'react-router-dom' ;
56import {
6- Card , Badge , Button , Stack , Row , Col ,
7+ Badge , Button , Card , Col , Hyperlink , Row , Stack ,
78} from '@openedx/paragon' ;
9+ import { FormattedMessage , getLocale } from '@edx/frontend-platform/i18n' ;
810
911import classNames from 'classnames' ;
10- import { getSubscriptionStatus } from './data/utils' ;
11- import { ACTIVE , SCHEDULED , SUBSCRIPTION_STATUS_BADGE_MAP } from './data/constants' ;
12+ import {
13+ ACTIVE , FREE_TRIAL_BADGE , TRIAL , SCHEDULED , SUBSCRIPTION_STATUS_BADGE_MAP , ENDED ,
14+ } from './data/constants' ;
15+ import { useUpcomingInvoiceAmount } from './data/hooks' ;
16+ import { SubscriptionContext } from './SubscriptionData' ;
1217import { ADMINISTER_SUBSCRIPTIONS_TARGETS } from '../ProductTours/AdminOnboardingTours/constants' ;
18+ import { makePlural } from '../../utils' ;
19+ import { getSubscriptionStatus , openStripeBillingPortal } from './data/utils' ;
1320
1421const SubscriptionCard = ( {
22+ enterpriseUuid,
1523 subscription,
1624 createActions,
1725} ) => {
1826 const {
19- title,
20- startDate,
2127 expirationDate,
2228 licenses = { } ,
29+ planType,
30+ startDate,
31+ title,
32+ uuid : subPlanUuid ,
2333 } = subscription ;
24-
34+ const { setErrors } = useContext ( SubscriptionContext ) ;
35+ const { invoiceAmount, currency, loadingStripeSummary } = useUpcomingInvoiceAmount (
36+ { subPlanUuid, planType, setErrors } ,
37+ ) ;
2538 const formattedStartDate = dayjs ( startDate ) . format ( 'MMMM D, YYYY' ) ;
2639 const formattedExpirationDate = dayjs ( expirationDate ) . format ( 'MMMM D, YYYY' ) ;
2740 const subscriptionStatus = getSubscriptionStatus ( subscription ) ;
2841
42+ let subscriptionUpcomingPrice ;
43+ if ( ! loadingStripeSummary ) {
44+ const locale = getLocale ( ) ;
45+ subscriptionUpcomingPrice = `${ invoiceAmount . toLocaleString ( locale , { style : 'currency' , currency, maximumFractionDigits : 0 } ) } ${ currency . toUpperCase ( ) } ` ;
46+ }
47+
2948 const renderDaysUntilPlanStartText = ( className ) => {
3049 if ( ! ( subscriptionStatus === SCHEDULED ) ) {
3150 return null ;
@@ -39,8 +58,8 @@ const SubscriptionCard = ({
3958 return (
4059 < span className = { classNames ( 'd-block small' , className ) } >
4160 Plan begins in {
42- daysUntilPlanStart > 0 ? `${ daysUntilPlanStart } day${ daysUntilPlanStart > 1 ? 's' : '' } `
43- : `${ hoursUntilPlanStart } hour${ hoursUntilPlanStart > 1 ? 's' : '' } `
61+ daysUntilPlanStart > 0 ? `${ makePlural ( daysUntilPlanStart , ' day' ) } `
62+ : `${ makePlural ( hoursUntilPlanStart , ' hour' ) } `
4463 }
4564 </ span >
4665 ) ;
@@ -69,14 +88,41 @@ const SubscriptionCard = ({
6988 const renderCardHeader = ( ) => {
7089 const subtitle = (
7190 < div className = "d-flex flex-wrap align-items-center" >
72- < Stack direction = "horizontal" gap = { 3 } >
73- < Badge variant = { SUBSCRIPTION_STATUS_BADGE_MAP [ subscriptionStatus ] . variant } >
74- { subscriptionStatus }
75- </ Badge >
91+ < Badge className = "mr-2" variant = { SUBSCRIPTION_STATUS_BADGE_MAP [ subscriptionStatus ] . variant } >
92+ { subscriptionStatus }
93+ </ Badge >
94+ { planType === TRIAL && (
95+ < >
96+ < Badge className = "mr-2" variant = "info" >
97+ { FREE_TRIAL_BADGE }
98+ </ Badge >
99+ { ! ( subscriptionStatus === ENDED ) && (
100+ < FormattedMessage
101+ id = "subscriptions.subscriptionCard.freeTrialDescription"
102+ defaultMessage = "Your 14-day free trial will conclude on {boldDate}. Your paid subscription will automatically start, and the {subscriptionUpcomingPrice} subscription fee will be charged to the card on file. {stripeLink}"
103+ description = "Message shown to warn customers with a free trial that they will be charged for the full subscription"
104+ values = { {
105+ boldDate : < span className = "ml-1 font-weight-bold" > { formattedExpirationDate } </ span > ,
106+ subscriptionUpcomingPrice : < span className = "ml-1 font-weight-bold" > { subscriptionUpcomingPrice } </ span > ,
107+ stripeLink : (
108+ < Hyperlink
109+ className = "ml-2"
110+ target = "_blank"
111+ rel = "noopener noreferrer"
112+ onClick = { ( ) => ( openStripeBillingPortal ( enterpriseUuid ) ) }
113+ >
114+ Manage subscription
115+ </ Hyperlink > ) ,
116+ } }
117+ />
118+ ) }
119+ </ >
120+ ) }
121+ { planType !== TRIAL && (
76122 < span >
77123 { formattedStartDate } - { formattedExpirationDate }
78124 </ span >
79- </ Stack >
125+ ) }
80126 </ div >
81127 ) ;
82128
@@ -89,7 +135,8 @@ const SubscriptionCard = ({
89135 subtitle = { subtitle }
90136 actions = { (
91137 < div >
92- { renderActions ( ) || renderDaysUntilPlanStartText ( 'mt-4' ) }
138+ { renderActions ( ) }
139+ { renderDaysUntilPlanStartText ( 'mt-4' ) }
93140 </ div >
94141 ) }
95142 />
@@ -135,24 +182,31 @@ const SubscriptionCard = ({
135182 ) ;
136183} ;
137184
185+ const mapStateToProps = state => ( {
186+ enterpriseUuid : state . portalConfiguration . enterpriseId ,
187+ } ) ;
188+
138189SubscriptionCard . defaultProps = {
139190 createActions : null ,
140191} ;
141192
142193SubscriptionCard . propTypes = {
194+ enterpriseUuid : PropTypes . string . isRequired ,
143195 subscription : PropTypes . shape ( {
144- startDate : PropTypes . string . isRequired ,
145196 expirationDate : PropTypes . string . isRequired ,
146- title : PropTypes . string . isRequired ,
147197 licenses : PropTypes . shape ( {
148198 assigned : PropTypes . number . isRequired ,
149199 activated : PropTypes . number . isRequired ,
150200 allocated : PropTypes . number . isRequired ,
151201 unassigned : PropTypes . number . isRequired ,
152202 total : PropTypes . number . isRequired ,
153203 } ) ,
204+ planType : PropTypes . string . isRequired ,
205+ startDate : PropTypes . string . isRequired ,
206+ title : PropTypes . string . isRequired ,
207+ uuid : PropTypes . string . isRequired ,
154208 } ) . isRequired ,
155209 createActions : PropTypes . func ,
156210} ;
157211
158- export default SubscriptionCard ;
212+ export default connect ( mapStateToProps ) ( SubscriptionCard ) ;
0 commit comments