Skip to content

Commit

Permalink
feat(OfferPresenter): display discount
Browse files Browse the repository at this point in the history
  • Loading branch information
guilhermespopolin committed Jul 4, 2023
1 parent b437eff commit c2ee004
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 53 deletions.
26 changes: 0 additions & 26 deletions apps/store/src/components/CartInventory/CartInventory.helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,6 @@ import { Money } from '@/utils/formatter'
import { useFormatter } from '@/utils/useFormatter'
import { CartEntry } from './CartInventory.types'

export const useGetDiscountExplanation = () => {
const { t } = useTranslation('cart')
const formatter = useFormatter()

return (discount: CampaignDiscount) => {
switch (discount.type) {
case CampaignDiscountType.MonthlyCost:
return `-${formatter.monthlyPrice(discount.amount)}`

case CampaignDiscountType.FreeMonths:
return t('DISCOUNT_STATE_FREE_MONTHS', { count: discount.months })

case CampaignDiscountType.MonthlyPercentage:
return t('DISCOUNT_STATE_MONTHLY_PERCENTAGE', {
percentage: discount.percentage,
count: discount.months,
})

case CampaignDiscountType.IndefinitePercentage:
return t('DISCOUNT_STATE_INDEFINITE_PERCENTAGE', {
percentage: discount.percentage,
})
}
}
}

