Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DONT MERGE] feat: load limited-time offer signals on the client side #14897

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/Components/Artwork/Details/BidTimerLine.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { EmptyLine } from "Components/Artwork/Details/Details"
import { useArtworkGridContext } from "Components/ArtworkGrid/ArtworkGridContext"
import { useTimer } from "Utils/Hooks/useTimer"
import { Text } from "@artsy/palette"
Expand Down Expand Up @@ -64,7 +63,7 @@ export const BidTimerLine: React.FC<React.PropsWithChildren<BidTimerLineProps>>
}

if (!lotClosesAt || numDays > 5 || hasBiddingEnded) {
return <EmptyLine />
return null
}

const renderLotCloseTime = [
Expand Down
153 changes: 45 additions & 108 deletions src/Components/Artwork/Details/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import * as React from "react"
import { createFragmentContainer, graphql } from "react-relay"
import styled from "styled-components"
import { RouterLink, RouterLinkProps } from "System/Components/RouterLink"
import { useTimer } from "Utils/Hooks/useTimer"
import { Details_artwork$data } from "__generated__/Details_artwork.graphql"
import { HoverDetailsFragmentContainer } from "Components/Artwork/HoverDetails"
import { SaveButtonQueryRenderer } from "Components/Artwork/SaveButton/SaveButton"
import { ConsignmentSubmissionStatusFragmentContainer } from "Components/Artwork/ConsignmentSubmissionStatus"
import HighDemandIcon from "@artsy/icons/HighDemandIcon"
import { BidTimerLine } from "./BidTimerLine"
import { PrimaryLabelLine } from "Components/Artwork/Details/PrimaryLabelLine"
import { PrimaryLabelLineQueryRenderer } from "./PrimaryLabelLine"
import { SaleMessageQueryRenderer } from "./SaleMessage"

export interface DetailsProps {
artwork: Details_artwork$data
Expand All @@ -32,13 +32,10 @@ export interface DetailsProps {
renderSaveButton?: (artworkId: string) => React.ReactNode
}

interface SaleInfoLineProps extends DetailsProps {
showActivePartnerOffer: boolean
}

interface SaleMessageProps extends DetailsProps {
showActivePartnerOffer: boolean
}
const LINE_HEIGHT = 22
const NUM_OF_LINES = 5
const CONTAINER_HEIGHT = LINE_HEIGHT * NUM_OF_LINES
const LINE_HEIGHT_PX = LINE_HEIGHT + "px"

const StyledConditionalLink = styled(RouterLink)`
color: ${themeGet("colors.black100")};
Expand All @@ -62,7 +59,7 @@ const ArtistLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
}) => {
if (cultural_maker) {
return (
<Text variant="sm-display" lineHeight="22px" overflowEllipsis>
<Text variant="sm-display" lineHeight={LINE_HEIGHT_PX} overflowEllipsis>
{cultural_maker}
</Text>
)
Expand All @@ -71,7 +68,7 @@ const ArtistLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
if (!artists?.length) {
if (showSaveButton) {
return (
<Text variant="sm-display" lineHeight="22px" overflowEllipsis>
<Text variant="sm-display" lineHeight={LINE_HEIGHT_PX} overflowEllipsis>
Artist Unavailable
</Text>
)
Expand All @@ -81,7 +78,7 @@ const ArtistLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
}

return (
<Text variant="sm-display" lineHeight="22px" overflowEllipsis>
<Text variant="sm-display" lineHeight={LINE_HEIGHT_PX} overflowEllipsis>
{artists.map((artist, i) => {
if (!artist || !artist.href || !artist.name) return null

Expand All @@ -104,7 +101,7 @@ const TitleLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
<ConditionalLink includeLinks={includeLinks} to={href}>
<Text
variant="sm-display"
lineHeight="22px"
lineHeight={LINE_HEIGHT_PX}
color="black60"
overflowEllipsis
>
Expand All @@ -123,7 +120,7 @@ const PartnerLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
return (
<Text
variant="sm-display"
lineHeight="22px"
lineHeight={LINE_HEIGHT_PX}
color="black60"
overflowEllipsis
>
Expand All @@ -137,7 +134,7 @@ const PartnerLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
<ConditionalLink includeLinks={includeLinks} to={partner?.href}>
<Text
variant="sm-display"
lineHeight="22px"
lineHeight={LINE_HEIGHT_PX}
color="black60"
overflowEllipsis
>
Expand All @@ -150,16 +147,15 @@ const PartnerLine: React.FC<React.PropsWithChildren<DetailsProps>> = ({
return null
}

const SaleInfoLine: React.FC<React.PropsWithChildren<SaleInfoLineProps>> = props => {
const { showActivePartnerOffer } = props
const SaleInfoLine: React.FC<React.PropsWithChildren<DetailsProps>> = props => {
const { lotClosesAt } = props.artwork.collectorSignals?.auction ?? {}
const { liveBiddingStarted } = props.artwork.collectorSignals?.auction ?? {}

if (lotClosesAt && new Date(lotClosesAt) <= new Date()) {
return (
<Text
variant="sm-display"
lineHeight="22px"
lineHeight={LINE_HEIGHT_PX}
color="black100"
fontWeight="bold"
>
Expand All @@ -170,7 +166,7 @@ const SaleInfoLine: React.FC<React.PropsWithChildren<SaleInfoLineProps>> = props

if (liveBiddingStarted) {
return (
<Text variant="sm-display" lineHeight="22px" color="blue100">
<Text variant="sm-display" lineHeight={LINE_HEIGHT_PX} color="blue100">
Bidding live now
</Text>
)
Expand All @@ -180,60 +176,34 @@ const SaleInfoLine: React.FC<React.PropsWithChildren<SaleInfoLineProps>> = props
<Flex flexDirection="row" alignItems="center">
<Text
variant="sm-display"
lineHeight="22px"
lineHeight={LINE_HEIGHT_PX}
color="black100"
fontWeight="bold"
overflowEllipsis
>
<SaleMessage {...props} /> <BidInfo {...props} />
<SaleMessageQueryRenderer {...props} id={props.artwork.internalID} />{" "}
<BidInfo {...props} />
</Text>
{showActivePartnerOffer && <ActivePartnerOfferTimer {...props} />}
</Flex>
)
}

export const EmptyLine: React.FC<React.PropsWithChildren<unknown>> = () => {
return (
<Text variant="xs" lineHeight="22px">
&nbsp;
</Text>
)
}

const HighDemandInfo = () => {
return (
<Flex flexDirection="row" alignItems="center">
<HighDemandIcon fill="blue100" />
<Text variant="sm-display" lineHeight="22px" color="blue100" ml={0.3}>
<Text
variant="sm-display"
lineHeight={LINE_HEIGHT_PX}
color="blue100"
ml={0.3}
>
&nbsp;High Demand
</Text>
</Flex>
)
}

const NBSP = " "

const SaleMessage: React.FC<React.PropsWithChildren<SaleMessageProps>> = props => {
const {
artwork: { sale, sale_message, sale_artwork, collectorSignals },
showActivePartnerOffer,
} = props

if (sale?.is_auction && !sale?.is_closed) {
const highestBid_display = sale_artwork?.highest_bid?.display
const openingBid_display = sale_artwork?.opening_bid?.display

return <>{highestBid_display || openingBid_display || ""}</>
}

if (showActivePartnerOffer) {
return <>{collectorSignals?.partnerOffer?.priceWithDiscount?.display}</>
}

// NBSP is used to prevent un-aligned carousels
return <>{sale_message ?? NBSP}</>
}

const BidInfo: React.FC<React.PropsWithChildren<DetailsProps>> = ({
artwork: { collectorSignals, sale, sale_artwork },
}) => {
Expand All @@ -256,29 +226,6 @@ const BidInfo: React.FC<React.PropsWithChildren<DetailsProps>> = ({
)
}

const ActivePartnerOfferTimer: React.FC<React.PropsWithChildren<DetailsProps>> = ({
artwork: { collectorSignals },
}) => {
const SEPARATOR = <>&nbsp;</>
const { endAt } = collectorSignals?.partnerOffer ?? {}
const { time } = useTimer(endAt ?? "")
const { days, hours } = time

return (
<Text
variant="sm-display"
lineHeight="22px"
color="blue100"
px={0.5}
alignSelf="flex-start"
>
Exp.{SEPARATOR}
{Number(days)}d{SEPARATOR}
{Number(hours)}h{SEPARATOR}
</Text>
)
}

export const Details: React.FC<React.PropsWithChildren<DetailsProps>> = ({
contextModule,
hideArtistName,
Expand Down Expand Up @@ -310,17 +257,11 @@ export const Details: React.FC<React.PropsWithChildren<DetailsProps>> = ({
showHighDemandIcon &&
!isConsignmentSubmission

const partnerOffer = rest?.artwork?.collectorSignals?.partnerOffer
const isAuction = rest?.artwork?.sale?.is_auction ?? false
const artworkId = rest?.artwork?.internalID

const showActivePartnerOffer: boolean =
!isAuction && !!partnerOffer && contextModule !== "activity"

const showPrimaryLabelLine: boolean =
!!rest?.artwork?.collectorSignals?.primaryLabel && !isAuction

const padForPrimaryLabelLine: boolean =
contextModule !== "activity" && !showPrimaryLabelLine
const primaryLabel = rest?.artwork?.collectorSignals?.primaryLabel
const showPrimaryLabelLine: boolean = !isAuction

// FIXME: Extract into a real component
const renderSaveButtonComponent = () => {
Expand Down Expand Up @@ -352,12 +293,16 @@ export const Details: React.FC<React.PropsWithChildren<DetailsProps>> = ({
}

return (
<Box>
<Box height={CONTAINER_HEIGHT + "px"}>
{isAuctionArtwork && (
<Flex flexDirection="row">
<Join separator={<Spacer x={1} />}>
{!hideLotLabel && (
<Text variant="sm-display" lineHeight="22px" flexShrink={0}>
<Text
variant="sm-display"
lineHeight={LINE_HEIGHT_PX}
flexShrink={0}
>
LOT {rest.artwork?.sale_artwork?.lotLabel}
</Text>
)}
Expand All @@ -371,7 +316,12 @@ export const Details: React.FC<React.PropsWithChildren<DetailsProps>> = ({
maxWidth={showPrimaryLabelLine ? "95%" : "75%"}
overflow="hidden"
>
{showPrimaryLabelLine && <PrimaryLabelLine artwork={rest.artwork} />}
{showPrimaryLabelLine && (
<PrimaryLabelLineQueryRenderer
id={artworkId}
label={primaryLabel}
/>
)}
{!hideArtistName && (
<ArtistLine showSaveButton={showSaveButton} {...rest} />
)}
Expand All @@ -395,16 +345,9 @@ export const Details: React.FC<React.PropsWithChildren<DetailsProps>> = ({
<ConsignmentSubmissionStatusFragmentContainer artwork={rest.artwork} />
)}

{!hideSaleInfo && (
<SaleInfoLine
showActivePartnerOffer={showActivePartnerOffer}
{...rest}
/>
)}
{!hideSaleInfo && <SaleInfoLine {...rest} />}

<BidTimerLine artwork={rest.artwork} />

{padForPrimaryLabelLine && <EmptyLine />}
{isAuction && <BidTimerLine artwork={rest.artwork} />}
</Box>
)
}
Expand All @@ -428,12 +371,6 @@ export const DetailsFragmentContainer = createFragmentContainer(Details, {
registrationEndsAt
onlineBiddingExtended
}
partnerOffer {
endAt
priceWithDiscount {
display
}
}
}
sale_message: saleMessage
cultural_maker: culturalMaker
Expand Down Expand Up @@ -504,23 +441,23 @@ export const DetailsPlaceholder: React.FC<React.PropsWithChildren<DetailsPlaceho
return (
<>
{!hideArtistName && (
<SkeletonText variant="sm-display" lineHeight="22px">
<SkeletonText variant="sm-display" lineHeight={LINE_HEIGHT_PX}>
Artist Name
</SkeletonText>
)}

<SkeletonText variant="sm-display" lineHeight="22px">
<SkeletonText variant="sm-display" lineHeight={LINE_HEIGHT_PX}>
Artwork Title
</SkeletonText>

{!hidePartnerName && (
<SkeletonText variant="sm-display" lineHeight="22px">
<SkeletonText variant="sm-display" lineHeight={LINE_HEIGHT_PX}>
Partner
</SkeletonText>
)}

{!hideSaleInfo && (
<SkeletonText variant="sm-display" lineHeight="22px">
<SkeletonText variant="sm-display" lineHeight={LINE_HEIGHT_PX}>
Price
</SkeletonText>
)}
Expand Down
Loading