Skip to content

Commit

Permalink
feat: Add Tasks ("Act Now") section to home view (#6095)
Browse files Browse the repository at this point in the history
* feat: Add Tasks section to home view

* feature flag

* tests

* copy and fix
  • Loading branch information
olerichter00 authored Oct 10, 2024
1 parent c15f2e5 commit 675ad99
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 47 deletions.
44 changes: 44 additions & 0 deletions _schemaV2.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -11382,6 +11382,30 @@ type HomeViewSectionShows implements HomeViewSectionGeneric & Node {
): ShowConnection
}

# A tasks section in the home view
type HomeViewSectionTasks implements HomeViewSectionGeneric & Node {
# Component prescription for this section, for overriding or customizing presentation and behavior
component: HomeViewComponent

# [Analytics] `context module` analytics value for this section, as defined in our schema (artsy/cohesion)
contextModule: String

# A globally unique ID.
id: ID!

# A type-specific ID likely used as a database ID.
internalID: ID!

# [Analytics] `owner type` analytics value for this scetion when displayed in a standalone UI, as defined in our schema (artsy/cohesion)
ownerType: String
tasksConnection(
after: String
before: String
first: Int
last: Int
): TaskConnection
}

# A viewing rooms section in the home view
type HomeViewSectionViewingRooms implements HomeViewSectionGeneric & Node {
# Component prescription for this section, for overriding or customizing presentation and behavior
Expand Down Expand Up @@ -19263,6 +19287,26 @@ type Task implements Node {
title: String!
}

# A connection to a list of items.
type TaskConnection {
# A list of edges.
edges: [TaskEdge]
pageCursors: PageCursors!

# Information to aid in pagination.
pageInfo: PageInfo!
totalCount: Int
}

# An edge in a connection.
type TaskEdge {
# A cursor for use in pagination
cursor: String!

# The item at the end of the edge
node: Task
}

type TaxInfo {
displayText: String!
moreInfo: TaxMoreInfo!
Expand Down
5 changes: 3 additions & 2 deletions src/lib/featureFlags.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import config from "config"
import { Context as UnleashContext, Unleash, initialize } from "unleash-client"
import { info, error } from "./loggers"
import { Unleash, Context as UnleashContext, initialize } from "unleash-client"
import { error, info } from "./loggers"

const { UNLEASH_API, UNLEASH_APP_NAME, UNLEASH_SERVER_KEY } = config

Expand All @@ -14,6 +14,7 @@ const FEATURE_FLAGS_LIST = [
"emerald_signals-auction-improvements",
"onyx_enable-home-view-section-featured-fairs",
"diamond_home-view-marketing-collection-categories",
"emerald_home-view-tasks-section",
] as const

export type FeatureFlag = typeof FEATURE_FLAGS_LIST[number]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/loaders/loaders_with_authentication/gravity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ export default (accessToken, userID, opts) => {
{},
{ headers: true }
),
meTasksLoader: gravityLoader("me/tasks", {}, {}),
meTasksLoader: gravityLoader("me/tasks", {}, { headers: true }),
meDismissTaskLoader: gravityLoader(
(id) => `me/task/${id}/dismiss`,
{},
Expand Down
94 changes: 94 additions & 0 deletions src/schema/v2/homeView/__tests__/HomeViewSection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,100 @@ describe("HomeViewSection", () => {
})
})

describe("HomeViewSectionTasks", () => {
beforeAll(() => {
mockIsFeatureFlagEnabled.mockImplementation((flag: string) => {
if (flag === "emerald_home-view-tasks-section") return true
})
})

const query = gql`
{
homeView {
section(id: "home-view-section-tasks") {
__typename
component {
title
}
... on HomeViewSectionTasks {
tasksConnection(first: 2) {
edges {
node {
title
}
}
}
}
}
}
}
`

it("returns correct data", async () => {
const tasks = {
body: [
{
title: "Task 1",
},
{
title: "Task 2",
},
],
headers: { "x-total-count": 10 },
}

const context = {
accessToken: "424242",
meLoader: () => Promise.resolve({}),
meTasksLoader: jest.fn().mockResolvedValue(tasks),
}

const { homeView } = await runQuery(query, context)

expect(homeView.section).toMatchInlineSnapshot(`
Object {
"__typename": "HomeViewSectionTasks",
"component": Object {
"title": "Act Now",
},
"tasksConnection": Object {
"edges": Array [
Object {
"node": Object {
"title": "Task 1",
},
},
Object {
"node": Object {
"title": "Task 2",
},
},
],
},
}
`)
})

describe("when the feature flag is disabled", () => {
beforeAll(() => {
mockIsFeatureFlagEnabled.mockImplementation((flag: string) => {
if (flag === "emerald_home-view-tasks-section") return false
})
})

it("throws an error", async () => {
const context = {
fairsLoader: jest.fn().mockResolvedValue([]),
}

await expect(runQuery(query, context)).rejects.toThrow(
"Section requires authorized user: home-view-section-tasks"
)
})
})
})

describe("GalleriesNearYou", () => {
it("returns correct data", async () => {
const query = gql`
Expand Down
35 changes: 35 additions & 0 deletions src/schema/v2/homeView/sectionTypes/Tasks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { GraphQLObjectType } from "graphql"
import { pageable } from "relay-cursor-paging"
import {
connectionWithCursorInfo,
emptyConnection,
} from "schema/v2/fields/pagination"
import { TaskType } from "schema/v2/me/task"
import { NodeInterface } from "schema/v2/object_identification"
import { ResolverContext } from "types/graphql"
import {
HomeViewGenericSectionInterface,
standardSectionFields,
} from "./GenericSectionInterface"
import { HomeViewSectionTypeNames } from "./names"

export const HomeViewTasksSectionType = new GraphQLObjectType<
any,
ResolverContext
>({
name: HomeViewSectionTypeNames.HomeViewSectionTasks,
description: "A tasks section in the home view",
interfaces: [HomeViewGenericSectionInterface, NodeInterface],
fields: {
...standardSectionFields,

tasksConnection: {
type: connectionWithCursorInfo({
nodeType: TaskType,
}).connectionType,
args: pageable({}),
resolve: (parent, ...rest) =>
parent.resolver ? parent.resolver(parent, ...rest) : emptyConnection,
},
},
})
2 changes: 2 additions & 0 deletions src/schema/v2/homeView/sectionTypes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { HomeViewHeroUnitsSectionType } from "./HeroUnits"
import { HomeViewMarketingCollectionsSectionType } from "./MarketingCollections"
import { HomeViewSalesSectionType } from "./Sales"
import { HomeViewShowsSectionType } from "./Shows"
import { HomeViewTasksSectionType } from "./Tasks"
import { HomeViewViewingRoomsSectionType } from "./ViewingRooms"

export const homeViewSectionTypes: GraphQLObjectType<any, ResolverContext>[] = [
Expand All @@ -27,5 +28,6 @@ export const homeViewSectionTypes: GraphQLObjectType<any, ResolverContext>[] = [
HomeViewMarketingCollectionsSectionType,
HomeViewSalesSectionType,
HomeViewShowsSectionType,
HomeViewTasksSectionType,
HomeViewViewingRoomsSectionType,
]
1 change: 1 addition & 0 deletions src/schema/v2/homeView/sectionTypes/names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export const HomeViewSectionTypeNames = {
HomeViewSectionMarketingCollections: "HomeViewSectionMarketingCollections",
HomeViewSectionSales: "HomeViewSectionSales",
HomeViewSectionShows: "HomeViewSectionShows",
HomeViewSectionTasks: "HomeViewSectionTasks",
HomeViewSectionViewingRooms: "HomeViewSectionViewingRooms",
} as const
40 changes: 40 additions & 0 deletions src/schema/v2/homeView/sections/Tasks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { connectionFromArraySlice } from "graphql-relay"
import { convertConnectionArgsToGravityArgs } from "lib/helpers"
import { createPageCursors } from "schema/v2/fields/pagination"
import { HomeViewSection } from "."
import { withHomeViewTimeout } from "../helpers/withHomeViewTimeout"
import { HomeViewSectionTypeNames } from "../sectionTypes/names"

export const Tasks: HomeViewSection = {
id: "home-view-section-tasks",
type: HomeViewSectionTypeNames.HomeViewSectionTasks,
// TODO: Create context module in Cohesion
// contextModule: ContextModule.tasks,
component: {
title: "Act Now",
},
featureFlag: "emerald_home-view-tasks-section",
requiresAuthentication: true,
resolver: withHomeViewTimeout(async (_parent, args, { meTasksLoader }) => {
if (!meTasksLoader) return null

const { page, size, offset } = convertConnectionArgsToGravityArgs(args)

const { body: results, headers } = await meTasksLoader({
page,
size,
total_count: true,
})

const count = parseInt(headers["x-total-count"] || "0", 10)

return {
totalCount: count,
pageCursors: createPageCursors({ ...args, page, size }, count),
...connectionFromArraySlice(results, args, {
arrayLength: count,
sliceStart: offset,
}),
}
}),
}
40 changes: 21 additions & 19 deletions src/schema/v2/homeView/sections/index.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import { ContextModule, OwnerType } from "@artsy/cohesion"
import { GraphQLFieldResolver } from "graphql"
import { FeatureFlag } from "lib/featureFlags"
import { ResolverContext } from "types/graphql"
import { HomeViewComponentBehaviors } from "../HomeViewComponent"
import { HomeViewSectionTypeNames } from "../sectionTypes/names"
import { ContextModule, OwnerType } from "@artsy/cohesion"
import { SimilarToRecentlyViewedArtworks } from "./SimilarToRecentlyViewedArtworks"
import { CuratorsPicksEmerging } from "./CuratorsPicksEmerging"
import { RecentlyViewedArtworks } from "./RecentlyViewedArtworks"
import { ActiveBids } from "./ActiveBids"
import { AuctionLotsForYou } from "./AuctionLotsForYou"
import { Auctions } from "./Auctions"
import { CuratorsPicksEmerging } from "./CuratorsPicksEmerging"
import { DiscoverSomethingNew } from "./DiscoverSomethingNew"
import { ExploreByCategory } from "./ExploreByCategory"
import { FeaturedFairs } from "./FeaturedFairs"
import { GalleriesNearYou } from "./GalleriesNearYou"
import { HeroUnits } from "./HeroUnits"
import { LatestActivity } from "./LatestActivity"
import { LatestArticles } from "./LatestArticles"
import { LatestAuctionResults } from "./LatestAuctionResults"
import { MarketingCollections } from "./MarketingCollections"
import { News } from "./News"
import { NewWorksForYou } from "./NewWorksForYou"
import { NewWorksFromGalleriesYouFollow } from "./NewWorksFromGalleriesYouFollow"
import { RecommendedArtworks } from "./RecommendedArtworks"
import { ActiveBids } from "./ActiveBids"
import { TrendingArtists } from "./TrendingArtists"
import { RecentlyViewedArtworks } from "./RecentlyViewedArtworks"
import { RecommendedArtists } from "./RecommendedArtists"
import { HeroUnits } from "./HeroUnits"
import { FeaturedFairs } from "./FeaturedFairs"
import { MarketingCollections } from "./MarketingCollections"
import { RecommendedArtworks } from "./RecommendedArtworks"
import { ShowsForYou } from "./ShowsForYou"
import { SimilarToRecentlyViewedArtworks } from "./SimilarToRecentlyViewedArtworks"
import { Tasks } from "./Tasks"
import { TrendingArtists } from "./TrendingArtists"
import { ViewingRooms } from "./ViewingRooms"
import { LatestActivity } from "./LatestActivity"
import { LatestAuctionResults } from "./LatestAuctionResults"
import { News } from "./News"
import { LatestArticles } from "./LatestArticles"
import { Auctions } from "./Auctions"
import { GalleriesNearYou } from "./GalleriesNearYou"
import { FeatureFlag } from "lib/featureFlags"
import { ExploreByCategory } from "./ExploreByCategory"
import { DiscoverSomethingNew } from "./DiscoverSomethingNew"

type MaybeResolved<T> =
| T
Expand Down Expand Up @@ -72,6 +73,7 @@ const sections: HomeViewSection[] = [
RecommendedArtworks,
ShowsForYou,
SimilarToRecentlyViewedArtworks,
Tasks,
TrendingArtists,
ViewingRooms,
]
Expand Down
3 changes: 2 additions & 1 deletion src/schema/v2/homeView/zones/__tests__/default.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isFeatureFlagEnabled } from "lib/featureFlags"
import { ResolverContext } from "types/graphql"
import { getSections } from "../default"
import { isFeatureFlagEnabled } from "lib/featureFlags"

jest.mock("lib/featureFlags", () => ({
isFeatureFlagEnabled: jest.fn(() => true),
Expand All @@ -20,6 +20,7 @@ describe("getSections", () => {

expect(sectionIds).toMatchInlineSnapshot(`
Array [
"home-view-section-tasks",
"home-view-section-latest-activity",
"home-view-section-new-works-for-you",
"home-view-section-discover-something-new",
Expand Down
Loading

0 comments on commit 675ad99

Please sign in to comment.