export const useGetDiscountDurationExplanation = () => {
const { t } = useTranslation('cart')
const formatter = useFormatter()
Expand Down
6 changes: 2 additions & 4 deletions apps/store/src/components/CartInventory/CartInventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import styled from '@emotion/styled'
import { Space, theme } from 'ui'
import { CampaignDiscountType, CartFragmentFragment } from '@/services/apollo/generated'
import { convertToDate } from '@/utils/date'
import { useGetDiscountExplanation } from '@/utils/useDiscountExplanation'
import { CampaignsSection } from './CampaignsSection'
import { CartEntryItem } from './CartEntryItem/CartEntryItem'
import { CartEntryList } from './CartEntryList'
import {
useGetDiscountDurationExplanation,
useGetDiscountExplanation,
} from './CartInventory.helpers'
import { useGetDiscountDurationExplanation } from './CartInventory.helpers'
import { CostSummary } from './CostSummary'
import { ReadOnlyCampaignCodeList } from './ReadOnlyCampaignCodeList'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ const cart = {
amount: 125,
currencyCode: CurrencyCode.Sek,
},
cost: {
gross: {
amount: 125,
currencyCode: CurrencyCode.Sek,
},
net: {
amount: 125,
currencyCode: CurrencyCode.Sek,
},
discount: {
amount: 0,
currencyCode: CurrencyCode.Sek,
},
},
cancellation: {
option: ExternalInsuranceCancellationOption.None,
requested: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import { SpaceFlex } from '@/components/SpaceFlex/SpaceFlex'
import {
ExternalInsuranceCancellationOption,
ProductOfferFragment,
RedeemedCampaign,
} from '@/services/apollo/generated'
import { PriceIntent } from '@/services/priceIntent/priceIntent.types'
import { ShopSession } from '@/services/shopSession/ShopSession.types'
import { useTracking } from '@/services/Tracking/useTracking'
import { convertToDate } from '@/utils/date'
import { PageLink } from '@/utils/PageLink'
import { useGetDiscountExplanation } from '@/utils/useDiscountExplanation'
import { useFormatter } from '@/utils/useFormatter'
import { CancellationForm, CancellationOption } from './CancellationForm/CancellationForm'
import { ComparisonTableModal } from './ComparisonTableModal'
Expand Down Expand Up @@ -51,6 +53,7 @@ export const OfferPresenter = (props: Props) => {
const [, setSelectedOffer] = useSelectedOffer()
const { t } = useTranslation('purchase-form')
const formatter = useFormatter()
const getDiscountExplanation = useGetDiscountExplanation()
const [addToCartRedirect, setAddToCartRedirect] = useState<AddToCartRedirect | null>(null)

const handleOfferChange = (offerId: string) => {
Expand Down Expand Up @@ -100,7 +103,9 @@ export const OfferPresenter = (props: Props) => {

const [handleUpdateCancellation, updateCancellationInfo] = useUpdateCancellation({ priceIntent })

const displayPrice = formatter.monthlyPrice(selectedOffer.price)
const crossedOutPrice =
selectedOffer.cost.discount.amount > 0 ? formatter.monthlyPrice(selectedOffer.cost.gross) : null
const displayPrice = formatter.monthlyPrice(selectedOffer.cost.net)

const cancellationOption = getCancellationOption({
priceIntent,
Expand All @@ -111,28 +116,39 @@ export const OfferPresenter = (props: Props) => {
loadingAddToCart || updateCancellationInfo.loading || updateStartDateResult.loading

const discountTooltipProps = useMemo(() => {
if (!selectedOffer.priceMatch) return null
if (selectedOffer.priceMatch) {
const company = selectedOffer.priceMatch.externalInsurer.displayName

if (selectedOffer.priceMatch.priceReduction.amount < 1) {
// No price reduction due to incomparable offers
const amount = formatter.monthlyPrice(selectedOffer.priceMatch.externalPrice)
return {
children: t('PRICE_MATCH_BUBBLE_INCOMPARABLE_TITLE', { amount, company }),
subtitle: t('PRICE_MATCH_BUBBLE_INCOMPARABLE_SUBTITLE'),
color: 'gray',
} as const
}

const company = selectedOffer.priceMatch.externalInsurer.displayName
const priceReduction = formatter.monthlyPrice(selectedOffer.priceMatch.priceReduction)

if (selectedOffer.priceMatch.priceReduction.amount < 1) {
// No price reduction due to incomparable offers
const amount = formatter.monthlyPrice(selectedOffer.priceMatch.externalPrice)
return {
children: t('PRICE_MATCH_BUBBLE_INCOMPARABLE_TITLE', { amount, company }),
subtitle: t('PRICE_MATCH_BUBBLE_INCOMPARABLE_SUBTITLE'),
color: 'gray',
children: t('PRICE_MATCH_BUBBLE_SUCCESS_TITLE', { amount: priceReduction }),
subtitle: t('PRICE_MATCH_BUBBLE_SUCCESS_SUBTITLE', { company }),
color: 'green',
} as const
}

const priceReduction = formatter.monthlyPrice(selectedOffer.priceMatch.priceReduction)

return {
children: t('PRICE_MATCH_BUBBLE_SUCCESS_TITLE', { amount: priceReduction }),
subtitle: t('PRICE_MATCH_BUBBLE_SUCCESS_SUBTITLE', { company }),
color: 'green',
} as const
}, [selectedOffer.priceMatch, formatter, t])
const redeemedCampaign = shopSession.cart.redeemedCampaigns[0] as RedeemedCampaign | undefined
if (redeemedCampaign && selectedOffer.cost.discount.amount > 0) {
return {
children: getDiscountExplanation({
...redeemedCampaign.discount,
amount: selectedOffer.cost.discount,
}),
color: 'green',
} as const
}
}, [selectedOffer, formatter, getDiscountExplanation, shopSession, t])

const startDate = convertToDate(selectedOffer.startDate)

Expand Down Expand Up @@ -182,9 +198,16 @@ export const OfferPresenter = (props: Props) => {
<SpaceFlex direction="vertical" align="center" space={1}>
{discountTooltipProps && <DiscountTooltip {...discountTooltipProps} />}
<Space y={0.5}>
<Text as="p" align="center" size="xl">
{displayPrice}
</Text>
<SpaceFlex space={0.5}>
{crossedOutPrice && (
<Text as="p" color="textSecondary" size="xl" strikethrough>
{crossedOutPrice}
</Text>
)}
<Text as="p" align="center" size="xl">
{displayPrice}
</Text>
</SpaceFlex>
<Centered>
<TextButton onClick={onClickEdit}>
<Text align="center" size="xs" color="textSecondary" as="span">
Expand Down
14 changes: 14 additions & 0 deletions apps/store/src/graphql/ProductOfferFragment.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ fragment ProductOffer on ProductOffer {
amount
currencyCode
}
cost {
gross {
amount
currencyCode
}
net {
amount
currencyCode
}
discount {
amount
currencyCode
}
}
startDate
cancellation {
option
Expand Down
2 changes: 1 addition & 1 deletion apps/store/src/pages/cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useMemo } from 'react'
import {
getCrossOut,
useGetDiscountDurationExplanation,
useGetDiscountExplanation,
getTotal,
getCartEntry,
} from '@/components/CartInventory/CartInventory.helpers'
Expand All @@ -21,6 +20,7 @@ import { useShopSession } from '@/services/shopSession/ShopSessionContext'
import { getGlobalStory } from '@/services/storyblok/storyblok'
import { GLOBAL_STORY_PROP_NAME } from '@/services/storyblok/Storyblok.constant'
import { isRoutingLocale } from '@/utils/l10n/localeUtils'
import { useGetDiscountExplanation } from '@/utils/useDiscountExplanation'

const NextCartPage: NextPageWithLayout = (props) => {
const { shopSession } = useShopSession()
Expand Down
2 changes: 1 addition & 1 deletion apps/store/src/pages/checkout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
getCrossOut,
getTotal,
useGetDiscountDurationExplanation,
useGetDiscountExplanation,
} from '@/components/CartInventory/CartInventory.helpers'
import { CheckoutStep } from '@/components/CheckoutHeader/Breadcrumbs'
import { fetchCheckoutSteps } from '@/components/CheckoutHeader/CheckoutHeader.helpers'
Expand All @@ -23,6 +22,7 @@ import { useShopSession } from '@/services/shopSession/ShopSessionContext'
import { getShouldCollectEmail, getShouldCollectName } from '@/utils/customer'
import { isRoutingLocale } from '@/utils/l10n/localeUtils'
import { PageLink } from '@/utils/PageLink'
import { useGetDiscountExplanation } from '@/utils/useDiscountExplanation'

type NextPageProps = Omit<CheckoutPageProps, 'cart' | 'customerAuthenticationStatus'>

Expand Down
29 changes: 29 additions & 0 deletions apps/store/src/utils/useDiscountExplanation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useTranslation } from 'next-i18next'
import { CampaignDiscount, CampaignDiscountType } from '@/services/apollo/generated'
import { useFormatter } from './useFormatter'

export const useGetDiscountExplanation = () => {
const { t } = useTranslation('cart')
const formatter = useFormatter()

return (discount: CampaignDiscount) => {
switch (discount.type) {
case CampaignDiscountType.MonthlyCost:
return `-${formatter.monthlyPrice(discount.amount)}`

case CampaignDiscountType.FreeMonths:
return t('DISCOUNT_STATE_FREE_MONTHS', { count: discount.months })

case CampaignDiscountType.MonthlyPercentage:
return t('DISCOUNT_STATE_MONTHLY_PERCENTAGE', {
percentage: discount.percentage,
count: discount.months,
})

case CampaignDiscountType.IndefinitePercentage:
return t('DISCOUNT_STATE_INDEFINITE_PERCENTAGE', {
percentage: discount.percentage,
})
}
}
}
4 changes: 3 additions & 1 deletion packages/ui/src/components/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type TextProps = {
children?: ReactNode
className?: string
uppercase?: boolean
strikethrough?: boolean
}

const elementConfig = {
Expand All @@ -38,11 +39,12 @@ const elementConfig = {
export const TextBase = styled(
Space,
elementConfig,
)<TextProps>(({ align, color, size = 'md', uppercase = false }) => ({
)<TextProps>(({ align, color, size = 'md', uppercase = false, strikethrough = false }) => ({
color: color ? theme.colors[color] : 'inherit',
...getFontSize(size),
...(align && { textAlign: align }),
...(uppercase && { textTransform: 'uppercase' }),
...(strikethrough && { textDecorationLine: 'line-through' }),
}))

export const Text = ({ as, balance, children, className, ...rest }: TextProps) => (
Expand Down

0 comments on commit c2ee004

Please sign in to comment.