Skip to content

Commit

Permalink
feat: add bottom sheet to infinite discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
araujobarret committed Dec 20, 2024
1 parent 06a164f commit e80af24
Show file tree
Hide file tree
Showing 34 changed files with 1,249 additions and 64 deletions.
10 changes: 7 additions & 3 deletions src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ContextModule, OwnerType } from "@artsy/cohesion"
import { Join, Spacer, Tabs } from "@artsy/palette-mobile"
import { Flex, Join, Spacer, Tabs } from "@artsy/palette-mobile"
import { ArtistAbout_artist$data } from "__generated__/ArtistAbout_artist.graphql"
import { Articles } from "app/Components/Artist/Articles/Articles"
import { ArtistAboutEmpty } from "app/Components/Artist/ArtistAbout/ArtistAboutEmpty"
import { ArtistAboutRelatedGenes } from "app/Components/Artist/ArtistAbout/ArtistAboutRelatedGenes"
import { Biography } from "app/Components/Artist/Biography"
import { Biography, MAX_WIDTH_BIO } from "app/Components/Artist/Biography"
import { RelatedArtistsRail } from "app/Components/Artist/RelatedArtistsRail"
import { SectionTitle } from "app/Components/SectionTitle"
import { ArtistSeriesMoreSeriesFragmentContainer } from "app/Scenes/ArtistSeries/ArtistSeriesMoreSeries"
import { extractNodes } from "app/utils/extractNodes"
import { createFragmentContainer, graphql } from "react-relay"
Expand Down Expand Up @@ -46,7 +47,10 @@ export const ArtistAbout: React.FC<Props> = ({ artist }) => {
{!!hasBiography && (
<>
<Spacer y={1} />
<Biography artist={artist} />
<Flex maxWidth={MAX_WIDTH_BIO} px={2}>
<SectionTitle title="Biography" />
<Biography artist={artist} />
</Flex>
</>
)}
{!!hasInsights && <ArtistCareerHighlights artist={artist} />}
Expand Down
18 changes: 8 additions & 10 deletions src/app/Components/Artist/Biography.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { Flex, Text } from "@artsy/palette-mobile"
import { Text } from "@artsy/palette-mobile"
import { Biography_artist$key } from "__generated__/Biography_artist.graphql"
import { HTML } from "app/Components/HTML"
import { SectionTitle } from "app/Components/SectionTitle"
import { useState } from "react"
import { graphql, useFragment } from "react-relay"

const MAX_CHARS = 250

export const MAX_WIDTH = 650
export const MAX_WIDTH_BIO = 650

interface BiographyProps {
artist: Biography_artist$key
variant?: "sm" | "xs"
}

export const Biography: React.FC<BiographyProps> = ({ artist }) => {
export const Biography: React.FC<BiographyProps> = ({ artist, variant = "sm" }) => {
const [expanded, setExpanded] = useState(false)
const data = useFragment(query, artist)

Expand All @@ -26,21 +25,20 @@ export const Biography: React.FC<BiographyProps> = ({ artist }) => {
const canExpand = text.length > MAX_CHARS

return (
<Flex maxWidth={MAX_WIDTH} px={2}>
<SectionTitle title="Biography" />
<>
<HTML
html={`${expanded ? text : truncatedText}${
text.length > MAX_CHARS && !expanded ? "... " : " "
}`}
variant="sm"
variant={variant}
/>

{!!canExpand && (
<Text underline onPress={() => setExpanded((e) => !e)} mt={-1}>
<Text underline onPress={() => setExpanded((e) => !e)} mt={-1} variant={variant}>
{expanded ? "Read Less" : "Read More"}
</Text>
)}
</Flex>
</>
)
}

Expand Down
61 changes: 61 additions & 0 deletions src/app/Components/ArtistFollowButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { FollowButton } from "@artsy/palette-mobile"
import { ArtistFollowButtonQuery } from "__generated__/ArtistFollowButtonQuery.graphql"
import { ArtistFollowButton_artist$key } from "__generated__/ArtistFollowButton_artist.graphql"
import { useFollowArtist } from "app/utils/mutations/useFollowArtist"
import { FC } from "react"
import { useLazyLoadQuery, graphql, useFragment } from "react-relay"

interface ArtistFollowButtonProps {
artist: ArtistFollowButton_artist$key
}

export const ArtistFollowButton: FC<ArtistFollowButtonProps> = ({ artist }) => {
const data = useFragment(fragment, artist)
const [commitMutation, isInFlight] = useFollowArtist()

if (!data) {
return null
}

const handleOnPress = () => {
commitMutation({
variables: { input: { artistID: data.internalID, unfollow: data.isFollowed } },
updater: (store) => {
store.get(data.internalID)?.setValue(!data.isFollowed, "isFollowed")
},
})
}

return <FollowButton isFollowed={data.isFollowed} onPress={handleOnPress} loading={isInFlight} />
}

const fragment = graphql`
fragment ArtistFollowButton_artist on Artist {
internalID @required(action: NONE)
isFollowed @required(action: NONE)
}
`

interface ArtistFollowButtonQueryRendererProps {
artistID: string
}

export const ArtistFollowButtonQueryRenderer: FC<ArtistFollowButtonQueryRendererProps> = ({
artistID,
}) => {
const data = useLazyLoadQuery<ArtistFollowButtonQuery>(query, { id: artistID })

if (!data.artist) {
return <FollowButton isFollowed={false} />
}

return <ArtistFollowButton artist={data.artist} />
}

const query = graphql`
query ArtistFollowButtonQuery($id: String!) {
artist(id: $id) {
...ArtistFollowButton_artist
}
}
`
100 changes: 100 additions & 0 deletions src/app/Components/ArtistListItemShort.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { EntityHeader, Flex, Touchable } from "@artsy/palette-mobile"
import { ArtistListItemShortQuery } from "__generated__/ArtistListItemShortQuery.graphql"
import { ArtistListItemShort_artist$key } from "__generated__/ArtistListItemShort_artist.graphql"
import { ArtistFollowButtonQueryRenderer } from "app/Components/ArtistFollowButton"
import { ReadMore } from "app/Components/ReadMore"
import { navigate } from "app/system/navigation/navigate"
import { truncatedTextLimit } from "app/utils/hardware"
import { withSuspense } from "app/utils/hooks/withSuspense"
import { FC } from "react"
import { graphql, useFragment, useLazyLoadQuery } from "react-relay"

interface ArtistListItemShortProps {
artist: ArtistListItemShort_artist$key
}

export const ArtistListItemShort: FC<ArtistListItemShortProps> = ({ artist }) => {
const data = useFragment(fragment, artist)

if (!data) {
return null
}

const image = data.coverArtwork?.image?.cropped?.url ?? undefined
const bio = data?.biographyBlurb?.text
const bioTextLimit = truncatedTextLimit()

const handleOnPress = () => {
navigate(data.href)
}

return (
<>
<Flex flexDirection="row" justifyContent="space-between" alignItems="center">
<Touchable onPress={handleOnPress} style={{ flex: 1 }}>
<EntityHeader
name={data.name}
initials={data.initials}
imageUrl={image}
meta={data.formattedNationalityAndBirthday ?? undefined}
RightButton={<ArtistFollowButtonQueryRenderer artistID={data.internalID} />}
/>
</Touchable>
</Flex>

{!!bio && (
<ReadMore content={bio} maxChars={bioTextLimit} textVariant="xs" linkTextVariant="xs" />
)}
</>
)
}

const fragment = graphql`
fragment ArtistListItemShort_artist on Artist {
internalID @required(action: NONE)
name @required(action: NONE)
initials @required(action: NONE)
href @required(action: NONE)
formattedNationalityAndBirthday
coverArtwork {
image {
cropped(height: 45, width: 45) {
url
}
}
}
biographyBlurb {
text
}
}
`

interface ArtworkListItemShortWithSuspenseProps {
artistSlug: string
}

export const ArtworkListItemShortWithSuspense = withSuspense<ArtworkListItemShortWithSuspenseProps>(
{
Component: ({ artistSlug }) => {
const data = useLazyLoadQuery<ArtistListItemShortQuery>(query, { slug: artistSlug })

if (!data?.artist) {
return null
}

return <ArtistListItemShort artist={data.artist} />
},
LoadingFallback: () => null,
ErrorFallback: () => null,
}
)

const query = graphql`
query ArtistListItemShortQuery($slug: String!) {
artist(id: $slug) {
...ArtistListItemShort_artist
name
}
}
`
9 changes: 7 additions & 2 deletions src/app/Components/Expandable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChevronIcon, Collapse, Flex, Text, Touchable } from "@artsy/palette-mobile"
import { MAX_WIDTH } from "app/Components/Artist/Biography"
import { MAX_WIDTH_BIO } from "app/Components/Artist/Biography"
import { MotiView } from "moti"
import { useState } from "react"

Expand Down Expand Up @@ -30,7 +30,12 @@ export const Expandable: React.FC<ExpandableProps> = ({
}

return (
<Flex borderTopWidth={1} py={1} accessibilityHint="Toggles the accordion" maxWidth={MAX_WIDTH}>
<Flex
borderTopWidth={1}
py={1}
accessibilityHint="Toggles the accordion"
maxWidth={MAX_WIDTH_BIO}
>
<Touchable
onPress={() => handleToggle()}
accessibilityRole="togglebutton"
Expand Down
2 changes: 1 addition & 1 deletion src/app/Components/PartnerEntityHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const PartnerEntityHeader: React.FC<PartnerEntityHeaderProps> = ({ partne
export const PartnerEntityHeaderFragmentContainer = createFragmentContainer(PartnerEntityHeader, {
partner: graphql`
fragment PartnerEntityHeader_partner on Partner {
...PartnerFollowButton_partner
...PartnerFollowButton_deprecated_partner
href
name
cities
Expand Down
70 changes: 70 additions & 0 deletions src/app/Components/PartnerFollowButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { FollowButton } from "@artsy/palette-mobile"
import { PartnerFollowButtonQuery } from "__generated__/PartnerFollowButtonQuery.graphql"
import { PartnerFollowButton_partner$key } from "__generated__/PartnerFollowButton_partner.graphql"
import { useFollowProfile } from "app/utils/mutations/useFollowProfile"
import { FC } from "react"
import { graphql, useFragment, useLazyLoadQuery } from "react-relay"

interface PartnerFollowButtonProps {
partner: PartnerFollowButton_partner$key
}

export const PartnerFollowButton: FC<PartnerFollowButtonProps> = ({ partner }) => {
const data = useFragment(fragment, partner)
const { followProfile, isInFlight } = useFollowProfile({
id: data?.profile.id ?? "",
internalID: data?.profile.internalID ?? "",
isFollowed: !!data?.profile.isFollowed,
})

if (!data) {
return null
}

const handleOnPress = () => {
followProfile()
}

return (
<FollowButton
isFollowed={!!data.profile.isFollowed}
onPress={handleOnPress}
loading={isInFlight}
/>
)
}

const fragment = graphql`
fragment PartnerFollowButton_partner on Partner {
internalID @required(action: NONE)
profile @required(action: NONE) {
id @required(action: NONE)
internalID @required(action: NONE)
isFollowed
}
}
`

interface PartnerFollowButtonQueryRendererProps {
partnerID: string
}

export const PartnerFollowButtonQueryRenderer: FC<PartnerFollowButtonQueryRendererProps> = ({
partnerID,
}) => {
const data = useLazyLoadQuery<PartnerFollowButtonQuery>(query, { id: partnerID })

if (!data.partner) {
return <FollowButton isFollowed={false} />
}

return <PartnerFollowButton partner={data.partner} />
}

const query = graphql`
query PartnerFollowButtonQuery($id: String!) {
partner(id: $id) {
...PartnerFollowButton_partner
}
}
`
Loading

0 comments on commit e80af24

Please sign in to comment.