-
Notifications
You must be signed in to change notification settings - Fork 126
[PAY-3213] ChatListBlastItem mobile UI #9656
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
Conversation
|
|
Preview this change https://demo.audius.co/rt-mobile-chat-blast-item |
| audience, | ||
| audience_content_id: audienceContentId, | ||
| audience_content_type: audienceContentType | ||
| } = chat as ChatBlast |
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 potential jank. i can't do if is_blast return null bc hooks are below, and they depend on the blast-specific fields.
i could pass the whole chat (of type ChatBlast) in but i prefer passing in the ID and selecting at the leaf?
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.
chatgpt has offered: = chat?.is_blast ? chat : ({} as ChatBlast)
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 it's a tricky one. There are a couple of ways to do this.
One way is to split it up into a child component where you only render the child component when the data matches the pattern you're looking for.
const BlastChat = ({chat}) => {
return <SomeStuffUsingTheChatFields} />
}
const ChatComponent = ({chatId}) => {
const chat = useProxySelector((state) => getChat(state, chatId), [chatId])
return is_blast ? <BlastChat chat={chat} /> : null
}
or something like that. You can also split it into a "loader" and "display" component, where the exported component is just in charge of the hook which fetches the data, and the display component is an internal component in the module which takes in the fetched data (not optionally) and assumes it will be fully formed and have all the necessary fields. That way there isn't a bunch of casting/null-checking/etc.
The general idea is if you find yourself in a place where you want to return null before some other hooks run that depend on data that may or may not exist, then you move those hooks into a nested component and conditionally render said component based on whether the data exists.
I would caution against trying to push absolutely all data fetching down into the leaf. It's okay if the "leaf" is a series of nested "display" components that all act on pieces of a single piece of data that's fetched at a relatively low point.
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 would solve my problems. i can pass the chat object in its entirety and guarantee that it will be a ChatBlast. perhaps i am over-eager in selecting at leaf.
| } = chat as ChatBlast | ||
|
|
||
| const decodedContentId = audienceContentId | ||
| ? decodeHashId(audienceContentId) ?? undefined |
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 also weird - decodeHashId could return null but i want decodedContentId to only be number | undefined
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.
If you wanted a slightly cleaner version, you could write the inverse of the OptionalId zod schema: the OptionalHashId. The idea being that you could then do OptionalHashId.parse(audienceContentId) and it will either give you a number or undefined.
However, I would also say that this field should already be parsed before we get here. The pattern being established in SDK migration is that if you need to transform something that comes back from the API, you use an adapter on the value right after its fetched. And that adapter will decode all the ids for you.
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.
ah nice.. i will see if we can do this.
| { | ||
| playlistId: decodedContentId! | ||
| }, | ||
| { disabled: !audienceContentId || audienceContentType !== 'album' } |
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.
Should this not be !decodedContentId? Since that's the argument you're passing above...
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.
hm actually i think it doesn't matter bc decodedContentId comes from audienceContentId.. but i guess it's cleaner
| } = chat as ChatBlast | ||
|
|
||
| const decodedContentId = audienceContentId | ||
| ? decodeHashId(audienceContentId) ?? undefined |
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.
If you wanted a slightly cleaner version, you could write the inverse of the OptionalId zod schema: the OptionalHashId. The idea being that you could then do OptionalHashId.parse(audienceContentId) and it will either give you a number or undefined.
However, I would also say that this field should already be parsed before we get here. The pattern being established in SDK migration is that if you need to transform something that comes back from the API, you use an adapter on the value right after its fetched. And that adapter will decode all the ids for you.
| audience, | ||
| audience_content_id: audienceContentId, | ||
| audience_content_type: audienceContentType | ||
| } = chat as ChatBlast |
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 it's a tricky one. There are a couple of ways to do this.
One way is to split it up into a child component where you only render the child component when the data matches the pattern you're looking for.
const BlastChat = ({chat}) => {
return <SomeStuffUsingTheChatFields} />
}
const ChatComponent = ({chatId}) => {
const chat = useProxySelector((state) => getChat(state, chatId), [chatId])
return is_blast ? <BlastChat chat={chat} /> : null
}
or something like that. You can also split it into a "loader" and "display" component, where the exported component is just in charge of the hook which fetches the data, and the display component is an internal component in the module which takes in the fetched data (not optionally) and assumes it will be fully formed and have all the necessary fields. That way there isn't a bunch of casting/null-checking/etc.
The general idea is if you find yourself in a place where you want to return null before some other hooks run that depend on data that may or may not exist, then you move those hooks into a nested component and conditionally render said component based on whether the data exists.
I would caution against trying to push absolutely all data fetching down into the leaf. It's okay if the "leaf" is a series of nested "display" components that all act on pieces of a single piece of data that's fetched at a relatively low point.
amendelsohn
left a comment
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.
Awesome!
| width={spacing.xl} | ||
| height={spacing.xl} |
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.
isn't there a size prop?
maybe not for mobile?
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.
seems like no :(
| useChatBlastAudienceContent({ | ||
| chat | ||
| }) |
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.
love this change!
can reuse the hook for web too?
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.
yep! slots in nicely
|
Preview this change https://demo.audius.co/rt-mobile-chat-blast-item |
[34d5a5a] [PAY-3213] ChatListBlastItem mobile UI (#9656) Reed [518f4d8] fix typecheck on main (#9669) Andrew Mendelsohn [f183d96] fix type for spl_usdc_payout_wallet on user adapter (#9667) Randy Schott [dab6070] [QA-1528] Move audius-query force ref tracking to useState (#9661) Andrew Mendelsohn [d9022cb] fix typecheck in ChatBlastSelectAudienceFields (#9668) Andrew Mendelsohn [cdb428a] [QA-1529] Add guard for -1 ids to audius-query api hooks (#9647) Andrew Mendelsohn [ec1dd85] [QA-1542] Fix mobile top supporters crashing profile page (#9646) Andrew Mendelsohn [7f49a62] [PAY-3416] Adds v1 account endpoint (#9651) Randy Schott [807d569] [C-5009] Add debug theme (#9611) Dylan Jeffers [9f75690] [C-5005] Add comment counts (#9630) Dylan Jeffers [dc74998] [C-4872, C-4993, QA-1538] Add ComposerInput component and update comments and DMs to user the input (#9638) Kyle Shanks [2bec1f2] [PAY-3420] Update styles on checkout UI (#9649) Raymond Jacobson [d90eeac] [QA-1545] Fix cover art size on album search results (#9654) Raymond Jacobson [842a762] Set audienceContentType=track for remix chat blasts (#9655) Reed [0e6b44e] [C-4975] Comments pagination (#9633) JD Francis [85fe0e7] Display audience counts in chat blast items (#9640) Reed [8236a47] [PAY-3401] Consolidate pay with anything tx (#9645) Raymond Jacobson [f897d8f] [PAY-3411] Enable monetization for everyone when network cut is enabled (#9644) Marcus Pasell [0902048] Add stems api for v1 (#9513) Raymond Jacobson [d04bf16] [C-4956] Add mobile comments sort ui (#9637) Sebastian Klingler [b915249] Fix purchasers count in chat blast modal (#9639) Reed [adf2207] [PAY-3370] Always use encoded content IDs in chats (#9636) Reed [53fe54e] [PAY-3388] Migrate feed to SDK (#9593) Randy Schott [59435ae] Show content title in chat blast item (#9627) Reed [824fc47] [C-4752] Reduce border width for small Avatar (#9612) Dylan Jeffers [fa9b498] [C-4952] Mobile comment overflow action confirmations (#9622) Sebastian Klingler [065e8b8] [PAY-3408][PAY-3409][PAY-3408][PAY-3405][PAY-3413] Update Sales/Purchase Modal (#9624) Marcus Pasell [04f810a] [PAY-3404] Fix floor() for negative numbers that are already floored (#9623) Marcus Pasell [fdc7cf3] Fix purchasing without network split (#9629) Marcus Pasell [682e7d4] [PAY-3410][PAY-3406] Update Sales Table help link and "Value" => "Total" (#9625) Marcus Pasell [2e621bb] [QA-1439] Don't block gated tracks from being remixes (#9620) Andrew Mendelsohn [cb753b3] [C-5008] Add single and multi lineHeight options to Text (#9610) Dylan Jeffers [11911da] [PAY-3378] Disable blast audiences radios with no recipients (#9619) Reed [826d3ae] Only add blasts to store for sender (#9617) Reed [661cca7] [PAY-3206] Populate content targeting dropdowns for blast modal (web) (#9601) Andrew Mendelsohn [f365f01] Add support for expand rounding mode to FixedDecimal (#9606) Marcus Pasell [d6344cb] Fix web external-text-link style propagation (#9609) Dylan Jeffers [90b3b41] [PAY-3324] Add copy notice around network take rate (#9608) Marcus Pasell [d876547] Release mobile apps to 113 (#9614) Dylan Jeffers [e9091d8] [C-5001] Add comment disabling for tracks (#9594) Dylan Jeffers [66b1e99] Fix broken common tests (#9605) Marcus Pasell
Description
ChatListBlastItemto mobileChatListBlastItemto preventchatBlastTitleandcontentTitlefrom wrappingNote - ideally the
contentTitlewould ellipsize as it gets cut off.. some css finnagling to do there but I couldn't figure it out first-pass.How Has This Been Tested?
mobile:


web: