Merge pull request #1921 from omnivore-app/fix/save-page

Return correct page slug and get saving request by url
This commit is contained in:
Hongbo Wu 2023-03-17 16:03:10 +08:00 committed by GitHub
commit 154d4aaa69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 163 additions and 168 deletions

View file

@ -168,6 +168,7 @@ export type ArticleSavingRequest = {
slug: Scalars['String'];
status: ArticleSavingRequestStatus;
updatedAt: Scalars['Date'];
url: Scalars['String'];
user: User;
/** @deprecated userId has been replaced with user */
userId: Scalars['ID'];
@ -1751,7 +1752,7 @@ export type QueryArticleArgs = {
export type QueryArticleSavingRequestArgs = {
id: Scalars['ID'];
url: Scalars['String'];
};
@ -4194,6 +4195,7 @@ export type ArticleSavingRequestResolvers<ContextType = ResolverContext, ParentT
slug?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
status?: Resolver<ResolversTypes['ArticleSavingRequestStatus'], ParentType, ContextType>;
updatedAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
url?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
user?: Resolver<ResolversTypes['User'], ParentType, ContextType>;
userId?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -5077,7 +5079,7 @@ export type ProfileResolvers<ContextType = ResolverContext, ParentType extends R
export type QueryResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
apiKeys?: Resolver<ResolversTypes['ApiKeysResult'], ParentType, ContextType>;
article?: Resolver<ResolversTypes['ArticleResult'], ParentType, ContextType, RequireFields<QueryArticleArgs, 'slug' | 'username'>>;
articleSavingRequest?: Resolver<ResolversTypes['ArticleSavingRequestResult'], ParentType, ContextType, RequireFields<QueryArticleSavingRequestArgs, 'id'>>;
articleSavingRequest?: Resolver<ResolversTypes['ArticleSavingRequestResult'], ParentType, ContextType, RequireFields<QueryArticleSavingRequestArgs, 'url'>>;
articles?: Resolver<ResolversTypes['ArticlesResult'], ParentType, ContextType, Partial<QueryArticlesArgs>>;
deviceTokens?: Resolver<ResolversTypes['DeviceTokensResult'], ParentType, ContextType>;
feedArticles?: Resolver<ResolversTypes['FeedArticlesResult'], ParentType, ContextType, Partial<QueryFeedArticlesArgs>>;

View file

@ -135,6 +135,7 @@ type ArticleSavingRequest {
slug: String!
status: ArticleSavingRequestStatus!
updatedAt: Date!
url: String!
user: User!
userId: ID! @deprecated(reason: "userId has been replaced with user")
}
@ -1245,7 +1246,7 @@ type Profile {
type Query {
apiKeys: ApiKeysResult!
article(format: String, slug: String!, username: String!): ArticleResult!
articleSavingRequest(id: ID!): ArticleSavingRequestResult!
articleSavingRequest(url: String!): ArticleSavingRequestResult!
articles(after: String, first: Int, includePending: Boolean, query: String, sharedOnly: Boolean, sort: SortParams): ArticlesResult!
deviceTokens: DeviceTokensResult!
feedArticles(after: String, first: Int, sharedByUser: ID, sort: SortParams): FeedArticlesResult!

View file

@ -1,4 +1,6 @@
/* eslint-disable prefer-const */
import { getPageByParam } from '../../elastic/pages'
import { env } from '../../env'
import {
ArticleSavingRequestError,
ArticleSavingRequestErrorCode,
@ -10,16 +12,14 @@ import {
MutationCreateArticleSavingRequestArgs,
QueryArticleSavingRequestArgs,
} from '../../generated/graphql'
import { createPageSaveRequest } from '../../services/create_page_save_request'
import { analytics } from '../../utils/analytics'
import {
authorized,
isParsingTimeout,
pageToArticleSavingRequest,
} from '../../utils/helpers'
import { createPageSaveRequest } from '../../services/create_page_save_request'
import { getPageById } from '../../elastic/pages'
import { isErrorWithCode } from '../user'
import { analytics } from '../../utils/analytics'
import { env } from '../../env'
export const createArticleSavingRequestResolver = authorized<
CreateArticleSavingRequestSuccess,
@ -56,17 +56,12 @@ export const articleSavingRequestResolver = authorized<
ArticleSavingRequestSuccess,
ArticleSavingRequestError,
QueryArticleSavingRequestArgs
>(async (_, { id }, { models }) => {
let page
let user
try {
page = await getPageById(id)
if (!page) {
return { errorCodes: [ArticleSavingRequestErrorCode.NotFound] }
}
user = await models.user.get(page.userId)
// eslint-disable-next-line no-empty
} catch (error) {}
>(async (_, { url }, { models, claims }) => {
const page = await getPageByParam({ url, userId: claims.uid })
if (!page) {
return { errorCodes: [ArticleSavingRequestErrorCode.NotFound] }
}
const user = await models.user.get(page.userId)
if (user && page) {
if (isParsingTimeout(page)) {
page.state = ArticleSavingRequestStatus.Succeeded

View file

@ -1074,6 +1074,7 @@ const schema = gql`
errorCode: CreateArticleErrorCode
createdAt: Date!
updatedAt: Date!
url: String!
}
# Query: ArticleSavingRequest
@ -2525,7 +2526,7 @@ const schema = gql`
getFollowers(userId: ID): GetFollowersResult!
getFollowing(userId: ID): GetFollowingResult!
getUserPersonalization: GetUserPersonalizationResult!
articleSavingRequest(id: ID!): ArticleSavingRequestResult!
articleSavingRequest(url: String!): ArticleSavingRequestResult!
newsletterEmails: NewsletterEmailsResult!
reminder(linkId: ID!): ReminderResult!
labels: LabelsResult!

View file

@ -1,18 +1,17 @@
import normalizeUrl from 'normalize-url'
import * as privateIpLib from 'private-ip'
import { v4 as uuidv4 } from 'uuid'
import { enqueueParseRequest } from '../utils/createTask'
// TODO: switch to a proper Entity instead of using the old data models.
import { DataModels } from '../resolvers/types'
import { createPubSubClient, PubsubClient } from '../datalayer/pubsub'
import { countByCreatedAt, createPage, getPageByParam } from '../elastic/pages'
import { ArticleSavingRequestStatus, PageType } from '../elastic/types'
import {
ArticleSavingRequest,
CreateArticleSavingRequestErrorCode,
} from '../generated/graphql'
// TODO: switch to a proper Entity instead of using the old data models.
import { DataModels } from '../resolvers/types'
import { enqueueParseRequest } from '../utils/createTask'
import { generateSlug, pageToArticleSavingRequest } from '../utils/helpers'
import * as privateIpLib from 'private-ip'
import { countByCreatedAt, createPage, getPageByParam } from '../elastic/pages'
import { ArticleSavingRequestStatus, PageType } from '../elastic/types'
import { createPubSubClient, PubsubClient } from '../datalayer/pubsub'
import normalizeUrl from 'normalize-url'
const SAVING_CONTENT = 'Your link is being saved...'
@ -92,10 +91,8 @@ export const createPageSaveRequest = async (
userId,
url: normalizedUrl,
})
if (page) {
console.log('Page already exists', page.id, page.url)
articleSavingRequestId = page.id
} else {
if (!page) {
console.log('Page not exists', normalizedUrl)
page = {
id: articleSavingRequestId,
userId,
@ -106,7 +103,7 @@ export const createPageSaveRequest = async (
readingProgressPercent: 0,
slug: generateSlug(url),
title: url,
url,
url: normalizedUrl,
state: ArticleSavingRequestStatus.Processing,
createdAt: new Date(),
savedAt: new Date(),
@ -123,7 +120,7 @@ export const createPageSaveRequest = async (
}
// enqueue task to parse page
await enqueueParseRequest(url, userId, articleSavingRequestId, priority)
await enqueueParseRequest(url, userId, page.id, priority)
return pageToArticleSavingRequest(user, page)
}

View file

@ -1,4 +1,9 @@
import { Readability } from '@omnivore/readability'
import normalizeUrl from 'normalize-url'
import { PubsubClient } from '../datalayer/pubsub'
import { addHighlightToPage } from '../elastic/highlights'
import { createPage, getPageByParam, updatePage } from '../elastic/pages'
import { ArticleSavingRequestStatus, Page, PageType } from '../elastic/types'
import { homePageURL } from '../env'
import {
Maybe,
@ -15,13 +20,7 @@ import {
wordsCount,
} from '../utils/helpers'
import { parsePreparedContent } from '../utils/parser'
import normalizeUrl from 'normalize-url'
import { createPageSaveRequest } from './create_page_save_request'
import { ArticleSavingRequestStatus, Page, PageType } from '../elastic/types'
import { createPage, getPageByParam, updatePage } from '../elastic/pages'
import { addHighlightToPage } from '../elastic/highlights'
import { Readability } from '@omnivore/readability'
type SaveContext = {
pubsub: PubsubClient
@ -76,7 +75,6 @@ export const savePage = async (
saver: SaverUserData,
input: SavePageInput
): Promise<SaveResult> => {
const [slug, croppedPathname] = createSlug(input.url, input.title)
const parseResult = await parsePreparedContent(
input.url,
{
@ -88,12 +86,14 @@ export const savePage = async (
},
input.parseResult
)
const [newSlug, croppedPathname] = createSlug(input.url, input.title)
let slug = newSlug
let pageId = input.clientRequestId
const articleToSave = parsedContentToPage({
url: input.url,
title: input.title,
userId: saver.userId,
pageId: input.clientRequestId,
pageId,
slug,
croppedPathname,
parsedContent: parseResult.parsedContent,
@ -102,7 +102,6 @@ export const savePage = async (
canonicalUrl: parseResult.canonicalUrl,
})
let pageId: string | undefined = undefined
const existingPage = await getPageByParam({
userId: saver.userId,
url: articleToSave.url,
@ -110,7 +109,6 @@ export const savePage = async (
})
if (existingPage) {
pageId = existingPage.id
if (
!(await updatePage(
existingPage.id,
@ -126,12 +124,13 @@ export const savePage = async (
message: 'Failed to update existing page',
}
}
input.clientRequestId = existingPage.id
pageId = existingPage.id
slug = existingPage.slug
} else if (shouldParseInBackend(input)) {
try {
await createPageSaveRequest(
saver.userId,
input.url,
articleToSave.url,
ctx.models,
ctx.pubsub,
input.clientRequestId
@ -143,16 +142,17 @@ export const savePage = async (
}
}
} else {
pageId = await createPage(articleToSave, ctx)
if (!pageId) {
const newPageId = await createPage(articleToSave, ctx)
if (!newPageId) {
return {
errorCodes: [SaveErrorCode.Unknown],
message: 'Failed to create new page',
}
}
pageId = newPageId
}
if (pageId && parseResult.highlightData) {
if (parseResult.highlightData) {
const highlight = {
updatedAt: new Date(),
createdAt: new Date(),
@ -175,7 +175,7 @@ export const savePage = async (
}
return {
clientRequestId: input.clientRequestId,
clientRequestId: pageId,
url: `${homePageURL()}/${saver.username}/${slug}`,
}
}

View file

@ -1,22 +1,24 @@
import { User } from '../../src/entity/user'
import { expect } from 'chai'
import 'mocha'
import sinon from 'sinon'
import { createPubSubClient } from '../../src/datalayer/pubsub'
import { deletePagesByParam, getPageByParam } from '../../src/elastic/pages'
import {
ArticleSavingRequestStatus,
PageContext,
} from '../../src/elastic/types'
import { createTestUser, deleteTestUser } from '../db'
import { graphqlRequest, request } from '../util'
import { createPubSubClient } from '../../src/datalayer/pubsub'
import { expect } from 'chai'
import { getPageById } from '../../src/elastic/pages'
import { User } from '../../src/entity/user'
import {
ArticleSavingRequestErrorCode,
CreateArticleSavingRequestErrorCode,
} from '../../src/generated/graphql'
import 'mocha'
import * as createTask from '../../src/utils/createTask'
import { createTestUser, deleteTestUser } from '../db'
import { graphqlRequest, request } from '../util'
const articleSavingRequestQuery = (id: string) => `
const articleSavingRequestQuery = (url: string) => `
query {
articleSavingRequest(id: "${id}") {
articleSavingRequest(url: "${url}") {
... on ArticleSavingRequestSuccess {
articleSavingRequest {
id
@ -39,6 +41,7 @@ const createArticleSavingRequestMutation = (url: string) => `
articleSavingRequest {
id
status
url
}
}
... on CreateArticleSavingRequestError {
@ -67,11 +70,14 @@ describe('ArticleSavingRequest API', () => {
refresh: true,
uid: user.id,
}
sinon.replace(createTask, 'enqueueParseRequest', sinon.fake.resolves(''))
})
after(async () => {
// clean up
await deletePagesByParam({ userId: user.id }, ctx)
await deleteTestUser(user.id)
sinon.restore()
})
describe('createArticleSavingRequest', () => {
@ -87,15 +93,14 @@ describe('ArticleSavingRequest API', () => {
})
it('creates a page in elastic', async () => {
const res = await graphqlRequest(
const url = 'https://blog.omnivore.app/1'
await graphqlRequest(
createArticleSavingRequestMutation('https://blog.omnivore.app/1'),
authToken
).expect(200)
const page = await getPageById(
res.body.data.createArticleSavingRequest.articleSavingRequest.id
)
expect(page?.content).to.eq('Your link is being saved...')
const page = await getPageByParam({ url })
expect(page?.content).to.eql('Your link is being saved...')
})
it('returns an error if the url is invalid', async () => {
@ -111,27 +116,26 @@ describe('ArticleSavingRequest API', () => {
})
describe('articleSavingRequest', () => {
let articleSavingRequestId: string
let url: string
before(async () => {
url = 'https://blog.omnivore.app/2'
// create article saving request
const res = await graphqlRequest(
createArticleSavingRequestMutation('https://blog.omnivore.app/2'),
await graphqlRequest(
createArticleSavingRequestMutation(url),
authToken
).expect(200)
articleSavingRequestId =
res.body.data.createArticleSavingRequest.articleSavingRequest.id
})
it('returns the article saving request if exists', async () => {
const res = await graphqlRequest(
articleSavingRequestQuery(articleSavingRequestId),
articleSavingRequestQuery(url),
authToken
).expect(200)
expect(res.body.data.articleSavingRequest.articleSavingRequest.id).to.eql(
articleSavingRequestId
)
expect(
res.body.data.articleSavingRequest.articleSavingRequest.status
).to.eql(ArticleSavingRequestStatus.Processing)
})
it('returns not_found if not exists', async () => {

View file

@ -7,5 +7,5 @@
"outDir": "dist"
},
"include": ["src", "test"],
"exclude": ["./src/generated"]
"exclude": ["./src/generated", "./test"]
}

View file

@ -1,17 +1,14 @@
import {
ModalRoot,
ModalContent,
ModalOverlay,
ModalTitleBar,
ModalButtonBar,
} from '../../elements/ModalPrimitives'
import { VStack, Box } from '../../elements/LayoutPrimitives'
import { useCallback, useState } from 'react'
import toast from 'react-hot-toast'
import { saveUrlMutation } from '../../../lib/networking/mutations/saveUrlMutation'
import { showErrorToast } from '../../../lib/toastHelpers'
import { Button } from '../../elements/Button'
import { FormInput } from '../../elements/FormElements'
import { useState, useCallback } from 'react'
import { saveUrlMutation } from '../../../lib/networking/mutations/saveUrlMutation'
import toast from 'react-hot-toast'
import { showErrorToast } from '../../../lib/toastHelpers'
import { Box, VStack } from '../../elements/LayoutPrimitives'
import {
ModalButtonBar, ModalContent,
ModalOverlay, ModalRoot, ModalTitleBar
} from '../../elements/ModalPrimitives'
type AddLinkModalProps = {
onOpenChange: (open: boolean) => void
@ -24,7 +21,7 @@ export function AddLinkModal(props: AddLinkModalProps): JSX.Element {
async (link: string) => {
const result = await saveUrlMutation(link)
// const result = await saveUrlMutation(link)
if (result && result.jobId) {
if (result) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
toast(
() => (
@ -35,7 +32,7 @@ export function AddLinkModal(props: AddLinkModalProps): JSX.Element {
style="ctaDarkYellow"
autoFocus
onClick={() => {
window.location.href = `/article/sr/${result.jobId}`
window.location.href = `/article/sr/${encodeURIComponent(link)}` // encode url
}}
>
Read Now

View file

@ -1,51 +1,51 @@
import { Box, HStack, VStack } from './../../elements/LayoutPrimitives'
import Dropzone from 'react-dropzone'
import * as Progress from '@radix-ui/react-progress'
import axios from 'axios'
import { Action, createAction, useKBar, useRegisterActions } from 'kbar'
import debounce from 'lodash/debounce'
import { useRouter } from 'next/router'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import Dropzone from 'react-dropzone'
import { Toaster } from 'react-hot-toast'
import TopBarProgress from 'react-topbar-progress-indicator'
import { useFetchMore } from '../../../lib/hooks/useFetchMoreScroll'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { libraryListCommands } from '../../../lib/keyboardShortcuts/navigationShortcuts'
import { useKeyboardShortcuts } from '../../../lib/keyboardShortcuts/useKeyboardShortcuts'
import {
PageType,
State
} from '../../../lib/networking/fragments/articleFragment'
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { setLabelsMutation } from '../../../lib/networking/mutations/setLabelsMutation'
import { uploadFileRequestMutation } from '../../../lib/networking/mutations/uploadFileMutation'
import {
SearchItem,
TypeaheadSearchItemsData,
typeaheadSearchQuery
} from '../../../lib/networking/queries/typeaheadSearch'
import type {
LibraryItem,
LibraryItemsQueryInput,
LibraryItemsQueryInput
} from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import {
useGetViewerQuery,
UserBasicData,
UserBasicData
} from '../../../lib/networking/queries/useGetViewerQuery'
import { Button } from '../../elements/Button'
import { StyledText } from '../../elements/StyledText'
import { ConfirmationModal } from '../../patterns/ConfirmationModal'
import { LinkedItemCardAction } from '../../patterns/LibraryCards/CardTypes'
import { LinkedItemCard } from '../../patterns/LibraryCards/LinkedItemCard'
import { useRouter } from 'next/router'
import { Button } from '../../elements/Button'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { StyledText } from '../../elements/StyledText'
import { AddLinkModal } from './AddLinkModal'
import { styled, theme } from '../../tokens/stitches.config'
import { libraryListCommands } from '../../../lib/keyboardShortcuts/navigationShortcuts'
import { useKeyboardShortcuts } from '../../../lib/keyboardShortcuts/useKeyboardShortcuts'
import { Toaster } from 'react-hot-toast'
import { useFetchMore } from '../../../lib/hooks/useFetchMoreScroll'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { ConfirmationModal } from '../../patterns/ConfirmationModal'
import { SetLabelsModal } from '../article/SetLabelsModal'
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { EmptyLibrary } from './EmptyLibrary'
import TopBarProgress from 'react-topbar-progress-indicator'
import {
PageType,
State,
} from '../../../lib/networking/fragments/articleFragment'
import { Action, createAction, useKBar, useRegisterActions } from 'kbar'
import { Box, HStack, VStack } from './../../elements/LayoutPrimitives'
import { AddLinkModal } from './AddLinkModal'
import { EditLibraryItemModal } from './EditItemModals'
import debounce from 'lodash/debounce'
import {
SearchItem,
TypeaheadSearchItemsData,
typeaheadSearchQuery,
} from '../../../lib/networking/queries/typeaheadSearch'
import axios from 'axios'
import { uploadFileRequestMutation } from '../../../lib/networking/mutations/uploadFileMutation'
import { setLabelsMutation } from '../../../lib/networking/mutations/setLabelsMutation'
import { LibraryHeader } from './LibraryHeader'
import { LibraryFilterMenu } from './LibraryFilterMenu'
import { EmptyLibrary } from './EmptyLibrary'
import { HighlightItemsLayout } from './HighlightsLayout'
import { LibraryFilterMenu } from './LibraryFilterMenu'
import { LibraryHeader } from './LibraryHeader'
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
export type LibraryMode = 'reads' | 'highlights'
@ -288,7 +288,7 @@ export function HomeFeedContainer(): JSX.Element {
if (username) {
setActiveCardId(item.node.id)
if (item.node.state === State.PROCESSING) {
router.push(`/${username}/links/${item.node.id}`)
router.push(`/${username}/links/${encodeURIComponent(item.node.url)}`)
} else {
const dl =
item.node.pageType === PageType.HIGHLIGHTS

View file

@ -6,7 +6,7 @@ import { makeGqlFetcher } from '../networkHelpers'
import { ArticleAttributes } from './useGetArticleQuery'
type ArticleSavingStatusInput = {
id: string
url: string
}
type ArticleSavingStatusResponse = {
@ -48,11 +48,11 @@ type ArticleSavingStatusError =
| 'unauthorized'
export function useGetArticleSavingStatus({
id,
url,
}: ArticleSavingStatusInput): ArticleSavingStatusResponse {
const query = gql`
query ArticleSavingRequest($id: ID!) {
articleSavingRequest(id: $id) {
query ArticleSavingRequest($url: String!) {
articleSavingRequest(url: $url) {
... on ArticleSavingRequestSuccess {
articleSavingRequest {
id
@ -85,7 +85,7 @@ export function useGetArticleSavingStatus({
`
// poll twice a second
const { data, error } = useSWR([query, id], makeGqlFetcher({ id }), {
const { data, error } = useSWR([query, url], makeGqlFetcher({ url }), {
refreshInterval: 500,
})

View file

@ -1,30 +1,29 @@
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { useGetArticleSavingStatus } from '../../../lib/networking/queries/useGetArticleSavingStatus'
import TopBarProgress from 'react-topbar-progress-indicator'
import { VStack } from '../../../components/elements/LayoutPrimitives'
import { ArticleActionsMenu } from '../../../components/templates/article/ArticleActionsMenu'
import { SkeletonArticleContainer } from '../../../components/templates/article/SkeletonArticleContainer'
import { PrimaryLayout } from '../../../components/templates/PrimaryLayout'
import {
Loader,
ErrorComponent,
ErrorComponent, Loader
} from '../../../components/templates/SavingRequest'
import { ArticleActionsMenu } from '../../../components/templates/article/ArticleActionsMenu'
import { VStack } from '../../../components/elements/LayoutPrimitives'
import { theme } from '../../../components/tokens/stitches.config'
import { applyStoredTheme } from '../../../lib/themeUpdater'
import { useReaderSettings } from '../../../lib/hooks/useReaderSettings'
import { SkeletonArticleContainer } from '../../../components/templates/article/SkeletonArticleContainer'
import TopBarProgress from 'react-topbar-progress-indicator'
import { useGetArticleSavingStatus } from '../../../lib/networking/queries/useGetArticleSavingStatus'
import { applyStoredTheme } from '../../../lib/themeUpdater'
export default function ArticleSavingRequestPage(): JSX.Element {
const router = useRouter()
const readerSettings = useReaderSettings()
const [articleId, setArticleId] = useState<string | undefined>(undefined)
const [url, setUrl] = useState<string | undefined>(undefined)
applyStoredTheme(false)
useEffect(() => {
if (!router.isReady) return
setArticleId(router.query.id as string)
}, [router.isReady, router.query.id])
setUrl(router.query.url as string)
}, [router.isReady, router.query.url])
return (
<PrimaryLayout
@ -81,7 +80,7 @@ export default function ArticleSavingRequestPage(): JSX.Element {
fontSize={readerSettings.fontSize}
lineHeight={readerSettings.lineHeight}
>
{articleId ? <PrimaryContent articleId={articleId} /> : <Loader />}
{url ? <PrimaryContent url={url} /> : <Loader />}
</SkeletonArticleContainer>
</VStack>
</PrimaryLayout>
@ -89,7 +88,7 @@ export default function ArticleSavingRequestPage(): JSX.Element {
}
type PrimaryContentProps = {
articleId: string
url: string
}
function PrimaryContent(props: PrimaryContentProps): JSX.Element {
@ -97,7 +96,7 @@ function PrimaryContent(props: PrimaryContentProps): JSX.Element {
const [timedOut, setTimedOut] = useState(false)
const { successRedirectPath, error } = useGetArticleSavingStatus({
id: props.articleId,
url: props.url,
})
useEffect(() => {

View file

@ -1,25 +1,25 @@
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { Box } from '../../../../components/elements/LayoutPrimitives'
import { useGetArticleSavingStatus } from '../../../../lib/networking/queries/useGetArticleSavingStatus'
import { ErrorComponent } from '../../../../components/templates/SavingRequest'
import { useSWRConfig } from 'swr'
import { cacheArticle } from '../../../../lib/networking/queries/useGetArticleQuery'
import { Box } from '../../../../components/elements/LayoutPrimitives'
import { PrimaryLayout } from '../../../../components/templates/PrimaryLayout'
import { ErrorComponent } from '../../../../components/templates/SavingRequest'
import { cacheArticle } from '../../../../lib/networking/queries/useGetArticleQuery'
import { useGetArticleSavingStatus } from '../../../../lib/networking/queries/useGetArticleSavingStatus'
import { applyStoredTheme } from '../../../../lib/themeUpdater'
export default function LinkRequestPage(): JSX.Element {
applyStoredTheme(false) // false to skip server sync
const router = useRouter()
const [requestID, setRequestID] = useState<string | undefined>(undefined)
const [url, setUrl] = useState<string | undefined>(undefined)
const [username, setUsername] = useState<string | undefined>(undefined)
useEffect(() => {
if (!router.isReady) return
setRequestID(router.query.id as string)
setUrl(router.query.url as string)
setUsername(router.query.username as string)
}, [router.isReady, router.query.id, router.query.username])
}, [router.isReady, router.query.url, router.query.username])
return (
<PrimaryLayout
@ -33,8 +33,8 @@ export default function LinkRequestPage(): JSX.Element {
<Box
css={{ bg: '$grayBase', height: '100vh', width: '100vw', px: '16px' }}
>
{requestID && username ? (
<PrimaryContent requestID={requestID} username={username} />
{url && username ? (
<PrimaryContent url={url} username={username} />
) : (
<Loader />
)}
@ -48,7 +48,7 @@ function Loader(): JSX.Element {
}
type PrimaryContentProps = {
requestID: string
url: string
username: string
}
@ -58,7 +58,7 @@ function PrimaryContent(props: PrimaryContentProps): JSX.Element {
const [timedOut, setTimedOut] = useState(false)
const { successRedirectPath, article, error } = useGetArticleSavingStatus({
id: props.requestID,
url: props.url,
})
useEffect(() => {

View file

@ -1,30 +1,29 @@
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { useGetArticleSavingStatus } from '../../../lib/networking/queries/useGetArticleSavingStatus'
import TopBarProgress from 'react-topbar-progress-indicator'
import { VStack } from '../../../components/elements/LayoutPrimitives'
import { ArticleActionsMenu } from '../../../components/templates/article/ArticleActionsMenu'
import { SkeletonArticleContainer } from '../../../components/templates/article/SkeletonArticleContainer'
import { PrimaryLayout } from '../../../components/templates/PrimaryLayout'
import {
Loader,
ErrorComponent,
ErrorComponent, Loader
} from '../../../components/templates/SavingRequest'
import { ArticleActionsMenu } from '../../../components/templates/article/ArticleActionsMenu'
import { VStack } from '../../../components/elements/LayoutPrimitives'
import { theme } from '../../../components/tokens/stitches.config'
import { applyStoredTheme } from '../../../lib/themeUpdater'
import { useReaderSettings } from '../../../lib/hooks/useReaderSettings'
import { SkeletonArticleContainer } from '../../../components/templates/article/SkeletonArticleContainer'
import TopBarProgress from 'react-topbar-progress-indicator'
import { useGetArticleSavingStatus } from '../../../lib/networking/queries/useGetArticleSavingStatus'
import { applyStoredTheme } from '../../../lib/themeUpdater'
export default function ArticleSavingRequestPage(): JSX.Element {
const router = useRouter()
const readerSettings = useReaderSettings()
const [articleId, setArticleId] = useState<string | undefined>(undefined)
const [url, setUrl] = useState<string | undefined>(undefined)
applyStoredTheme(false)
useEffect(() => {
if (!router.isReady) return
setArticleId(router.query.id as string)
}, [router.isReady, router.query.id])
setUrl(router.query.url as string)
}, [router.isReady, router.query.url])
return (
<PrimaryLayout
@ -78,7 +77,7 @@ export default function ArticleSavingRequestPage(): JSX.Element {
fontSize={readerSettings.fontSize}
lineHeight={readerSettings.lineHeight}
>
{articleId ? <PrimaryContent articleId={articleId} /> : <Loader />}
{url ? <PrimaryContent url={url} /> : <Loader />}
</SkeletonArticleContainer>
</VStack>
</PrimaryLayout>
@ -86,7 +85,7 @@ export default function ArticleSavingRequestPage(): JSX.Element {
}
type PrimaryContentProps = {
articleId: string
url: string
}
function PrimaryContent(props: PrimaryContentProps): JSX.Element {
@ -94,7 +93,7 @@ function PrimaryContent(props: PrimaryContentProps): JSX.Element {
const [timedOut, setTimedOut] = useState(false)
const { successRedirectPath, error } = useGetArticleSavingStatus({
id: props.articleId,
url: props.url,
})
useEffect(() => {