Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ export const PartnerOfferCreatedNotification: React.FC<PartnerOfferCreatedNotifi
const noLongerAvailable = !item?.partnerOffer?.isAvailable
const isOfferFromSaves = item?.partnerOffer?.source === "SAVE"

let subtitle = isOfferFromSaves
let subtitle: string | null = isOfferFromSaves

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think in cases like this && reads better. Something like subtitle = isOfferFromSaves && xxx

? "Review the offer on your saved artwork"
: "Review the offer before it expires"
: null

if (noLongerAvailable) {
subtitle =
Expand Down Expand Up @@ -87,7 +87,7 @@ export const PartnerOfferCreatedNotification: React.FC<PartnerOfferCreatedNotifi

<Spacer y={0.5} />

<Text variant="sm-display">{subtitle}</Text>
{!!subtitle && <Text variant="sm-display">{subtitle}</Text>}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact as it now only one possible case I would just inline it here. Subtitle is always the same now so we could text !!isOfferFromSaves && <Text>...</Text>


<Spacer y={0.5} />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe("PartnerOfferCreatedNotification", () => {
expect(screen.getByText("$405,000")).toBeOnTheScreen()
expect(screen.getByText(/List price:\s*\$450,000\s*/)).toBeOnTheScreen()
expect(screen.getByText('"This is a note from the gallery"')).toBeOnTheScreen()
expect(screen.getByText("Review the offer before it expires")).toBeOnTheScreen()
expect(screen.queryByText("Review the offer before it expires")).not.toBeOnTheScreen()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this changes this .not test becomes more confusing than anything.... Like we could have texted for any random text not there? One would not be able to find it in code as now it would never appear. I would just remove this line.

expect(screen.queryByText("Review the offer on your saved artwork")).not.toBeOnTheScreen()
expect(screen.queryByText("Manage Saves")).not.toBeOnTheScreen()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,52 +95,70 @@ describe("conversation about an artwork with inquiry checkout enabled", () => {
expect(screen.UNSAFE_queryAllByType(OpenInquiryModalButton)).toHaveLength(1)
})

describe("with an active partner offer", () => {
const futureISO = () => new Date(Date.now() + 60 * 60 * 1000).toISOString()

const partnerOfferResolvers = {
Conversation: () => ({
items: [{ item: { __typename: "Artwork" }, liveArtwork: { __typename: "Artwork" } }],
activeOrders: { edges: [] },
}),
// Ensures both `items.item` and `liveArtwork` resolve to the same artwork id
// that the offer below references.
Artwork: () => ({ internalID: "123", href: "/artwork/foo", isOfferableFromInquiry: true }),
Me: () => ({
partnerOffersConnection: {
edges: [
{
node: {
internalID: "partner-offer-id",
artworkId: "123",
endAt: futureISO(),
isAvailable: true,
priceWithDiscount: { display: "US$450" },
// The `partnerOffersConnection` query fetches both `BULK` (sent via the
// partner dashboard's send-offer tool) and `PERSONALIZED` offer types.
// Eigen can't distinguish between the two once fetched, so both should
// behave identically here.
describe.each([["a personalized partner offer"], ["a bulk offer (send offer)"]])(
"with %s",
() => {
const futureISO = () => new Date(Date.now() + 60 * 60 * 1000).toISOString()
const pastISO = () => new Date(Date.now() - 60 * 60 * 1000).toISOString()

const buildPartnerOfferResolvers = (offerOverrides: Record<string, unknown> = {}) => ({
Conversation: () => ({
items: [{ item: { __typename: "Artwork" }, liveArtwork: { __typename: "Artwork" } }],
activeOrders: { edges: [] },
}),
// Ensures both `items.item` and `liveArtwork` resolve to the same artwork id
// that the offer below references.
Artwork: () => ({ internalID: "123", href: "/artwork/foo", isOfferableFromInquiry: true }),
Me: () => ({
partnerOffersConnection: {
edges: [
{
node: {
internalID: "partner-offer-id",
artworkId: "123",
endAt: futureISO(),
isAvailable: true,
priceWithDiscount: { display: "US$450" },
...offerOverrides,
},
},
},
],
},
}),
}
],
},
}),
})

it("replaces the inquiry buttons with the offer banner when the flag is on", () => {
__globalStoreTestUtils__?.injectFeatureFlags({ AREnableConversationPartnerOffers: true })
it("replaces the inquiry buttons with the offer banner when the flag is on", () => {
__globalStoreTestUtils__?.injectFeatureFlags({ AREnableConversationPartnerOffers: true })

renderWithRelay(partnerOfferResolvers)
renderWithRelay(buildPartnerOfferResolvers())

// The dedicated offer banner replaces the inquiry transaction buttons.
expect(screen.UNSAFE_queryAllByType(OpenInquiryModalButton)).toHaveLength(0)
expect(screen.UNSAFE_queryAllByType(ConversationPartnerOfferCTA)).toHaveLength(1)
})
// The dedicated offer banner replaces the inquiry transaction buttons.
expect(screen.UNSAFE_queryAllByType(OpenInquiryModalButton)).toHaveLength(0)
expect(screen.UNSAFE_queryAllByType(ConversationPartnerOfferCTA)).toHaveLength(1)
})

it("still renders the inquiry buttons when the flag is off", () => {
__globalStoreTestUtils__?.injectFeatureFlags({ AREnableConversationPartnerOffers: false })
it("still renders the inquiry buttons when the flag is off", () => {
__globalStoreTestUtils__?.injectFeatureFlags({ AREnableConversationPartnerOffers: false })

renderWithRelay(partnerOfferResolvers)
renderWithRelay(buildPartnerOfferResolvers())

expect(screen.UNSAFE_queryAllByType(OpenInquiryModalButton)).toHaveLength(1)
})
})
expect(screen.UNSAFE_queryAllByType(OpenInquiryModalButton)).toHaveLength(1)
})

it("falls back to the inquiry buttons once the offer expires", () => {
__globalStoreTestUtils__?.injectFeatureFlags({ AREnableConversationPartnerOffers: true })

renderWithRelay(buildPartnerOfferResolvers({ endAt: pastISO() }))

expect(screen.UNSAFE_queryAllByType(ConversationPartnerOfferCTA)).toHaveLength(0)
expect(screen.UNSAFE_queryAllByType(OpenInquiryModalButton)).toHaveLength(1)
})
}
)

it("renders the payment failed message if the payment failed", () => {
renderWithOrders({ lastTransactionFailed: true, mode: "OFFER" })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,37 @@ describe("ConversationPartnerOfferCTA", () => {
__globalStoreTestUtils__?.injectFeatureFlags({ AREnableConversationPartnerOffers: true })
})

it("renders the offer banner, tracks it, and navigates to the artwork with the partner offer id", () => {
renderWithRelay(offerResolvers())

expect(screen.getByText("Offer received for $450")).toBeTruthy()

expect(mockTrackEvent).toHaveBeenCalledWith({
action: "partnerOfferInConversationViewed",
context_owner_id: "conversation-id",
context_owner_type: "conversation",
})

fireEvent.press(screen.getByTestId("partnerOfferActionLink"))
expect(navigate).toHaveBeenCalledWith("/artwork/some-artwork?partner_offer_id=partner-offer-id")
})
// The `partnerOffersConnection` query fetches both `BULK` (sent via the
// partner dashboard's send-offer tool) and `PERSONALIZED` offer types.
// Eigen can't distinguish between the two once fetched, so the banner
// should render identically for both.
describe.each([["a personalized partner offer"], ["a bulk offer (send offer)"]])(
"with %s",
() => {
it("renders the offer banner, tracks it, and navigates to the artwork with the partner offer id", () => {
renderWithRelay(offerResolvers())

expect(screen.getByText("Offer received for $450")).toBeTruthy()

expect(mockTrackEvent).toHaveBeenCalledWith({
action: "partnerOfferInConversationViewed",
context_owner_id: "conversation-id",
context_owner_type: "conversation",
})

fireEvent.press(screen.getByTestId("partnerOfferActionLink"))
expect(navigate).toHaveBeenCalledWith(
"/artwork/some-artwork?partner_offer_id=partner-offer-id"
)
})

it("renders nothing when the offer has expired", () => {
renderWithRelay(offerResolvers({ endAt: pastISO() }))

expect(screen.queryByTestId("partnerOfferActionLink")).toBeNull()
})
}
)

it("falls back to a generic title when there is no discounted price", () => {
renderWithRelay(offerResolvers({ priceWithDiscount: null }))
Expand All @@ -103,12 +120,6 @@ describe("ConversationPartnerOfferCTA", () => {
expect(screen.queryByTestId("partnerOfferActionLink")).toBeNull()
})

it("renders nothing when the offer has expired", () => {
renderWithRelay(offerResolvers({ endAt: pastISO() }))

expect(screen.queryByTestId("partnerOfferActionLink")).toBeNull()
})

it("renders nothing when the offer is unavailable", () => {
renderWithRelay(offerResolvers({ isAvailable: false }))

Expand Down
2 changes: 1 addition & 1 deletion src/app/Scenes/Inbox/hooks/usePartnerOffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const usePartnerOffer = ({ me, artworkId }: UsePartnerOfferProps) => {

const fragment = graphql`
fragment usePartnerOffer_me on Me {
partnerOffersConnection(first: 100, offerType: [PERSONALIZED]) {
partnerOffersConnection(first: 100, offerType: [BULK, PERSONALIZED]) {
edges {
node {
...ConversationPartnerOfferCTA_partnerOffers
Expand Down
Loading