diff --git a/packages/api/src/elastic/types.ts b/packages/api/src/elastic/types.ts index 030c2a98e..44185dc12 100644 --- a/packages/api/src/elastic/types.ts +++ b/packages/api/src/elastic/types.ts @@ -198,6 +198,7 @@ export interface Page { state: ArticleSavingRequestStatus taskName?: string language?: string + readAt?: Date } export interface SearchItem { diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index d7c823e6d..66e4efb7c 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1246,6 +1246,7 @@ export type Query = { newsletterEmails: NewsletterEmailsResult; reminder: ReminderResult; search: SearchResult; + sendInstallInstructions: SendInstallInstructionsResult; sharedArticle: SharedArticleResult; subscriptions: SubscriptionsResult; user: UserResult; @@ -1515,6 +1516,7 @@ export type SearchItem = { pageType: PageType; publishedAt?: Maybe; quote?: Maybe; + readAt?: Maybe; readingProgressAnchorIndex?: Maybe; readingProgressPercent?: Maybe; shortId?: Maybe; @@ -3712,6 +3714,7 @@ export type QueryResolvers; reminder?: Resolver>; search?: Resolver>; + sendInstallInstructions?: Resolver; sharedArticle?: Resolver>; subscriptions?: Resolver>; user?: Resolver>; @@ -3831,6 +3834,7 @@ export type SearchItemResolvers; publishedAt?: Resolver, ParentType, ContextType>; quote?: Resolver, ParentType, ContextType>; + readAt?: Resolver, ParentType, ContextType>; readingProgressAnchorIndex?: Resolver, ParentType, ContextType>; readingProgressPercent?: Resolver, ParentType, ContextType>; shortId?: Resolver, ParentType, ContextType>; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index de480ff1b..8a2862f8a 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -902,6 +902,7 @@ type Query { newsletterEmails: NewsletterEmailsResult! reminder(linkId: ID!): ReminderResult! search(after: String, first: Int, query: String): SearchResult! + sendInstallInstructions: SendInstallInstructionsResult! sharedArticle(selectedHighlightId: String, slug: String!, username: String!): SharedArticleResult! subscriptions(sort: SortParams): SubscriptionsResult! user(userId: ID, username: String): UserResult! @@ -1078,6 +1079,7 @@ type SearchItem { pageType: PageType! publishedAt: Date quote: String + readAt: Date readingProgressAnchorIndex: Int readingProgressPercent: Float shortId: String diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index c0dde0344..9981430d9 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -49,9 +49,9 @@ import { isParsingTimeout, pageError, stringToHash, + titleForFilePath, userDataToUser, validatedDate, - titleForFilePath, } from '../../utils/helpers' import { ParsedContentPuppeteer, @@ -729,9 +729,10 @@ export const saveArticleReadingProgressResolver = authorized< readingProgressAnchorIndex: shouldUpdate ? readingProgressAnchorIndex : page.readingProgressAnchorIndex, + readAt: new Date(), } - shouldUpdate && (await updatePage(id, updatedPart, { pubsub, uid })) + await updatePage(id, updatedPart, { pubsub, uid }) return { updatedArticle: { diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index de74652d1..cf18b74ef 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -1495,6 +1495,7 @@ const schema = gql` state: ArticleSavingRequestStatus siteName: String language: String + readAt: Date } type SearchItemEdge { diff --git a/packages/api/src/utils/search.ts b/packages/api/src/utils/search.ts index 90ba0ba5b..25f86292b 100644 --- a/packages/api/src/utils/search.ts +++ b/packages/api/src/utils/search.ts @@ -61,6 +61,7 @@ export enum SortBy { UPDATED = 'updatedAt', SCORE = '_score', PUBLISHED = 'publishedAt', + READ = 'readAt', } export enum SortOrder { @@ -178,6 +179,11 @@ const parseSortParams = (str?: string): SortParams | undefined => { by: SortBy.PUBLISHED, order: sortOrder, } + case 'READ': + return { + by: SortBy.READ, + order: sortOrder, + } } } @@ -323,6 +329,7 @@ export const parseSearchQuery = (query: string | undefined): SearchFilter => { break } case 'saved': + case 'read': case 'published': { const dateFilter = parseDateFilter(keyword.keyword, keyword.value) dateFilter && result.dateFilters.push(dateFilter) diff --git a/packages/db/elastic_migrations/index_settings.json b/packages/db/elastic_migrations/index_settings.json index d5dca4841..e0dc26cbd 100644 --- a/packages/db/elastic_migrations/index_settings.json +++ b/packages/db/elastic_migrations/index_settings.json @@ -124,6 +124,9 @@ "language": { "type": "keyword", "normalizer": "lowercase_normalizer" + }, + "readAt": { + "type": "date" } } } diff --git a/packages/web/components/templates/homeFeed/LibrarySearchBar.tsx b/packages/web/components/templates/homeFeed/LibrarySearchBar.tsx index 6e08f3f33..561680306 100644 --- a/packages/web/components/templates/homeFeed/LibrarySearchBar.tsx +++ b/packages/web/components/templates/homeFeed/LibrarySearchBar.tsx @@ -22,7 +22,7 @@ type LibraryFilter = | 'type:file' | 'type:highlights' | `saved:${string}` - | `sort:updated` + | `sort:read` // get last week's date const recentlySavedStartDate = new Date( @@ -122,13 +122,27 @@ export function LibrarySearchBar(props: LibrarySearchBarProps): JSX.Element { {searchTerm && ( - )} @@ -175,7 +189,7 @@ export function DropdownFilterMenu( hideSeparator /> props.onFilterChange(`sort:updated`)} + onSelect={() => props.onFilterChange(`sort:read`)} title="Recently Read" hideSeparator /> diff --git a/packages/web/lib/networking/queries/useGetLibraryItemsQuery.tsx b/packages/web/lib/networking/queries/useGetLibraryItemsQuery.tsx index 89f45aa79..0aad1edc1 100644 --- a/packages/web/lib/networking/queries/useGetLibraryItemsQuery.tsx +++ b/packages/web/lib/networking/queries/useGetLibraryItemsQuery.tsx @@ -76,6 +76,7 @@ export type LibraryItemNode = { state: State pageType: PageType siteName?: string + readAt?: string } export type PageInfo = { @@ -127,6 +128,7 @@ export function useGetLibraryItemsQuery({ annotation state siteName + readAt } } pageInfo {