- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494
- 495
- 496
- 497
- 498
- 499
- 500
- 501
- 502
- 503
- 504
- 505
- 506
- 507
- 508
- 509
- 510
- 511
- 512
- 513
- 514
- 515
- 516
- 517
- 518
- 519
- 520
- 521
- 522
- 523
- 524
- 525
- 526
- 527
- 528
- 529
- 530
- 531
- 532
- 533
- 534
- 535
- 536
- 537
- 538
- 539
- 540
- 541
- 542
- 543
- 544
- 545
- 546
- 547
- 548
- 549
- 550
- 551
- 552
- 553
- 554
- 555
- 556
- 557
- 558
- 559
- 560
- 561
- 562
- 563
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571
- 572
- 573
- 574
- 575
- 576
- 577
- 578
- 579
- 580
- 581
- 582
- 583
- 584
- 585
- 586
- 587
- 588
- 589
- 590
- 591
- 592
- 593
- 594
- 595
- 596
- 597
- 598
- 599
- 600
- 601
- 602
- 603
- 604
- 605
- 606
- 607
- 608
- 609
- 610
- 611
- 612
- 613
- 614
- 615
- 616
- 617
- 618
- 619
- 620
- 621
- 622
- 623
- 624
- 625
- 626
- 627
- 628
- 629
- 630
- 631
- 632
- 633
- 634
- 635
- 636
- 637
- 638
- 639
- 640
- 641
- 642
- 643
- 644
- 645
- 646
- 647
- 648
- 649
- 650
- 651
- 652
- 653
- 654
- 655
- 656
- 657
- 658
- 659
- 660
- 661
- 662
- 663
- 664
- 665
- 666
- 667
- 668
- 669
- 670
- 671
- 672
- 673
- 674
- 675
- 676
- 677
- 678
- 679
- 680
- 681
- 682
- 683
- 684
- 685
- 686
- 687
- 688
- 689
- 690
- 691
- 692
- 693
- 694
- 695
- 696
- 697
- 698
- 699
- 700
- 701
- 702
- 703
- 704
- 705
- 706
- 707
- 708
- 709
- 710
- 711
- 712
- 713
- 714
- 715
- 716
- 717
- 718
- 719
- 720
- 721
- 722
- 723
- 724
- 725
- 726
- 727
- 728
- 729
- 730
- 731
- 732
- 733
- 734
- 735
- 736
- 737
- 738
- 739
- 740
- 741
- 742
- 743
- 744
- 745
- 746
- 747
import styled from "@emotion/styled";
import Lion, { lionSelectors } from "@rosetta/react-lion";
import React from "react";
import { connect } from "react-redux";
import ReactToggle from "react-toggle";
import TutorImage from "../assets/images/device-images/myaccount-tutoring.png";
import { selectors as appSelectors } from "../common/appreducer";
import { fetchCreditCard } from "../common/backbone/backbone-service";
import { getAppParams } from "../common/community/integration";
import AppUnderHeaderContainer from "../common/header/AppUnderHeaderContainer";
import CourseHeader from "../common/header/CourseHeader";
import { sessionObj } from "../common/session/session-sagas";
import ReactToggleCSS from "../common/styles/react-toggle-css";
import CreditCardForm from "./CreditCardForm";
import { errorsMap } from "./errors";
import Modal from "./Modal";
import { actions, myAccountReducer } from "./my-account-reducer";
import { myAccountSagas } from "./my-account-sagas";
import { getIsFreeTrial, tutoringPackByProductSessions } from "./my-account-selectors";
const usStates = [
{ name: 'ALABAMA', abbreviation: 'AL'},
{ name: 'ALASKA', abbreviation: 'AK'},
{ name: 'AMERICAN SAMOA', abbreviation: 'AS'},
{ name: 'ARIZONA', abbreviation: 'AZ'},
{ name: 'ARKANSAS', abbreviation: 'AR'},
{ name: 'CALIFORNIA', abbreviation: 'CA'},
{ name: 'COLORADO', abbreviation: 'CO'},
{ name: 'CONNECTICUT', abbreviation: 'CT'},
{ name: 'DELAWARE', abbreviation: 'DE'},
{ name: 'DISTRICT OF COLUMBIA', abbreviation: 'DC'},
{ name: 'FEDERATED STATES OF MICRONESIA', abbreviation: 'FM'},
{ name: 'FLORIDA', abbreviation: 'FL'},
{ name: 'GEORGIA', abbreviation: 'GA'},
{ name: 'GUAM', abbreviation: 'GU'},
{ name: 'HAWAII', abbreviation: 'HI'},
{ name: 'IDAHO', abbreviation: 'ID'},
{ name: 'ILLINOIS', abbreviation: 'IL'},
{ name: 'INDIANA', abbreviation: 'IN'},
{ name: 'IOWA', abbreviation: 'IA'},
{ name: 'KANSAS', abbreviation: 'KS'},
{ name: 'KENTUCKY', abbreviation: 'KY'},
{ name: 'LOUISIANA', abbreviation: 'LA'},
{ name: 'MAINE', abbreviation: 'ME'},
{ name: 'MARSHALL ISLANDS', abbreviation: 'MH'},
{ name: 'MARYLAND', abbreviation: 'MD'},
{ name: 'MASSACHUSETTS', abbreviation: 'MA'},
{ name: 'MICHIGAN', abbreviation: 'MI'},
{ name: 'MINNESOTA', abbreviation: 'MN'},
{ name: 'MISSISSIPPI', abbreviation: 'MS'},
{ name: 'MISSOURI', abbreviation: 'MO'},
{ name: 'MONTANA', abbreviation: 'MT'},
{ name: 'NEBRASKA', abbreviation: 'NE'},
{ name: 'NEVADA', abbreviation: 'NV'},
{ name: 'NEW HAMPSHIRE', abbreviation: 'NH'},
{ name: 'NEW JERSEY', abbreviation: 'NJ'},
{ name: 'NEW MEXICO', abbreviation: 'NM'},
{ name: 'NEW YORK', abbreviation: 'NY'},
{ name: 'NORTH CAROLINA', abbreviation: 'NC'},
{ name: 'NORTH DAKOTA', abbreviation: 'ND'},
{ name: 'NORTHERN MARIANA ISLANDS', abbreviation: 'MP'},
{ name: 'OHIO', abbreviation: 'OH'},
{ name: 'OKLAHOMA', abbreviation: 'OK'},
{ name: 'OREGON', abbreviation: 'OR'},
{ name: 'PALAU', abbreviation: 'PW'},
{ name: 'PENNSYLVANIA', abbreviation: 'PA'},
{ name: 'PUERTO RICO', abbreviation: 'PR'},
{ name: 'RHODE ISLAND', abbreviation: 'RI'},
{ name: 'SOUTH CAROLINA', abbreviation: 'SC'},
{ name: 'SOUTH DAKOTA', abbreviation: 'SD'},
{ name: 'TENNESSEE', abbreviation: 'TN'},
{ name: 'TEXAS', abbreviation: 'TX'},
{ name: 'UTAH', abbreviation: 'UT'},
{ name: 'VERMONT', abbreviation: 'VT'},
{ name: 'VIRGIN ISLANDS', abbreviation: 'VI'},
{ name: 'VIRGINIA', abbreviation: 'VA'},
{ name: 'WASHINGTON', abbreviation: 'WA'},
{ name: 'WEST VIRGINIA', abbreviation: 'WV'},
{ name: 'WISCONSIN', abbreviation: 'WI'},
{ name: 'WYOMING', abbreviation: 'WY' }
];
const PageWrapper = styled.div({
margin: "auto",
label: "MyAccountPageWrapper",
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
overflowX: "hidden",
overflowY: "auto",
"& > div": { maxWidth: "1211px", margin: "auto", alignItems: "baseline",justifyContent: "center" }
});
const CardWrapper = styled.div(props => ({
label: "CardWrapper",
display: "flex",
flexDirection: "column",
background: props.theme.exploreCardBackground,
borderRadius: "6px",
padding: "25px",
margin: '25px 12.5px 0',
width: "580px",
boxSizing: "border-box",
alignItems: "baseline",
position: "relative"
, "@media (max-width: 1211px)": {
width: "100%"
},
"&.tutoring-section": {
backgroundColor: "#3752B4",
color: "#fff",
width: "440px"
}
}));
const CardsContainer = styled.div(props => ({
display: 'flex',
flexWrap: 'wrap',
position: "relative"
}))
const CardTitleText = styled.div(props => {
const styles = {
padding: 0,
fontSize: 32,
marginBottom: 15,
color: props.color || "inherit",
textAlign: props.align || "left",
lineHeight: "120%",
};
if (props.screenWidth) {
if (props.screenWidth < 885) {
styles.fontSize = 18;
styles.lineHeight = "20px";
}
}
return styles;
});
const CardDescriptionText = styled.p(props => {
const styles = {
color: props.color ? props.color : "#262626",
fontSize: "20px",
lineHeight: "30px",
fontWeight: 400,
fontFamily: "Helvetica",
".block" : {
display: "block"
},
};
if (props.textAlign) {
styles.textAlign = props.textAlign
}
if (props.screenWidth) {
if (props.screenWidth < 885) {
styles.fontSize = 13;
styles.lineHeight = "16px";
}
}
return styles;
});
const ProductName = styled.span({
color: "#0098DB",
fontSize: "20px",
fontWeight: 700,
display: "block"
});
const FlexTitle = styled.div({
display: "flex"
})
const ToggleWrapper = styled.div({
marginLeft: 20,
marginTop: 3
});
const Button = styled.button({
background: "#02B1FF",
color: "#fff",
border: "1px solid transparent",
borderRadius: "10px",
padding: "15px 0",
fontSize: "17px",
width: "100%",
"&:disabled": {
background: '#ccc'
}
});
const TutorPricing = styled.div({
margin: "40px 0 20px",
display: "flex",
alignItems: "center",
".price-area": {
display: "flex",
flexDirection: "column",
alignItems: "center",
p: {
fontSize: "18px",
fontWeight: "bold",
textAlign: "center",
marginBottom: "15px"
},
".price": {
display: "flex",
alignItems: "center",
fontWeight: 300,
".currency-sign": {
fontSize: "42px",
position: "relative",
top: "-9px"
},
".dollars": {
fontSize: "68px"
},
".cents-wrapper": {
display: "flex",
flexDirection: "column"
},
".cents": {
fontSize: "32px"
}
}
}
});
const TutoringDeviceImg = styled.div({
display: "flex",
justifyContent: "center",
width: "223px",
});
const TutorLegalese = styled.div(props => {
const styles = {
fontSize: "12px",
lineHeight: "15px",
position: "absolute",
bottom: "-39px",
color: "#262626"
}
if (props.bottom) {
styles.bottom = props.bottom;
}
return styles;
});
const Spacer = styled.div({
height: "40px"
});
// This will become its own module later when we also make Button a component
// with event callbacks, etc.
const ModalContainer = styled.div({
position: "fixed",
top: 0,
right: 0,
bottom: 0,
left: 0,
background: "rgba(0, 0, 0, 0.5)",
backdropFilter: "blur(3px)",
});
/*
const Modal = styled.div({
border: "1px solid black",
borderRadius: "20px",
width: "38%",
maxWidth: "524px",
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
background: "#fff",
padding: "40px",
textAlign: "center",
fontSize: "20px",
color: "#262626",
".close-button": {
cursor: "pointer",
position: "absolute",
fontSize: "42px",
right: "15px",
top: 0,
},
p: {
marginBottom: "25px"
},
".title": {
color: "#3752B4",
fontSize: "24px",
"&.error" : {
color: "#d92a2a"
}
}
})
*/
// TODO - these map values should ideally come from the server, translated,
// so that every client doesn't have to do this. Full list of names & terms:
// https://stash.trstone.com/projects/IIS/repos/provision-iis/browse/src/main/resources/braze-template.properties?at=543f9d89be3c2cd3793022eb51611d1fce4b0a29
const PRODUCT_MAP = {
RS_SPANISH_LA: "Spanish (Latin America)",
RS_SPANISH_SP: "Spanish (Spain)",
RS_FRENCH: "French",
RS_ITALIAN: "Italian",
RS_GERMAN: "German",
RS_ENGLISH_USA: "English (American)",
RS_ENGLISH_BR: "English (British)",
RS_ARABIC: "Arabic",
RS_CHINESE: "Chinese (Mandarin)",
RS_DUTCH: "Dutch",
RS_FILIPINO: "Tagalog (Filipino)",
RS_GREEK: "Greek",
RS_HEBREW: "Hebrew",
RS_HINDI: "Hindi",
RS_IRISH: "Irish",
RS_JAPANESE: "Japanese",
RS_KOREAN: "Korean",
RS_PERSIAN: "Farsi (Persian)",
RS_POLISH: "Polish",
RS_PORTUGUESE: "Portuguese (Brazil)",
RS_RUSSIAN: "Russian",
RS_SWEDISH: "Swedish",
RS_TURKISH: "Turkish",
RS_VIETNAMESE: "Vietnamese",
RS_LATIN: "Latin",
RS_UNLIMITED: "Unlimited Languages"
}
const DURATION_MAP = {
PAY_PER_MONTH: "1 Month Plan",
PAY_PER_3_MONTHS: "3 Month Plan",
PAY_PER_6_MONTHS: "6 Month Plan",
PAY_PER_YEAR: "12 Month Plan",
PAY_PER_2_YEARS: "2 Year Plan",
LIFETIME: "Lifetime Plan"
}
const TRIAL_LANG_MAP = {
ARA: "Arabic",
CHI: "Chinese (Mandarin)",
DEU: "German",
EBR: "English (British)",
ENG: "English (American)",
ESC: "Spanish (Spain)",
ESP: "Spanish (Latin America)",
FAR: "Farsi (Persian)",
FRA: "French",
GLE: "Irish",
GRK: "Greek",
HEB: "Hebrew",
HIN: "Hindi",
ITA: "Italian",
JPN: "Japanese",
KOR: "Korean",
LAT: "Latin",
NED: "Dutch",
POL: "Polish",
POR: "Portuguese (Brazil)",
RUS: "Russian",
SVE: "Swedish",
TGL: "Tagalog (Filipino)",
TUR: "Turkish",
VIE: "Vietnamese"
}
const TRIAL_TEXT = "Free Trial";
// Make sure mo/yr is not in past
function validateExpirationDate(dropdownMonth, dropdownYear) {
let ret = true
if (!dropdownMonth && !dropdownYear) {
ret = {msg: "Expiration month and year cannot be blank."}
} else if(!dropdownMonth) {
ret = {msg: "Expiration month cannot be blank."}
} else if (!dropdownYear) {
ret = {msg: "Expiration year cannot be blank."}
}
const currentMonth = new Date().getMonth() + 1
const currentYear = parseInt(new Date().getFullYear().toString().slice(-2))
if (dropdownMonth < currentMonth && dropdownYear === currentYear) {
ret = {msg: "Expiration date cannot be in the past."}
}
return ret
}
// For Credit Card expiration year dropdown
const expirationYears = [""]
const currentYear = new Date().getFullYear()
for (let year = currentYear; year < currentYear + 15; year++) {
expirationYears.push({fullYear: year, shortYear: year.toString().slice(2)})
}
class MyAccount extends React.Component {
constructor(props) {
super(props);
this.props = props
this.state = {
purchaseTutoringCardError: null,
isCardFormButtonDisabled: false,
isModalOpen: true,
tutorPurchaseResult: null, // success, error, null,
tutorPrice: {
dollars: null,
cents: null,
},
// This will be set after async call to fetch user's card on componentWillMount
// It holds all card data, such as name, last 4 digits, city, etc
cardData: {},
}
}
async componentDidUpdate(prevProps) {
// We got an accountHeaderId. Let's fetch user's credit card data with it
if (!prevProps.account && this.props.account?.accountHeaderId) {
console.log('---- FETCHING')
const cardData = await fetchCreditCard(this.props.account.accountHeaderId);
console.log(cardData)
this.setState({ cardData })
}
//
}
handleTutoringPurchaseWithExistingCard = async () => {
console.log('testTutoringPurchase', this.props);
// This API returns `true` or `false`? not an object or str, but a bool.
// minimalistic, i dig.
let result = await sessionObj.purchaseTutoringPacks({ purchases: [ { numSessions: 2, product: 'RS_GROUP_TUTORING_PACK' } ]});
if (result) {
this.setState({ tutorPurchaseResult: "success"})
} else {
this.setState({ tutorPurchaseResult: "error"})
}
}
handleModalClose = async () => {
this.setState({tutorPurchaseResult: null});
this.setState({isModalOpen: false});
}
handleCreditCardFormSubmit = e => {
e.preventDefault()
const { dispatch, creditCard } = this.props
let errors = []
if (!creditCard) {
errors.push("An unknown error occurred. Please try again.")
dispatch(actions.updateCreditCard({ ...creditCard, errors }))
console.log("[error] creditCard state not loaded.")
return
}
// Full name validation
if (
!creditCard.name
|| creditCard.name.trim() > 100
|| creditCard.name.trim() < 2
|| !/^([a-z]+(-|\.| )*)+$/i.test(creditCard.name))
{
errors.push("Name is invalid.")
}
// Card number validation
if (!(creditCard.number.length >= 15 && creditCard.number.length <= 16) || /\*/.test(creditCard.number)) {
errors.push(errorsMap["InvalidCCNumber"])
}
// State validation
if (usStates.filter(e => e.abbreviation === creditCard.state).length === 0) {
errors.push("State is invalid.")
}
// Zip code validation
if (!creditCard.zip || creditCard.zip.length !== 5 ) {
errors.push("Zip code is invalid.")
}
// Expiration date can't be in past
const isExpDateValid = validateExpirationDate(
parseInt(creditCard.expirationMonth),
parseInt(creditCard.expirationYear)
)
if (isExpDateValid !== true) {
errors.push(isExpDateValid.msg)
}
// Security code validation - 3 or 4 digits
if (!creditCard.securityCode || !(creditCard.securityCode.length >= 3 && creditCard.securityCode.length <= 4)) {
errors.push("Security code is invalid.")
}
if (errors.length) {
dispatch(actions.updateCreditCard({ ...creditCard, errors }))
return
}
const postData = {
cardNumber: creditCard.number,
expDate: {
expMonth: parseInt(creditCard.expirationMonth),
expYear: creditCard.expirationYear
},
securityCode: creditCard.securityCode,
nameOnCard: creditCard.name,
address: {
zipCode: creditCard.zip,
state: creditCard.state,
country: creditCard.country,
}
}
this.props.dispatch(actions.creditCardTokenFetchRequested(postData))
}
openModal(modal) {
}
updateCreditCardSubmit() {
console.log("WE ARE SUBMITTING TO UPDATE`")
}
render() {
if (!this.props.lionLoaded || !this.props.account) return null;
const dispatch = this.props.dispatch
const account = this.props.account
const creditCard = this.props.creditCard
const cardData = this.state.cardData
// RSPE-151: Render the myaccount page differently for trial users
const trialStartsAt = this.props.isFreeTrial
? new Date((parseInt(getAppParams().trial_ends_at) - (86400 * 3)) * 1000).toISOString().split('T')[0]
: "";
const trialEndsAt = this.props.isFreeTrial
? new Date((parseInt(getAppParams().trial_ends_at) - (86400 * 1)) * 1000).toISOString().split('T')[0]
: "";
let dollars, cents
try {
const price = this.props.tutoringPackByProductSessions('RS_GROUP_TUTORING_PACK', 2).fullPrice + ""
dollars = price.split(".")[0]
cents = price?.split('.')[1] ?? "00"
} catch (e) {
console.log("couldn't manipulate tutoring price")
}
return (
<>
<CourseHeader />
<AppUnderHeaderContainer>
<PageWrapper>
<CardsContainer>
{/* Left side - products, payment info, auto renewal */}
<CardWrapper>
<CardTitleText>
<Lion.span lionkey="your_products" />
</CardTitleText>
{ this.props.isFreeTrial ?
<CardDescriptionText>
<ProductName>{ TRIAL_LANG_MAP[getAppParams().target_language_rs_code] } { TRIAL_TEXT } </ProductName>
<Lion.span className="block" lionkey="subscription_start_date" replacements={{ $date: trialStartsAt }}/>
<Lion.span className="block" lionkey="subscription_end_date" replacements={{ $date: trialEndsAt }}/>
</CardDescriptionText> :
<CardDescriptionText>
<ProductName>{ PRODUCT_MAP[account.products?.[0]] } { DURATION_MAP[account.paymentTerm]} </ProductName>
<Lion.span className="block" lionkey="subscription_start_date" replacements={{ $date: account.startDate }}/>
{ account.paymentTerm !== "LIFETIME" &&
<Lion.span className="block" lionkey="subscription_end_date" replacements={{ $date: account.expirationDate }}/>
}
</CardDescriptionText>
}
{ account.paymentTerm !== "LIFETIME" && /* lifetime users can't update credit card */
!this.props.isFreeTrial && /* RSPE-151: trial users shouldn't see payment info section */
<div>
<Spacer />
<CardTitleText bold blue>
<Lion.span lionkey="my_payment_information" />
</CardTitleText>
<div>
<Lion.div lionkey="full_name" />
<div>{ cardData.name }</div>
</div>
<div>
<Lion.div lionkey="card_number" />
<div>{ creditCard.number }</div>
</div>
<div>
<Lion.div lionkey="expiration_date" />
{creditCard.expirationYear}/{creditCard.expirationYear}
</div>
</div>
}
{ account.paymentTerm !== "LIFETIME" /* lifetime users can't auto renew, it's one price for lifetime */ &&
!this.props.isFreeTrial /* RSPE-151: trial users shouldn't see autorenew section */ &&
account.isGift === "false" &&
<div>
<Spacer />
<CardTitleText>
<FlexTitle>
<Lion.span lionkey="auto_renewal" />
{ account.isAllowedToAutoRenew &&
<ToggleWrapper>
<ReactToggleCSS />
<ReactToggle
className="dark-theme-toggle"
checked={account.isAutoRenew}
onChange={()=> dispatch(actions.setAutoRenewAsync(account.isAutoRenew))}
/>
</ToggleWrapper>
}
</FlexTitle>
</CardTitleText>
<CardDescriptionText>
{account.isAutoRenew &&
<Lion.span lionkey="your_subscription_will_automatically_renew" replacements={{
$date: account.expirationDate,
$renewPrice: `$${account.nextBillPrice}`
}} />
}
</CardDescriptionText>
</div>
}
</CardWrapper>
{/* Right side - tutoring */}
{ account.paymentTerm !== "LIFETIME" && /* lifetime & freetrial users don't see tutor ad */
!this.props.isFreeTrial &&
<CardWrapper className="tutoring-section">
<CardTitleText align="center">
Want to get real-life practice with your new language?
</CardTitleText>
<CardDescriptionText color="#fff" textAlign="center">
Level up your learning through interactive tutoring sessions with native speakers!
</CardDescriptionText>
<TutorPricing>
<TutoringDeviceImg>
<img src={TutorImage} alt="Tutoring session on mobile phone" />
</TutoringDeviceImg>
<div className="price-area">
<p>
Get started with 2 sessions of group tutoring for only
</p>
<div className="price">
<super className="currency-sign">$</super>
<span className="dollars">{ dollars }</span>
<span className="cents-wrapper">
<span className="cents">{ '.' + cents}</span>
<span className="tax">+ tax</span>
</span>
</div>
</div>
</TutorPricing>
<Button
onClick={() => this.setState({isModalOpen: true})}
disabled={false}
type="submit">
BUY NOW
</Button>
<TutorLegalese>
*One-time exclusive offer. Rosetta Stone Tutoring sessions are only
available for use with an active product subscription. All prices are shown in US Dollars.
</TutorLegalese>
</CardWrapper>
}
{/* modal */}
{this.state.isModalOpen &&
<ModalContainer>
<Modal>
<CreditCardForm
cardNumber={cardData.lastFourDigits}
cardName={cardData.name}
submitButtonText="UPDATE"
submitCallback={this.updateCreditCardSubmit}
/>
</Modal>
</ModalContainer>
}
</CardsContainer>
</PageWrapper>
</AppUnderHeaderContainer>
</>
);
}
}
const mapStateToProps = (state) => {
return {
lionLoaded: lionSelectors.getLionAppResourcesLoaded(state),
lionTranslateString: key => {
return lionSelectors.getLionTranslatedString(state, key);
},
account: state.myAccount.account,
creditCard: state.myAccount.creditCard,
pricingInfo: state.myAccount.pricingInfo,
tutoringPackByProductSessions: tutoringPackByProductSessions(state),
clientConfig: appSelectors.getClientConfig(state),
isFreeTrial: getIsFreeTrial(state),
};
};
const MyAccountContainer = connect(mapStateToProps)(MyAccount);
export default {
sagas: myAccountSagas,
reducers: {
myAccount: myAccountReducer
},
rootComponent: MyAccountContainer
};