diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModalArtistPreview.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModalArtistPreview.tsx
index 8ee00fa749b..5cc71b57360 100644
--- a/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModalArtistPreview.tsx
+++ b/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModalArtistPreview.tsx
@@ -1,88 +1,140 @@
-import {
- Checkbox,
- Flex,
- InfoCircleIcon,
- Join,
- Message,
- Spacer,
- Text,
- Touchable,
-} from "@artsy/palette-mobile"
+import { Checkbox, Flex, InfoCircleIcon, Join, Message, Spacer, Text } from "@artsy/palette-mobile"
+import { useActionSheet } from "@expo/react-native-action-sheet"
import { BottomSheetView } from "@gorhom/bottom-sheet"
import { MyCollectionBottomSheetModalArtistPreviewQuery } from "__generated__/MyCollectionBottomSheetModalArtistPreviewQuery.graphql"
import { MyCollectionBottomSheetModalArtistPreview_artist$data } from "__generated__/MyCollectionBottomSheetModalArtistPreview_artist.graphql"
import { MyCollectionBottomSheetModalArtistPreview_me$data } from "__generated__/MyCollectionBottomSheetModalArtistPreview_me.graphql"
import { ArtistListItemContainer, ArtistListItemPlaceholder } from "app/Components/ArtistListItem"
+import { useToast } from "app/Components/Toast/toastHook"
import { ArtistKindPills } from "app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModalArtistPreview/ArtistKindPills"
+import { MyCollectionTabsStore } from "app/Scenes/MyCollection/State/MyCollectionTabsStore"
+import { deleteUserInterest } from "app/Scenes/MyCollection/mutations/deleteUserInterest"
+import { updateUserInterest } from "app/Scenes/MyCollection/mutations/updateUserInterest"
import { getRelayEnvironment } from "app/system/relay/defaultEnvironment"
import { renderWithPlaceholder } from "app/utils/renderWithPlaceholder"
+import { useState } from "react"
import { QueryRenderer, createFragmentContainer } from "react-relay"
+import useDebounce from "react-use/lib/useDebounce"
import { graphql } from "relay-runtime"
interface MyCollectionBottomSheetModalArtistPreviewProps {
artist: MyCollectionBottomSheetModalArtistPreview_artist$data
me: MyCollectionBottomSheetModalArtistPreview_me$data
+ interestId: string
}
export const MyCollectionBottomSheetModalArtistPreview: React.FC<
MyCollectionBottomSheetModalArtistPreviewProps
-> = ({ artist, me }) => {
- const artworksCountWithinMyCollection = me?.myCollectionConnection?.totalCount ?? 0
- const canBeRemoved = artworksCountWithinMyCollection === 0
+> = ({ artist, me, interestId }) => {
+ const artworksCountWithMyCollection = me?.myCollectionConnection?.totalCount ?? 0
+ const canBeRemoved = artworksCountWithMyCollection === 0
+ const { showActionSheetWithOptions } = useActionSheet()
+
+ const [isPrivate, setIsPrivate] = useState(me.userInterest?.private ?? false)
+
+ const setViewKind = MyCollectionTabsStore.useStoreActions((actions) => actions.setViewKind)
+
+ const toast = useToast()
+
+ useDebounce(
+ () => {
+ if (me.userInterest?.private === isPrivate) {
+ return
+ }
+ updateUserInterest({
+ id: interestId,
+ private: isPrivate,
+ })
+ },
+ 300,
+ [isPrivate]
+ )
+
+ const deleteArtist = () => {
+ deleteUserInterest({
+ id: interestId,
+ })
+ .then(() => {
+ toast.show("Artist removed from My Collection", "bottom", {
+ backgroundColor: "green100",
+ })
+ // Hide modal after removing artist
+ setViewKind({ viewKind: null })
+ })
+ .catch((error) => {
+ console.error(error)
+ toast.show("Something went wrong", "bottom", {
+ backgroundColor: "red100",
+ })
+ })
+ }
return (
}>
}>
-
+
- {}} />
+
+ {
+ setIsPrivate(!isPrivate)
+ }}
+ >
+ <>
+ Share this artist with galleries during inquiries.
+
+ Galleries are more likely to respond if they can see the artists you collect.
+
+ >
+
+
-
+ {canBeRemoved ? (
+ {
+ showActionSheetWithOptions(
+ {
+ title: "Delete artist?",
+ options: ["Delete", "Cancel"],
+ destructiveButtonIndex: 0,
+ cancelButtonIndex: 1,
+ useModal: true,
+ },
+ (buttonIndex) => {
+ if (buttonIndex === 0) {
+ deleteArtist()
+ }
+ }
+ )
+ }}
+ color="red100"
+ variant="xs"
+ underline
+ >
+ Remove Artist
+
+ ) : (
+ <>
+
+ }
+ />
+ >
+ )}
)
}
-const RemoveTheArtist: React.FC<{ canBeRemoved: boolean }> = ({ canBeRemoved }) => (
- }>
- {canBeRemoved ? (
- {}} color="red100" variant="xs" underline>
- Remove Artist
-
- ) : (
- }
- />
- )}
-
-)
-
-const ShareArtistCheckbox: React.FC<{ onCheckboxPress: () => void }> = ({ onCheckboxPress }) => {
- return (
-
-
-
- <>
- Share this artist with galleries during inquiries.
-
- Galleries are more likely to respond if they can see the artists you collect.
-
- >
-
-
-
- )
-}
export const MyCollectionBottomSheetModalArtistPreviewFragmentContainer = createFragmentContainer(
MyCollectionBottomSheetModalArtistPreview,
{
@@ -97,6 +149,10 @@ export const MyCollectionBottomSheetModalArtistPreviewFragmentContainer = create
myCollectionConnection(artistIDs: [$artistID]) {
totalCount
}
+ userInterest(id: $interestId) {
+ id
+ private
+ }
}
`,
}
@@ -104,12 +160,16 @@ export const MyCollectionBottomSheetModalArtistPreviewFragmentContainer = create
export const MyCollectionBottomSheetModalArtistPreviewQueryRenderer: React.FC<{
artistID: string
-}> = ({ artistID }) => {
+ interestId: string
+}> = ({ artistID, interestId }) => {
return (
environment={getRelayEnvironment()}
query={graphql`
- query MyCollectionBottomSheetModalArtistPreviewQuery($artistID: String!) {
+ query MyCollectionBottomSheetModalArtistPreviewQuery(
+ $artistID: String!
+ $interestId: String!
+ ) {
artist(id: $artistID) {
...MyCollectionBottomSheetModalArtistPreview_artist
}
@@ -121,11 +181,15 @@ export const MyCollectionBottomSheetModalArtistPreviewQueryRenderer: React.FC<{
cacheConfig={{ force: true }}
variables={{
artistID,
+ interestId,
}}
render={renderWithPlaceholder({
Container: MyCollectionBottomSheetModalArtistPreviewFragmentContainer,
renderPlaceholder: LoadingSkeleton,
renderFallback: () => null,
+ initialProps: {
+ interestId,
+ },
})}
/>
)
diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModals.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModals.tsx
index ce08c903e1d..8f350595313 100644
--- a/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModals.tsx
+++ b/src/app/Scenes/MyCollection/Components/MyCollectionBottomSheetModals/MyCollectionBottomSheetModals.tsx
@@ -12,7 +12,8 @@ export const MyCollectionBottomSheetModals: React.FC<{}> = () => {
const setViewKind = MyCollectionTabsStore.useStoreActions((actions) => actions.setViewKind)
const view = MyCollectionTabsStore.useStoreState((state) => state.viewKind)
- const id = MyCollectionTabsStore.useStoreState((state) => state.id)
+ const artistId = MyCollectionTabsStore.useStoreState((state) => state.artistId)
+ const interestId = MyCollectionTabsStore.useStoreState((state) => state.interestId)
const snapPoints = useMemo(() => [view === "Artist" ? 410 : 370], [])
@@ -45,9 +46,12 @@ export const MyCollectionBottomSheetModals: React.FC<{}> = () => {
handleIndicatorStyle={{ backgroundColor: "black", width: 40, height: 4, borderRadius: 2 }}
>
{view === "Add" && }
- {view === "Artist" && !!id && (
-
- )}
+ {view === "Artist" && !!artistId && !!interestId ? (
+
+ ) : null}
>
)
diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistGridItem.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistGridItem.tsx
deleted file mode 100644
index 1572eab6d7f..00000000000
--- a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistGridItem.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { Avatar, Flex, Text, Touchable } from "@artsy/palette-mobile"
-import { MyCollectionCollectedArtistGridItem_artist$key } from "__generated__/MyCollectionCollectedArtistGridItem_artist.graphql"
-import { formatTombstoneText } from "app/Components/ArtistListItem"
-import { MyCollectionTabsStore } from "app/Scenes/MyCollection/State/MyCollectionTabsStore"
-import { isPad } from "app/utils/hardware"
-import { pluralize } from "app/utils/pluralize"
-import { useFragment } from "react-relay"
-import { graphql } from "relay-runtime"
-
-interface MyCollectionCollectedArtistGridItemProps {
- artist: MyCollectionCollectedArtistGridItem_artist$key
- artworksCount: number | null
-}
-
-export const MyCollectionCollectedArtistGridItem: React.FC<
- MyCollectionCollectedArtistGridItemProps
-> = ({ artist, artworksCount }) => {
- const setViewKind = MyCollectionTabsStore.useStoreActions((state) => state.setViewKind)
-
- const artistData = useFragment(
- artistFragment,
- artist
- )
- const { nationality, birthday, deathday } = artistData
-
- const isAPad = isPad()
-
- const getMeta = () => {
- const tombstoneText = formatTombstoneText(nationality, birthday, deathday)
-
- if (!!tombstoneText || Number.isInteger(artworksCount)) {
- return (
-
- {!!tombstoneText && (
-
- {tombstoneText}
-
- )}
- {Number.isInteger(artworksCount) && (
-
- {artworksCount} {pluralize("artwork", artworksCount || 0)} uploaded
-
- )}
-
- )
- }
-
- return undefined
- }
- const meta = getMeta()
-
- return (
-
- {
- setViewKind({
- viewKind: "Artist",
- id: artistData.internalID,
- })
- }}
- >
-
-
-
- {artistData.name ?? ""}
-
- {meta}
-
-
-
- )
-}
-
-const artistFragment = graphql`
- fragment MyCollectionCollectedArtistGridItem_artist on Artist {
- name
- id
- internalID
- slug
- name
- initials
- href
- is_followed: isFollowed
- nationality
- birthday
- deathday
- image {
- url
- }
- }
-`
diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistItem.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistItem.tsx
index 815af92bc11..c59c7a5a4ae 100644
--- a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistItem.tsx
+++ b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistItem.tsx
@@ -10,9 +10,14 @@ interface ArtistItem {
// TODO: Implement compact version of artists grid
compact?: boolean
isPrivate?: boolean
+ interestId: string
}
-export const MyCollectionCollectedArtistItem: React.FC = ({ artist, isPrivate }) => {
+export const MyCollectionCollectedArtistItem: React.FC = ({
+ artist,
+ isPrivate,
+ interestId,
+}) => {
const setViewKind = MyCollectionTabsStore.useStoreActions((state) => state.setViewKind)
const artistData = useFragment(artistFragment, artist)
const space = useSpace()
@@ -20,7 +25,8 @@ export const MyCollectionCollectedArtistItem: React.FC = ({ artist,
const showArtistPreview = () => {
setViewKind({
viewKind: "Artist",
- id: artistData.internalID,
+ artistId: artistData.internalID,
+ interestId: interestId,
})
}
diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsRail.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsRail.tsx
index 92c4176a852..c3aa1c98256 100644
--- a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsRail.tsx
+++ b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsRail.tsx
@@ -2,7 +2,6 @@ import { Avatar, Flex, Spacer, Spinner, Text, Touchable, useSpace } from "@artsy
import { MyCollectionCollectedArtistsRail_artist$key } from "__generated__/MyCollectionCollectedArtistsRail_artist.graphql"
import { MyCollectionCollectedArtistsRail_me$key } from "__generated__/MyCollectionCollectedArtistsRail_me.graphql"
import { MyCollectionTabsStore } from "app/Scenes/MyCollection/State/MyCollectionTabsStore"
-import { extractNodes } from "app/utils/extractNodes"
import { Animated } from "react-native"
import { useFragment, usePaginationFragment } from "react-relay"
import { graphql } from "relay-runtime"
@@ -31,18 +30,33 @@ export const MyCollectionCollectedArtistsRail: React.FC userInterest?.node)
if (!collectedArtists) return <>>
+ const filteredUserInterests = userInterests.filter((userInterest) => {
+ if (userInterest?.internalID && userInterest.node && userInterest.node.internalID) {
+ return true
+ }
+ return
+ })
+
return (
}
- keyExtractor={({ internalID }) => internalID!}
+ data={filteredUserInterests}
+ renderItem={({ item }) => {
+ if (item?.node && item.internalID && item.node.internalID) {
+ return (
+
+ )
+ }
+ return null
+ }}
+ keyExtractor={(item, index) => item?.internalID || index.toString()}
onEndReachedThreshold={1}
ItemSeparatorComponent={() => }
contentContainerStyle={{
@@ -70,9 +84,10 @@ export const MyCollectionCollectedArtistsRail: React.FC = ({
- artist,
-}) => {
+export const Artist: React.FC<{
+ artist: MyCollectionCollectedArtistsRail_artist$key
+ interestId: string
+}> = ({ artist, interestId }) => {
const data = useFragment(artistFragment, artist)
const setViewKind = MyCollectionTabsStore.useStoreActions((state) => state.setViewKind)
@@ -82,7 +97,8 @@ export const Artist: React.FC<{ artist: MyCollectionCollectedArtistsRail_artist$
onPress={() => {
setViewKind({
viewKind: "Artist",
- id: data.internalID,
+ artistId: data.internalID,
+ interestId: interestId,
})
}}
accessibilityHint={`View more details ${data.name}`}
@@ -112,6 +128,7 @@ const collectedArtistsPaginationFragment = graphql`
interestType: ARTIST
) @connection(key: "MyCollectionCollectedArtistsRail_userInterestsConnection") {
edges {
+ internalID
node {
... on Artist {
internalID
diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx
index edcf212162a..c160ee1a5bf 100644
--- a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx
+++ b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx
@@ -53,15 +53,16 @@ export const MyCollectionCollectedArtistsView: React.FC "list" + item?.node?.internalID}
+ keyExtractor={(item) => "list" + item?.internalID}
renderItem={({ item }) => {
- if (item && item.node && item.node.internalID && item.private) {
+ if (item?.node) {
return (
)
}
@@ -102,7 +103,6 @@ const collectedArtistsPaginationFragment = graphql`
internalID
name
...MyCollectionCollectedArtistItem_artist
- ...MyCollectionCollectedArtistGridItem_artist
}
}
}
diff --git a/src/app/Scenes/MyCollection/State/MyCollectionTabsStore.tsx b/src/app/Scenes/MyCollection/State/MyCollectionTabsStore.tsx
index 41efab9e46d..e2ed0dafc37 100644
--- a/src/app/Scenes/MyCollection/State/MyCollectionTabsStore.tsx
+++ b/src/app/Scenes/MyCollection/State/MyCollectionTabsStore.tsx
@@ -9,12 +9,14 @@ type ViewPayload =
}
| {
viewKind: "Artist"
- id: string
+ artistId: string
+ interestId: string
}
export interface MyCollectionTabsStoreModel {
selectedTab: CollectedTab
viewKind: MyCollectionBottomSheetModalKind
- id: string | null
+ artistId: string | null
+ interestId: string | null
setSelectedTab: Action
setViewKind: Action
}
@@ -22,7 +24,8 @@ export interface MyCollectionTabsStoreModel {
export const myCollectionTabsStoreModel: MyCollectionTabsStoreModel = {
selectedTab: null,
viewKind: null,
- id: null,
+ artistId: null,
+ interestId: null,
setSelectedTab: action((state, payload) => {
state.selectedTab = payload
}),
@@ -31,7 +34,8 @@ export const myCollectionTabsStoreModel: MyCollectionTabsStoreModel = {
switch (payload.viewKind) {
case null:
state.viewKind = null
- state.id = null
+ state.interestId = null
+ state.artistId = null
break
case "Add":
@@ -40,7 +44,8 @@ export const myCollectionTabsStoreModel: MyCollectionTabsStoreModel = {
default:
state.viewKind = payload.viewKind
- state.id = payload.id
+ state.artistId = payload.artistId
+ state.interestId = payload.interestId
break
}
}),
diff --git a/src/app/Scenes/MyCollection/mutations/updateUserInterest.ts b/src/app/Scenes/MyCollection/mutations/updateUserInterest.ts
new file mode 100644
index 00000000000..7b4dbaebf30
--- /dev/null
+++ b/src/app/Scenes/MyCollection/mutations/updateUserInterest.ts
@@ -0,0 +1,48 @@
+import { UpdateUserInterestMutationInput } from "__generated__/updateUserInterestMutation.graphql"
+import { getRelayEnvironment } from "app/system/relay/defaultEnvironment"
+import { commitMutation, graphql } from "react-relay"
+
+export const updateUserInterest = (input: UpdateUserInterestMutationInput) => {
+ return new Promise((resolve, reject) => {
+ commitMutation(getRelayEnvironment(), {
+ mutation: graphql`
+ mutation updateUserInterestMutation($input: UpdateUserInterestMutationInput!) {
+ updateUserInterest(input: $input) {
+ userInterestOrError {
+ ... on UpdateUserInterestSuccess {
+ userInterest {
+ id
+ private
+ }
+ }
+ }
+ }
+ }
+ `,
+ variables: {
+ input,
+ },
+ // @ts-expect-error
+ optimisticResponse: {
+ updateUserInterest: {
+ userInterestOrError: {
+ __typename: "UpdateUserInterestSuccess",
+ userInterest: {
+ id: input.id,
+ private: input.private,
+ },
+ },
+ },
+ },
+
+ onCompleted: (response, errors) => {
+ if (errors?.length) {
+ reject(errors)
+ } else {
+ resolve(response)
+ }
+ },
+ onError: reject,
+ })
+ })
+}