Skip to content
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

Deploy #13638

Merged
merged 12 commits into from Mar 28, 2024
Merged

Deploy #13638

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions .circleci/config.yml
Expand Up @@ -5,13 +5,13 @@ orbs:
aws-s3: circleci/aws-s3@2.0.0
hokusai: artsy/hokusai@volatile
horizon: artsy/release@volatile
slack: circleci/slack@4.13.1
slack: circleci/slack@4.13.2
yarn: artsy/yarn@6.5.0

jobs:
validate_production_schema:
docker:
- image: cimg/node:18.19.1
- image: cimg/node:18.20.0
parameters:
# find channel ID at the botton of channel details view (slack app) or by right clicking on channel, and copying the link. The ID will be visible at the end of that URL.
dev:
Expand Down Expand Up @@ -242,13 +242,17 @@ not_staging_or_release: &not_staging_or_release
- release

only_main: &only_main
context: hokusai
context:
- hokusai
- slack-orb
filters:
branches:
only: main

only_release: &only_release
context: hokusai
context:
- hokusai
- slack-orb
filters:
branches:
only: release
Expand Down
@@ -0,0 +1,81 @@
import { Stack, Text } from "@artsy/palette"
import { FC } from "react"
import { graphql } from "react-relay"
import { useClientQuery } from "Utils/Hooks/useClientQuery"
import { CollectorProfileArtistsListQuery } from "__generated__/CollectorProfileArtistsListQuery.graphql"
import {
CollectorProfileArtistsListArtist,
CollectorProfileArtistsListArtistSkeleton,
} from "Apps/CollectorProfile/Components/CollectorProfileArtists/CollectorProfileArtistsListArtist"
import { compact } from "lodash"

interface CollectorProfileArtistsListProps {}

export const CollectorProfileArtistsList: FC<CollectorProfileArtistsListProps> = () => {
const { data, loading } = useClientQuery<CollectorProfileArtistsListQuery>({
query: COLLECTOR_PROFILE_ARTISTS_LIST_QUERY,
})

const userInterestEdges = compact(data?.me?.userInterestsConnection?.edges)

return (
<Stack gap={2}>
<Stack
gap={2}
flexDirection="row"
alignItems="center"
color="black60"
borderBottom="1px solid"
borderColor="black10"
pb={2}
>
<Text size="sm-display" overflowEllipsis flex={1}>
Artist
</Text>

<Text size="sm-display" overflowEllipsis flex={1}>
Artworks uploaded
</Text>

<Text size="sm-display" overflowEllipsis flex={1}>
Share with the galleries during inquiries
</Text>

<Text size="sm-display" overflowEllipsis flex={1} textAlign="right">
Follow artist
</Text>
</Stack>

{loading ? (
new Array(10).fill(null).map((_, i) => {
return <CollectorProfileArtistsListArtistSkeleton key={i} />
})
) : (
<>
{userInterestEdges.map(userInterestEdge => {
return (
<CollectorProfileArtistsListArtist
key={userInterestEdge.internalID}
userInterestEdge={userInterestEdge}
/>
)
})}
</>
)}
</Stack>
)
}

const COLLECTOR_PROFILE_ARTISTS_LIST_QUERY = graphql`
query CollectorProfileArtistsListQuery($after: String) {
me {
userInterestsConnection(first: 10, after: $after, interestType: ARTIST) {
totalCount
edges {
...CollectorProfileArtistsListArtist_userInterestEdge
internalID
}
}
}
}
`
@@ -0,0 +1,98 @@
import { FC } from "react"
import { graphql, useFragment } from "react-relay"
import { CollectorProfileArtistsListArtist_userInterestEdge$key } from "__generated__/CollectorProfileArtistsListArtist_userInterestEdge.graphql"
import { Box, Button, Checkbox, SkeletonText, Text } from "@artsy/palette"
import { EntityHeaderArtistFragmentContainer } from "Components/EntityHeaders/EntityHeaderArtist"
import { FollowArtistButtonQueryRenderer } from "Components/FollowButton/FollowArtistButton"
import { EntityHeaderPlaceholder } from "Components/EntityHeaders/EntityHeaderPlaceholder"
import styled from "styled-components"

