11import React , { HTMLAttributes , useState } from "react"
22import { ActionButton , Alert , styled } from "@mitodl/smoot-design"
33import { productQueries } from "api/mitxonline-hooks/products"
4- import { Dialog , Link , Skeleton , Stack , Typography } from "ol-components"
4+ import { Dialog , Link , Skeleton , Stack , theme , Typography } from "ol-components"
55import type { StackProps } from "ol-components"
66import {
77 RiCalendarLine ,
@@ -390,7 +390,7 @@ const ProgramPaySection = styled.div(({ theme }) => ({
390390 display : "flex" ,
391391 flexDirection : "column" ,
392392 alignItems : "flex-start" ,
393- gap : "4px " ,
393+ gap : "12px " ,
394394 width : "346px" ,
395395 alignSelf : "stretch" ,
396396 flex : "none" ,
@@ -404,63 +404,84 @@ const ProgramPayLabel = styled.span(({ theme }) => ({
404404 letterSpacing : "0.04em" ,
405405} ) )
406406
407- const ProgramPayContent = styled . div ( ( { theme } ) => ( {
407+ /** Horizontal row: [current price block] | [vertical divider] | [list price block] */
408+ const ProgramPriceRowInner = styled . div < { } > ( {
408409 display : "flex" ,
409- flexDirection : "column" ,
410- alignItems : "flex-start" ,
411- gap : "12px" ,
412- width : "100%" ,
413- maxWidth : "320px" ,
414- [ theme . breakpoints . down ( "sm" ) ] : {
415- maxWidth : "100%" ,
416- } ,
417- } ) )
410+ flexDirection : "row" as const ,
411+ alignItems : "flex-end" as const ,
412+ gap : "24px" ,
413+ } )
418414
419- const ProgramPriceLine = styled . div ( ( { theme } ) => ( {
415+ const ProgramCurrentPriceBlock = styled . div < { } > ( {
420416 display : "flex" ,
421- alignItems : "flex-end" ,
422- gap : "4px" ,
423- flexWrap : "wrap" ,
424- color : theme . custom . colors . darkGray2 ,
425- } ) )
417+ flexDirection : "column" as const ,
418+ justifyContent : "flex-end" as const ,
419+ alignItems : "flex-start" as const ,
420+ } )
426421
427422const ProgramPriceAmount = styled . span ( ( { theme } ) => ( {
428- ...theme . typography . h3 ,
423+ ...theme . typography . subtitle2 ,
424+ fontFamily : "'Helvetica Neue', Helvetica, Arial, sans-serif" ,
429425 fontWeight : theme . typography . fontWeightBold ,
430- lineHeight : "36px" ,
426+ fontSize : "34px" ,
427+ lineHeight : "40px" ,
428+ color : theme . custom . colors . darkGray2 ,
431429} ) )
432430
433431const ProgramPriceSuffix = styled . span ( ( { theme } ) => ( {
434- ...theme . typography . subtitle1 ,
435- fontSize : "18px" ,
436- lineHeight : "26px" ,
437- color : theme . custom . colors . silverGrayDark ,
432+ ...theme . typography . body3 ,
433+ color : "#626A73" ,
438434} ) )
439435
440- const ProgramDiscountBlock = styled . div ( ( { theme } ) => ( {
441- display : "flex" ,
442- flexDirection : "column" ,
443- justifyContent : "center" ,
444- alignItems : "flex-start" ,
445- gap : "8px" ,
446- color : theme . custom . colors . darkGray2 ,
436+ const ProgramVerticalDivider = styled . div ( ( ) => ( {
437+ width : "1px" ,
438+ height : "48px" ,
439+ backgroundColor : "#CBD2D9" ,
440+ flexShrink : 0 ,
447441} ) )
448442
449- const ProgramSavingsText = styled . span ( ( { theme } ) => ( {
450- ...theme . typography . subtitle1 ,
451- color : "#008000" ,
452- fontWeight : theme . typography . fontWeightBold ,
453- } ) )
443+ const ProgramListPriceBlock = styled . div < { } > ( {
444+ display : "flex" ,
445+ flexDirection : "column" as const ,
446+ justifyContent : "flex-end" as const ,
447+ alignItems : "flex-start" as const ,
448+ } )
454449
455- const ProgramListPriceText = styled . span ( ( { theme } ) => ( {
456- ...theme . typography . body2 ,
450+ const ProgramListPriceAmount = styled . span ( {
451+ ...theme . typography . body3 ,
452+ fontFamily : "'Helvetica Neue', Helvetica, Arial, sans-serif" ,
453+ fontSize : "28px" ,
454+ lineHeight : "36px" ,
455+ display : "flex" ,
456+ alignItems : "flex-end" as const ,
457+ textDecoration : "line-through" ,
458+ color : "#626A73" ,
459+ } )
460+
461+ const ProgramListPriceSubLabel = styled . span ( {
462+ ...theme . typography . body3 ,
457463 color : theme . custom . colors . silverGrayDark ,
458- } ) )
464+ } )
459465
460- const ProgramListPriceAmount = styled . span ( ( { theme } ) => ( {
461- ...theme . typography . subtitle2 ,
462- textDecoration : "line-through" ,
463- } ) )
466+ /** Inline row: "Save $X compared to purchasing N courses separately" */
467+ const ProgramDiscountRow = styled . div < { } > ( {
468+ display : "flex" ,
469+ flexDirection : "row" as const ,
470+ alignItems : "center" as const ,
471+ gap : "4px" ,
472+ width : "100%" ,
473+ } )
474+
475+ const ProgramSavingsText = styled . span ( {
476+ ...theme . typography . subtitle3 ,
477+ fontWeight : theme . typography . fontWeightBold ,
478+ color : "#008000" ,
479+ } )
480+
481+ const ProgramSavingsDetailText = styled . span ( {
482+ ...theme . typography . body3 ,
483+ color : theme . custom . colors . silverGrayDark ,
484+ } )
464485
465486const ProgramPriceDivider = styled . div ( ( { theme } ) => ( {
466487 width : "100%" ,
@@ -497,19 +518,25 @@ const ProgramStartForFreeTextContainer = styled.span(({ theme }) => ({
497518 ...theme . typography . body2 ,
498519} ) )
499520
500- const ProgramStartForFreeTextStrong = styled . span ( ( { theme } ) => ( {
521+ const ProgramStartForFreeTextStrong = styled . span ( {
501522 ...theme . typography . subtitle2 ,
502523 color : "#008000" ,
503- } ) )
524+ } )
504525
505- const ProgramStartForFreeTextRegular = styled . span ( ( { theme } ) => ( {
526+ const ProgramStartForFreeTextRegular = styled . span ( {
506527 ...theme . typography . body2 ,
507528 color : theme . custom . colors . darkGray2 ,
508- } ) )
529+ } )
509530
510- const ProgramStartForFreeLink = styled ( UnderlinedLink ) ( ( { theme } ) => ( {
511- ...theme . typography . body2 ,
512- color : theme . custom . colors . darkGray2 ,
531+ const ProgramStartForFreeInfoIcon = styled . span ( ( { theme } ) => ( {
532+ display : "inline-flex" ,
533+ alignItems : "center" ,
534+ flexShrink : 0 ,
535+ color : theme . custom . colors . silverGrayDark ,
536+ "& svg" : {
537+ width : "20px" ,
538+ height : "20px" ,
539+ } ,
513540} ) )
514541
515542const CertificateBoxRoot = styled . div ( ( { theme } ) => ( {
@@ -918,71 +945,84 @@ const ProgramPriceRow: React.FC<ProgramPriceRowProps> = ({
918945 const paidSection = currentPrice ? (
919946 < ProgramPaySection >
920947 < ProgramPayLabel > Price</ ProgramPayLabel >
921- < ProgramPayContent >
922- < ProgramPriceLine >
948+ < ProgramPriceRowInner >
949+ < ProgramCurrentPriceBlock >
923950 < ProgramPriceAmount >
924951 { formatPrice ( currentPrice , { avoidCents : true } ) }
925952 </ ProgramPriceAmount >
926- < ProgramPriceSuffix > / full program</ ProgramPriceSuffix >
927- </ ProgramPriceLine >
928- { hasSavings && savingsAmount !== null && listAmount !== null ? (
929- < ProgramDiscountBlock >
930- < ProgramSavingsText >
931- Save { formatPrice ( savingsAmount , { avoidCents : true } ) }
932- </ ProgramSavingsText >
933- < ProgramListPriceText >
953+ < ProgramPriceSuffix > full program</ ProgramPriceSuffix >
954+ </ ProgramCurrentPriceBlock >
955+ { hasSavings && listAmount !== null ? (
956+ < >
957+ < ProgramVerticalDivider />
958+ < ProgramListPriceBlock >
934959 < ProgramListPriceAmount >
935960 { formatPrice ( listAmount , { avoidCents : true } ) }
936- </ ProgramListPriceAmount > { " " }
937- total for { totalRequired } { pluralize ( "course" , totalRequired ) } { " " }
938- purchased separately
939- </ ProgramListPriceText >
940- </ ProgramDiscountBlock >
961+ </ ProgramListPriceAmount >
962+ < ProgramListPriceSubLabel >
963+ purchased separately
964+ </ ProgramListPriceSubLabel >
965+ </ ProgramListPriceBlock >
966+ </ >
941967 ) : null }
942- { program . page . financial_assistance_form_url ? (
943- < SecondaryUnderlinedLink
944- color = "black"
945- href = { mitxonlineLegacyUrl (
946- program . page . financial_assistance_form_url ,
947- ) }
968+ </ ProgramPriceRowInner >
969+ { hasSavings && savingsAmount !== null ? (
970+ < ProgramDiscountRow >
971+ < ProgramSavingsText >
972+ Save { formatPrice ( savingsAmount , { avoidCents : true } ) }
973+ </ ProgramSavingsText >
974+ < ProgramSavingsDetailText >
975+ compared to purchasing { totalRequired } { " " }
976+ { pluralize ( "course" , totalRequired ) } separately
977+ </ ProgramSavingsDetailText >
978+ </ ProgramDiscountRow >
979+ ) : null }
980+ { program . page . financial_assistance_form_url ? (
981+ < SecondaryUnderlinedLink
982+ color = "black"
983+ href = { mitxonlineLegacyUrl (
984+ program . page . financial_assistance_form_url ,
985+ ) }
986+ target = "_blank"
987+ rel = "noopener noreferrer"
988+ style = { { minWidth : "fit-content" } }
989+ >
990+ Financial assistance available
991+ </ SecondaryUnderlinedLink >
992+ ) : null }
993+ { enrollmentType === "both" ? (
994+ < ProgramStartForFreeBox >
995+ < ProgramStartForFreeIcon
996+ width = "24"
997+ height = "24"
998+ viewBox = "0 0 22 19"
999+ fill = "none"
1000+ xmlns = "http://www.w3.org/2000/svg"
1001+ aria-hidden = "true"
1002+ >
1003+ < path d = "M14 0C16.2091 0 18 1.79086 18 4C18 4.72903 17.8049 5.41251 17.4642 6.00111L22 6V7.99999H20V18C20 18.5523 19.5523 19 19 19H3C2.44772 19 2 18.5523 2 18V7.99999H0V6L4.53577 6.00111C4.19504 5.41251 4 4.72903 4 4C4 1.79086 5.79086 0 8 0C9.19522 0 10.268 0.52421 11.0009 1.35526C11.732 0.52421 12.8048 0 14 0ZM10 7.99999H4V17H10V7.99999ZM18 7.99999H12V17H18V7.99999ZM8 2C6.89543 2 6 2.89543 6 4C6 5.05436 6.81588 5.91816 7.85074 5.99451L8 6H10V4C10 2.99835 9.26372 2.16869 8.30278 2.02277L8.14927 2.00548L8 2ZM14 2C12.9456 2 12.0818 2.81588 12.0055 3.85074L12 4V6H14C15.0543 6 15.9181 5.18412 15.9945 4.14926L16 4C16 2.89543 15.1046 2 14 2Z" />
1004+ </ ProgramStartForFreeIcon >
1005+ < ProgramStartForFreeTextContainer >
1006+ < ProgramStartForFreeTextStrong >
1007+ Audit for free
1008+ </ ProgramStartForFreeTextStrong >
1009+ < ProgramStartForFreeTextRegular >
1010+ or upgrade to certificate
1011+ </ ProgramStartForFreeTextRegular >
1012+ </ ProgramStartForFreeTextContainer >
1013+ < a
1014+ href = { PROGRAM_CERT_INFO_HREF }
9481015 target = "_blank"
9491016 rel = "noopener noreferrer"
950- style = { { minWidth : "fit-content" } }
1017+ aria-label = "Learn more about program certificates"
1018+ style = { { display : "inline-flex" , alignItems : "center" } }
9511019 >
952- Financial assistance available
953- </ SecondaryUnderlinedLink >
954- ) : null }
955- { enrollmentType === "both" ? (
956- < ProgramStartForFreeBox >
957- < ProgramStartForFreeIcon
958- width = "24"
959- height = "24"
960- viewBox = "0 0 22 19"
961- fill = "none"
962- xmlns = "http://www.w3.org/2000/svg"
963- aria-hidden = "true"
964- >
965- < path d = "M14 0C16.2091 0 18 1.79086 18 4C18 4.72903 17.8049 5.41251 17.4642 6.00111L22 6V7.99999H20V18C20 18.5523 19.5523 19 19 19H3C2.44772 19 2 18.5523 2 18V7.99999H0V6L4.53577 6.00111C4.19504 5.41251 4 4.72903 4 4C4 1.79086 5.79086 0 8 0C9.19522 0 10.268 0.52421 11.0009 1.35526C11.732 0.52421 12.8048 0 14 0ZM10 7.99999H4V17H10V7.99999ZM18 7.99999H12V17H18V7.99999ZM8 2C6.89543 2 6 2.89543 6 4C6 5.05436 6.81588 5.91816 7.85074 5.99451L8 6H10V4C10 2.99835 9.26372 2.16869 8.30278 2.02277L8.14927 2.00548L8 2ZM14 2C12.9456 2 12.0818 2.81588 12.0055 3.85074L12 4V6H14C15.0543 6 15.9181 5.18412 15.9945 4.14926L16 4C16 2.89543 15.1046 2 14 2Z" />
966- </ ProgramStartForFreeIcon >
967- < ProgramStartForFreeTextContainer >
968- < ProgramStartForFreeTextStrong >
969- Start for free
970- </ ProgramStartForFreeTextStrong >
971- < ProgramStartForFreeTextRegular >
972- or upgrade to{ " " }
973- </ ProgramStartForFreeTextRegular >
974- < ProgramStartForFreeLink
975- color = "black"
976- href = { PROGRAM_CERT_INFO_HREF }
977- target = "_blank"
978- rel = "noopener noreferrer"
979- >
980- certificate
981- </ ProgramStartForFreeLink >
982- </ ProgramStartForFreeTextContainer >
983- </ ProgramStartForFreeBox >
984- ) : null }
985- </ ProgramPayContent >
1020+ < ProgramStartForFreeInfoIcon >
1021+ < RiInformation2Line aria-hidden = "true" />
1022+ </ ProgramStartForFreeInfoIcon >
1023+ </ a >
1024+ </ ProgramStartForFreeBox >
1025+ ) : null }
9861026 </ ProgramPaySection >
9871027 ) : (
9881028 < InfoLabelValue label = "Price" value = "Price unavailable" />
0 commit comments