-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GEN-748 | Add CRM Retargeting Landing Page (#2741)
<!-- PR title: GRW-123 / Feature / Awesome new thing --> ## Describe your changes ![Screenshot 2023-07-11 at 11.50.36.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/OgXegTwxM9IeuXHZyw5h/eb737c5f-f85b-40c4-bbf5-cadf87bced1a/Screenshot%202023-07-11%20at%2011.50.36.png) - Implement a draft version of the CRM landing page to be used for re-targeting - List all price intents that have been confirmed but not yet added to cart <!-- What changes are made? If there are many changes, a list might be a good format. If it makes sense, add screenshots and/or screen recordings here. --> ## Justify why they are needed Design is just a draft but this is necessary to understand if we need to make any changes to the overall idea and/or API. ## Checklist before requesting a review - [ ] I have performed a self-review of my code
- Loading branch information
1 parent
d41a830
commit 1d30a97
Showing
9 changed files
with
221 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
apps/store/src/components/RetargetingPage/MultiTierOffer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { useTranslation } from 'next-i18next' | ||
import { CartItem } from '@/components/CartItem/CartItem' | ||
import { type ProductOfferFragment } from '@/services/apollo/generated' | ||
import { ProductPageLink } from './ProductPageLink' | ||
|
||
type Props = { | ||
product: ProductOfferFragment['variant']['product'] | ||
offers: Array<ProductOfferFragment> | ||
defaultOffer: ProductOfferFragment | ||
} | ||
|
||
export const MultiTierOffer = (props: Props) => { | ||
const { t } = useTranslation() | ||
|
||
return ( | ||
<CartItem | ||
pillow={props.product.pillowImage} | ||
displayName={props.product.displayNameFull} | ||
cost={props.defaultOffer.cost} | ||
documents={props.defaultOffer.variant.documents} | ||
productName={props.product.name} | ||
data={props.defaultOffer.priceIntentData} | ||
startDate={props.defaultOffer.startDate ? new Date(props.defaultOffer.startDate) : undefined} | ||
> | ||
<ProductPageLink href={props.product.pageLink}> | ||
{t('CRM_RETARGETING_CHOOSE_TIER')} | ||
</ProductPageLink> | ||
</CartItem> | ||
) | ||
} |
17 changes: 17 additions & 0 deletions
17
apps/store/src/components/RetargetingPage/ProductPageLink.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ButtonNextLink } from '@/components/ButtonNextLink' | ||
import { SpaceFlex } from '@/components/SpaceFlex/SpaceFlex' | ||
|
||
type Props = { | ||
href: string | ||
children: string | ||
} | ||
|
||
export const ProductPageLink = (props: Props) => { | ||
return ( | ||
<ButtonNextLink href={props.href} size="medium" variant="secondary-alt"> | ||
<SpaceFlex space={0.5} align="center"> | ||
{props.children} | ||
</SpaceFlex> | ||
</ButtonNextLink> | ||
) | ||
} |
82 changes: 82 additions & 0 deletions
82
apps/store/src/components/RetargetingPage/RetargetingPage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import styled from '@emotion/styled' | ||
import { type ComponentProps, useMemo } from 'react' | ||
import { Heading, Space, theme } from 'ui' | ||
import { GridLayout } from '@/components/GridLayout/GridLayout' | ||
import { usePriceIntentsQuery } from '@/services/apollo/generated' | ||
import { MultiTierOffer } from './MultiTierOffer' | ||
import { SingleTierOffer } from './SingleTierOffer' | ||
|
||
type Props = { | ||
shopSessionId: string | ||
} | ||
|
||
type OfferSingle = ComponentProps<typeof SingleTierOffer> & { type: 'single' } | ||
type OfferMultiple = ComponentProps<typeof MultiTierOffer> & { type: 'multiple' } | ||
type Offer = (OfferSingle | OfferMultiple) & { key: string } | ||
|
||
export const RetargetingPage = (props: Props) => { | ||
const result = usePriceIntentsQuery({ variables: { shopSessionId: props.shopSessionId } }) | ||
|
||
const offers = useMemo(() => { | ||
if (!result.data) return [] | ||
|
||
const cartOffers = new Set(result.data.shopSession.cart.entries.map((item) => item.id)) | ||
|
||
return result.data.shopSession.priceIntents.reduce<Array<Offer>>((total, item) => { | ||
if (item.offers.some((offer) => cartOffers.has(offer.id))) { | ||
return total | ||
} | ||
|
||
if (item.offers.length === 1) { | ||
total.push({ | ||
key: item.id, | ||
type: 'single', | ||
product: item.offers[0].variant.product, | ||
offer: item.offers[0], | ||
}) | ||
} else if (item.offers.length > 1) { | ||
total.push({ | ||
key: item.id, | ||
type: 'multiple', | ||
product: item.offers[0].variant.product, | ||
defaultOffer: item.offers[0], | ||
offers: item.offers, | ||
}) | ||
} | ||
|
||
return total | ||
}, []) | ||
}, [result.data]) | ||
|
||
return ( | ||
<GridLayout.Root> | ||
<GridLayoutContent width={{ md: '2/3', lg: '1/2', xl: '1/3' }} align="center"> | ||
<Space y={2}> | ||
<Heading as="h1" variant={{ _: 'serif.40' }} align="center"> | ||
Your current offers | ||
</Heading> | ||
|
||
<List> | ||
{offers.map((item) => ( | ||
<li key={item.key}> | ||
{item.type === 'single' && <SingleTierOffer {...item} />} | ||
{item.type === 'multiple' && <MultiTierOffer {...item} />} | ||
</li> | ||
))} | ||
</List> | ||
</Space> | ||
</GridLayoutContent> | ||
</GridLayout.Root> | ||
) | ||
} | ||
|
||
const GridLayoutContent = styled(GridLayout.Content)({ | ||
paddingBlock: theme.space.lg, | ||
minHeight: '60vh', | ||
}) | ||
|
||
const List = styled.ul({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
gap: theme.space.md, | ||
}) |
42 changes: 42 additions & 0 deletions
42
apps/store/src/components/RetargetingPage/SingleTierOffer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import styled from '@emotion/styled' | ||
import { useTranslation } from 'next-i18next' | ||
import { Button, theme } from 'ui' | ||
import { CartItem } from '@/components/CartItem/CartItem' | ||
import { type ProductOfferFragment } from '@/services/apollo/generated' | ||
import { ProductPageLink } from './ProductPageLink' | ||
|
||
type Props = { | ||
offer: ProductOfferFragment | ||
product: ProductOfferFragment['variant']['product'] | ||
} | ||
|
||
export const SingleTierOffer = (props: Props) => { | ||
const { t } = useTranslation('cart') | ||
|
||
return ( | ||
<CartItem | ||
pillow={props.product.pillowImage} | ||
displayName={props.product.displayNameFull} | ||
cost={props.offer.cost} | ||
documents={props.offer.variant.documents} | ||
productName={props.product.name} | ||
data={props.offer.priceIntentData} | ||
startDate={props.offer.startDate ? new Date(props.offer.startDate) : undefined} | ||
> | ||
<ButtonGroup> | ||
<ProductPageLink href={props.product.pageLink}> | ||
{t('CART_ENTRY_EDIT_BUTTON')} | ||
</ProductPageLink> | ||
<Button size="medium" variant="secondary-alt"> | ||
{t('ADD_TO_CART_BUTTON_LABEL')} | ||
</Button> | ||
</ButtonGroup> | ||
</CartItem> | ||
) | ||
} | ||
|
||
const ButtonGroup = styled.div({ | ||
display: 'grid', | ||
gridTemplateColumns: 'repeat(2, 1fr)', | ||
columnGap: theme.space.xs, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
query PriceIntents($shopSessionId: UUID!) { | ||
shopSession(id: $shopSessionId) { | ||
id | ||
cart { | ||
entries { | ||
id | ||
} | ||
} | ||
priceIntents { | ||
id | ||
offers { | ||
...ProductOffer | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ fragment ProductOffer on ProductOffer { | |
product { | ||
id | ||
name | ||
pageLink | ||
displayNameFull | ||
pillowImage { | ||
id | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { type GetServerSideProps, type NextPageWithLayout } from 'next' | ||
import { getLayoutWithMenuProps } from '@/components/LayoutWithMenu/getLayoutWithMenuProps' | ||
import { LayoutWithMenu } from '@/components/LayoutWithMenu/LayoutWithMenu' | ||
import { RetargetingPage } from '@/components/RetargetingPage/RetargetingPage' | ||
|
||
type Props = { | ||
shopSessionId: string | ||
} | ||
|
||
type Params = { | ||
shopSessionId: string | ||
} | ||
|
||
const NextPage: NextPageWithLayout<Props> = RetargetingPage | ||
|
||
export const getServerSideProps: GetServerSideProps<Props, Params> = async (context) => { | ||
if (!context.params) throw new Error('No params in context') | ||
|
||
const { shopSessionId } = context.params | ||
|
||
return { | ||
props: { | ||
...(await getLayoutWithMenuProps(context)), | ||
shopSessionId, | ||
}, | ||
} | ||
} | ||
|
||
NextPage.getLayout = (children) => <LayoutWithMenu>{children}</LayoutWithMenu> | ||
|
||
export default NextPage |