interface CollectorProfileArtistsListArtistProps {
userInterestEdge: CollectorProfileArtistsListArtist_userInterestEdge$key
}

export const CollectorProfileArtistsListArtist: FC<CollectorProfileArtistsListArtistProps> = ({
userInterestEdge,
}) => {
const { private: isPrivate, node: artist } = useFragment(
COLLECTOR_PROFILE_ARTISTS_LIST_ARTIST_FRAGMENT,
userInterestEdge
)

if (!artist || artist.__typename !== "Artist") {
return null
}

const count = artist.counts?.artworks || 0

return (
<CollectorProfileArtistsListArtistRow>
<EntityHeaderArtistFragmentContainer
artist={artist}
displayFollowButton={false}
flex={1}
/>

<Text variant="sm-display" flex={1} overflowEllipsis>
{count} artwork{count === 1 ? "" : "s"}
</Text>

<Checkbox selected={!isPrivate} flex={1}>
Share with galleries
</Checkbox>

<Box flex={1} display="flex" justifyContent="flex-end">
<FollowArtistButtonQueryRenderer id={artist.internalID} size="small" />
</Box>
</CollectorProfileArtistsListArtistRow>
)
}

export const CollectorProfileArtistsListArtistSkeleton: FC = () => {
return (
<CollectorProfileArtistsListArtistRow>
<EntityHeaderPlaceholder flex={1} />

<SkeletonText variant="sm-display" flex={1} overflowEllipsis>
00 artworks
</SkeletonText>

<Checkbox disabled flex={1}>
Share with galleries
</Checkbox>

<Box flex={1} display="flex" justifyContent="flex-end">
<Button variant="secondaryNeutral" size="small" disabled>
Follow
</Button>
</Box>
</CollectorProfileArtistsListArtistRow>
)
}

const CollectorProfileArtistsListArtistRow = styled(Box).attrs({
display: "flex",
gap: 2,
flexDirection: "row",
alignItems: "center",
borderBottom: "1px solid",
borderColor: "black10",
py: 4,
})``

const COLLECTOR_PROFILE_ARTISTS_LIST_ARTIST_FRAGMENT = graphql`
fragment CollectorProfileArtistsListArtist_userInterestEdge on UserInterestEdge {
private
node {
__typename
... on Artist {
...EntityHeaderArtist_artist
internalID
name
counts {
artworks
}
}
}
}
`
@@ -0,0 +1,39 @@
import FilterIcon from "@artsy/icons/FilterIcon"
import AddIcon from "@artsy/icons/AddIcon"
import { AutocompleteInput, Button, Stack } from "@artsy/palette"
import { MetaTags } from "Components/MetaTags"
import { FC } from "react"
import { CollectorProfileArtistsList } from "Apps/CollectorProfile/Components/CollectorProfileArtists/CollectorProfileArtistsList"

interface CollectorProfileArtistsRouteProps {}

export const CollectorProfileArtistsRoute: FC<CollectorProfileArtistsRouteProps> = props => {
return (
<>
<MetaTags
title="Artists | Collector Profile | Artsy"
pathname="collector-profile/artists"
/>

<Stack gap={6}>
<Stack gap={2} flexDirection="row" alignItems="center">
<AutocompleteInput
placeholder="Search artists in your collection"
options={[]}
flex={1}
/>

<Button variant="tertiary" Icon={FilterIcon} size="small">
Sort & Filter
</Button>

<Button variant="primaryBlack" Icon={AddIcon}>
Add Artist
</Button>
</Stack>

<CollectorProfileArtistsList />
</Stack>
</>
)
}
@@ -0,0 +1,15 @@
import { render, screen } from "@testing-library/react"
import { CollectorProfileArtistsRoute } from "Apps/CollectorProfile/Routes/Artists/CollectorProfileArtistsRoute"
import { MockBoot } from "DevTools/MockBoot"

describe("CollectorProfileArtistsRoute", () => {
it("renders correctly", () => {
render(
<MockBoot>
<CollectorProfileArtistsRoute />
</MockBoot>
)

expect(screen.getByText("Add Artist")).toBeInTheDocument()
})
})
Expand Up @@ -28,9 +28,9 @@ const CollectorProfileSavesRoute: FC<CollectorProfileSavesRouteProps> = ({
const { trackEvent } = useTracking()
const initialArtworkListId = useRef(match.params.id)
const { page, sort } = match.location.query ?? {}
const savedArtworksArtworkList = me.savedArtworksArtworkList!
const savedArtworksArtworkList = me.savedArtworksArtworkList
const selectedArtworkListId =
match.params.id ?? savedArtworksArtworkList.internalID
match.params.id ?? savedArtworksArtworkList?.internalID
let customArtworkLists = extractNodes(me.customArtworkLists)

useEffect(() => {
Expand Down Expand Up @@ -58,7 +58,9 @@ const CollectorProfileSavesRoute: FC<CollectorProfileSavesRouteProps> = ({
}

// Always display "Saved Artworks" artwork list first in the list
const artworkLists = [savedArtworksArtworkList, ...customArtworkLists]
const artworkLists = savedArtworksArtworkList
? [savedArtworksArtworkList, ...customArtworkLists]
: customArtworkLists

/**
* When the artwork list has been successfully deleted,
Expand Down Expand Up @@ -88,6 +90,7 @@ const CollectorProfileSavesRoute: FC<CollectorProfileSavesRouteProps> = ({
savedArtworksCount={
me?.savedArtworksArtworkList?.artworksConnection?.totalCount ?? 0
}
me={me}
/>

<Jump id={ARTWORK_LIST_SCROLL_TARGET_ID} />
Expand All @@ -97,7 +100,7 @@ const CollectorProfileSavesRoute: FC<CollectorProfileSavesRouteProps> = ({
<Shelf showProgress={false}>
{artworkLists.map(artworkList => {
const isDefaultArtworkList =
artworkList.internalID === savedArtworksArtworkList.internalID
artworkList.internalID === savedArtworksArtworkList?.internalID

return (
<ArtworkListItemFragmentContainer
Expand Down Expand Up @@ -136,7 +139,9 @@ export const CollectorProfileSavesRouteFragmentContainer = createFragmentContain
fragment CollectorProfileSavesRoute_me on Me {
savedArtworksArtworkList: collection(id: "saved-artwork") {
internalID
shareableWithPartners
...ArtworkListItem_item
...OfferSettingsListItem_item

artworksConnection(first: 4) {
totalCount
Expand All @@ -157,7 +162,9 @@ export const CollectorProfileSavesRouteFragmentContainer = createFragmentContain
node {
internalID
default
shareableWithPartners
...ArtworkListItem_item
...OfferSettingsListItem_item
}
}
}
Expand Down
@@ -0,0 +1,32 @@
import { graphql } from "react-relay"
import { useMutation } from "Utils/Hooks/useMutation"
import { useUpdateMeCollectionMutation } from "__generated__/useUpdateMeCollectionMutation.graphql"

export const useUpdateMeCollection = () => {
return useMutation<useUpdateMeCollectionMutation>({
mutation: graphql`
mutation useUpdateMeCollectionMutation(
$input: updateMeCollectionsMutationInput!
) {
updateMeCollectionsMutation(input: $input) {
meCollectionsOrErrors {
... on UpdateMeCollectionsSuccess {
collection {
id
shareableWithPartners
name
artworksCount
}
}
... on UpdateMeCollectionsFailure {
mutationError {
type
message
}
}
}
}
}
`,
})
}