-
Notifications
You must be signed in to change notification settings - Fork 153
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
[WIP] refactor: load limited-time offer signal on the client side #14807
Conversation
} | ||
const LINE_HEIGHT = 22 | ||
const NUM_OF_LINES = 5 | ||
const CONTAINER_HEIGHT = LINE_HEIGHT * NUM_OF_LINES |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation requires logic to make sure we have consistent number of lines (e.g. if there is no badge, we will pad with an empty line). Since we agreed on fixed 5 lines, I feel it's easier to set a fixed container height and just add lines to it, without maintaining the # of lines logic which gets a bit tricky with client-side loaded content.
) | ||
} | ||
|
||
const PartnerOfferLine: React.FC<PartnerOfferLineProps> = ({ artwork }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the combined fifth line that's now fetched and rendered on the client side.
fallback: object | ||
} | ||
|
||
const PartnerOfferedPrice: React.FC<PartnerOfferedPriceProps> = ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the artwork price line which takes the server-side rendered prices (publicly listed price) as the placeholder and dynamically overwrite it, if there is a partner offer fetched on the client side.
I think I'll need to rename this component to make it clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! Fairly straightforward and nothing 'weird' - good and simple.
I think there's the primaryLabel
thing which is what you're referring to in terms of determining precedence to only display one label. My initial thought is that we should be ok w/ sometimes displaying two labels, since we dont know if the offer label exists in the context of caching. Perhaps that means the design needs to change (partner offer collector signal represented differently)?
@@ -430,12 +403,6 @@ export const DetailsFragmentContainer = createFragmentContainer(Details, { | |||
registrationEndsAt | |||
onlineBiddingExtended | |||
} | |||
partnerOffer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hooray!
I wonder if primaryLabel
needs to also be removed here (or updated in MP), as I think it can return the personalized 'offer' label. Or is this perhaps what you refer to in the PR description about the precedence of only displaying one label at most?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I decided to remove partner offer from the primary label field for that reason. After artsy/metaphysics#6220, the primary label will be fully cacheable. I think it's also more aligned with the pattern that separates authenticated data out from non-auth data.
I shared more context on Slack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool - makes sense. I think you're right that schema-wise - of course it's a case-by-case basis - but not mixing authenticated and cacheable data as part of the resolving of the same field (in this case collectorSignals
under the Artwork
type) - is something we should be doing.
I think collector signals might be the only case of that really (🤞), as typically an entire field would be either authenticated or not - and not a more generic-y mix of both as collector signals is.
placeholder={<SaleMessage artwork={artwork} />} | ||
variables={{ id }} | ||
render={({ error, props }) => { | ||
const publicPrice = <SaleMessage artwork={artwork} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clever!
} | ||
|
||
return ( | ||
<PartnerOfferedPriceFragmentContainer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can maybe include a subtle/nice little 'pulse' animation like in
force/src/Apps/Artwork/Components/ArtworkSidebar/ArtworkSidebarCurrentBidInfo.tsx
Line 20 in 4d6f44a
const pulse = keyframes` |
Maybe another way of thinking about it schema/product/design-wise, is that 'collector signals' are always public, cached, show up how they show up - the extra line. You know before rendering if that line / any works in a rail or grid will have them. And then the 'offer'/user-specific messaging has a different appearance entirely, maybe isn't even called a 'collector signal' in our schema and is modeled differently, and is also allowed to show up in addition to the regular public collector signal (maybe as a 'badge' in the corner of the image - not sure the best design here). Do you know if there are any plans for other personalized signals/messaging? That may help inform direction. |
1064829
to
6f75eb5
Compare
#943 Bundle Size — 9.51MiB (-0.35%).c172c74(current) vs ffe4f84 main#484(baseline) Important Bundle introduced 1 and removed 4 duplicate packages – View changed duplicate packages Warning Bundle introduced 3 new packages: web-vitals, @sentry-internal/browser-utils, stylis – View changed packages Bundle metrics
|
Current #943 |
Baseline #484 |
|
---|---|---|
Initial JS | 3.83MiB (-3.07% ) |
3.95MiB |
Initial CSS | 0B |
0B |
Cache Invalidation | 84.09% |
2.04% |
Chunks | 140 (-2.1% ) |
143 |
Assets | 144 (-1.37% ) |
146 |
Modules | 5671 (+0.6% ) |
5637 |
Duplicate Modules | 472 (+3.74% ) |
455 |
Duplicate Code | 6.18% (+5.1% ) |
5.88% |
Packages | 282 (-3.09% ) |
291 |
Duplicate Packages | 39 (-7.14% ) |
42 |
Bundle size by type 2 changes
2 improvements
Current #943 |
Baseline #484 |
|
---|---|---|
JS | 9.28MiB (-0.35% ) |
9.31MiB |
Other | 237.37KiB (-0.2% ) |
237.84KiB |
Bundle analysis report Branch review-app-client-side-offer-sig... Project dashboard
Generated by RelativeCI Documentation Report issue
a4755f2
to
c172c74
Compare
We decided to take a different route and this PR got too big. I'm going to close it and open a new one. Thank you all for the patience! 🙏 |
The type of this PR is: Refactor
This PR solves EMI-2161
Opening a draft PR from the spike. Will need polish and tests, and I realized there are more to be discussed/done, but would like to align on overall direction. 🙏
Description
This loads the partner offer collector signal on the client-side, with the goal of being able to cache artwork grids more comprehensively. It follows the migration pattern by moving the data needing authentication from
FragmentContainer
to a deferredQueryRenderer
.It's more nuanced than a straight migration because the authenticated data can be displayed in-between server-side rendered content, and "inserting" the data on the client side after page renders can lead to content shift. In particular for limited-time offer signals, there 3 pieces of information:
What about the badge that's in the middle of an artwork card?
To avoid content shift for the badge, we agreed on migrating to the new artwork card design on app which combines the badge into the fifth line.
How about the final price that we don't know until fetching partner offers?
To support rendering the client-side loaded data, specifically for partner offered price that replaces the listed price, I spiked on 2 approaches and the team agreed on option 1, simply overwriting server-rendered data when client-side data come back. See below:
Slack discussion and recordings about the 2 options
Option 1 (review app): Render publicly listed price on the backend and dynamically overwrite it after fetching partner offer on the client side.
Option 2 (review app): Defer rendering entire pricing until partner offer is fetched on the client side.
Ah, and I realized there are more... 😓
The limited-time offer signal competes with the "increased interest" and "curator's pick", meaning that an artwork can have multiple badges and we'll only show one, based on defined precedence, in which the limited-time offer is the highest. I guess I'll need to start a new discussion about it...
@artsy/emerald-devs