diff --git a/src/components/DraftDigest/Feed/DeleteButton.tsx b/src/components/DraftDigest/Feed/DeleteButton.tsx index 6a8e6b5e52..b2a7be573f 100644 --- a/src/components/DraftDigest/Feed/DeleteButton.tsx +++ b/src/components/DraftDigest/Feed/DeleteButton.tsx @@ -12,9 +12,9 @@ import { useDialogSwitch, useMutation, } from '~/components' +import { updateUserDrafts } from '~/components/GQL' import { DeleteButtonDraftFragment, DeleteDraftMutation } from '~/gql/graphql' -import { DraftsContext } from '../../../views/Me/Drafts/context' import styles from './styles.module.css' interface DeleteButtonProps { @@ -36,17 +36,17 @@ const fragments = { const DeleteButton = ({ draft }: DeleteButtonProps) => { const { show, openDialog, closeDialog } = useDialogSwitch(false) - const [edges, setEdges] = useContext(DraftsContext) const { lang } = useContext(LanguageContext) const [deleteDraft] = useMutation(DELETE_DRAFT, { variables: { id: draft.id }, - update: () => { - const filteredEdges = (edges ?? []).filter( - ({ node }) => node.id !== draft.id - ) - setEdges(filteredEdges) + update: (cache) => { + updateUserDrafts({ + cache, + targetId: draft.id, + type: 'remove', + }) }, }) diff --git a/src/components/GQL/updates/index.ts b/src/components/GQL/updates/index.ts index 1cfd330dc5..79a7c9337a 100644 --- a/src/components/GQL/updates/index.ts +++ b/src/components/GQL/updates/index.ts @@ -12,6 +12,7 @@ export * from './userArticles' export * from './userCollectionDetail' export * from './userCollections' export * from './userCollectionsArticles' +export * from './userDrafts' export * from './userFollowerCount' export * from './userProfile' export * from './viewerFolloweeCount' diff --git a/src/components/GQL/updates/userDrafts.ts b/src/components/GQL/updates/userDrafts.ts new file mode 100644 index 0000000000..9f1e984941 --- /dev/null +++ b/src/components/GQL/updates/userDrafts.ts @@ -0,0 +1,47 @@ +import { DataProxy } from 'apollo-cache' + +import { MeDraftFeedQuery } from '~/gql/graphql' + +export const updateUserDrafts = ({ + cache, + targetId, + type, +}: { + cache: DataProxy + targetId?: string + type: 'remove' | 'add' +}) => { + // FIXME: circular dependencies + const { ME_DRAFTS_FEED } = require('~/views/Me/Drafts/gql') + + let draftsData: MeDraftFeedQuery | null = null + try { + draftsData = cache.readQuery({ query: ME_DRAFTS_FEED }) + } catch (e) { + // + } + + let draftEdges = draftsData?.viewer?.drafts.edges || [] + + switch (type) { + case 'remove': + draftEdges = draftEdges.filter((edge) => edge.node.id !== targetId) + break + } + + if (draftsData) { + cache.writeQuery({ + query: ME_DRAFTS_FEED, + data: { + ...draftsData, + viewer: { + ...draftsData?.viewer, + drafts: { + ...draftsData?.viewer?.drafts, + edges: draftEdges, + }, + }, + }, + }) + } +} diff --git a/src/components/Hook/useCreateDraft.tsx b/src/components/Hook/useCreateDraft.tsx index aab06811ee..77a29e9136 100644 --- a/src/components/Hook/useCreateDraft.tsx +++ b/src/components/Hook/useCreateDraft.tsx @@ -2,11 +2,15 @@ import { useRoute } from '~/components' import { useMutation } from '~/components/GQL' import CREATE_DRAFT from '~/components/GQL/mutations/createDraft' import { CreateDraftMutation } from '~/gql/graphql' +import { ME_DRAFTS_FEED } from '~/views/Me/Drafts/gql' export const useCreateDraft = () => { const { router } = useRoute() - const [create] = useMutation(CREATE_DRAFT) + // refetch /me/drafts after creating a new draft + const [create] = useMutation(CREATE_DRAFT, { + refetchQueries: [{ query: ME_DRAFTS_FEED }], + }) // create draft and redirect to draft detail page // NOTE: shallow replace if it's already on it diff --git a/src/views/Me/DraftDetail/PublishState/PublishedState.tsx b/src/views/Me/DraftDetail/PublishState/PublishedState.tsx index ca6ec223c3..26124ef9e5 100644 --- a/src/views/Me/DraftDetail/PublishState/PublishedState.tsx +++ b/src/views/Me/DraftDetail/PublishState/PublishedState.tsx @@ -2,8 +2,15 @@ import { useRouter } from 'next/router' import { useEffect } from 'react' import { toPath } from '~/common/utils' -import { Dialog, ShareDialog, Translate } from '~/components' -import { PublishStateDraftFragment } from '~/gql/graphql' +import { + Dialog, + ShareDialog, + Translate, + useImperativeQuery, +} from '~/components' +import { MeDraftFeedQuery, PublishStateDraftFragment } from '~/gql/graphql' + +import { ME_DRAFTS_FEED } from '../../Drafts/gql' const BasePublishedState = ({ openShareDialog, @@ -20,6 +27,14 @@ const BasePublishedState = ({ const PublishedState = ({ draft }: { draft: PublishStateDraftFragment }) => { const router = useRouter() + // refetch /me/drafts on published + const refetch = useImperativeQuery(ME_DRAFTS_FEED, { + variables: { id: draft.id }, + }) + useEffect(() => { + refetch() + }, []) + if (!draft.article) { return null } diff --git a/src/views/Me/Drafts/context.ts b/src/views/Me/Drafts/context.ts deleted file mode 100644 index 32426c50c1..0000000000 --- a/src/views/Me/Drafts/context.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createCacheContext } from '~/components/Hook' -import { MeDraftFeedQuery } from '~/gql/graphql' - -type Edges = NonNullable< - NonNullable['drafts']['edges'] -> - -export const DraftsContext = createCacheContext() diff --git a/src/views/Me/Drafts/gql.ts b/src/views/Me/Drafts/gql.ts new file mode 100644 index 0000000000..357d08f039 --- /dev/null +++ b/src/views/Me/Drafts/gql.ts @@ -0,0 +1,26 @@ +import gql from 'graphql-tag' + +import { DraftDigest } from '~/components/DraftDigest' + +export const ME_DRAFTS_FEED = gql` + query MeDraftFeed($after: String) { + viewer { + id + drafts(input: { first: 20, after: $after }) + @connection(key: "viewerDrafts") { + pageInfo { + startCursor + endCursor + hasNextPage + } + edges { + cursor + node { + ...DraftDigestFeedDraft + } + } + } + } + } + ${DraftDigest.Feed.fragments.draft} +` diff --git a/src/views/Me/Drafts/index.tsx b/src/views/Me/Drafts/index.tsx index c6fed419ee..06eed9c3b1 100644 --- a/src/views/Me/Drafts/index.tsx +++ b/src/views/Me/Drafts/index.tsx @@ -1,6 +1,4 @@ import { useQuery } from '@apollo/react-hooks' -import gql from 'graphql-tag' -import { useEffect } from 'react' import { mergeConnections } from '~/common/utils' import { @@ -12,52 +10,15 @@ import { List, QueryError, Spinner, - useCache, } from '~/components' import { MeDraftFeedQuery } from '~/gql/graphql' -import { DraftsContext } from './context' - -const ME_DRAFTS_FEED = gql` - query MeDraftFeed($after: String) { - viewer { - id - drafts(input: { first: 20, after: $after }) - @connection(key: "viewerDrafts") { - pageInfo { - startCursor - endCursor - hasNextPage - } - edges { - cursor - node { - ...DraftDigestFeedDraft - } - } - } - } - } - ${DraftDigest.Feed.fragments.draft} -` - -type Edge = NonNullable< - NonNullable['drafts']['edges'] -> +import { ME_DRAFTS_FEED } from './gql' export const BaseMeDrafts = () => { - const [edges, setEdges, DraftsContextProvider] = useCache( - [], - DraftsContext - ) - const { data, loading, error, fetchMore } = useQuery(ME_DRAFTS_FEED) - useEffect(() => { - setEdges(data?.viewer?.drafts.edges ?? []) - }, [data?.viewer?.drafts.edges?.length]) - if (loading) { return } @@ -67,9 +28,9 @@ export const BaseMeDrafts = () => { } const connectionPath = 'viewer.drafts' - const { pageInfo } = data?.viewer?.drafts || {} + const { edges, pageInfo } = data?.viewer?.drafts || {} - if (edges.length <= 0 || !pageInfo) { + if (!edges || edges.length <= 0 || !pageInfo) { return } @@ -85,21 +46,15 @@ export const BaseMeDrafts = () => { }) return ( - - - - {edges.map(({ node, cursor }) => ( - - - - ))} - - - + + + {edges.map(({ node, cursor }) => ( + + + + ))} + + ) }