From e15c6c3c64f2f68fa4b9def4eeeb5162563febc0 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 27 Jan 2026 19:57:32 +0200 Subject: [PATCH] convert useLoadDraft() hook to regular async function Co-Authored-By: Claude Opus 4.5 --- src/view/com/composer/Composer.tsx | 5 +- src/view/com/composer/drafts/state/queries.ts | 90 +++++++++---------- 2 files changed, 42 insertions(+), 53 deletions(-) diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 8c8a117f14..6583ceee34 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -131,7 +131,7 @@ import {useAnalytics} from '#/analytics' import {IS_ANDROID, IS_IOS, IS_NATIVE, IS_WEB} from '#/env' import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet' import {draftToComposerPosts} from './drafts/state/api' -import {useLoadDraft, useSaveDraftMutation} from './drafts/state/queries' +import {loadDraft, useSaveDraftMutation} from './drafts/state/queries' import {type DraftSummary} from './drafts/state/schema' import {PostLanguageSelect} from './select-language/PostLanguageSelect' import { @@ -193,7 +193,6 @@ export const ComposePost = ({ const discardPromptControl = Prompt.usePromptControl() const {mutateAsync: saveDraft, isPending: _isSavingDraft} = useSaveDraftMutation() - const loadDraft = useLoadDraft() const {closeAllDialogs} = useDialogStateControlContext() const {closeAllModals} = useModalControls() const {data: preferences} = usePreferencesQuery() @@ -343,7 +342,7 @@ export const ComposePost = ({ loadedMedia, }) }, - [loadDraft, composerDispatch], + [composerDispatch], ) const [publishOnUpload, setPublishOnUpload] = useState(false) diff --git a/src/view/com/composer/drafts/state/queries.ts b/src/view/com/composer/drafts/state/queries.ts index 9b9e6f67ff..a1efe2177c 100644 --- a/src/view/com/composer/drafts/state/queries.ts +++ b/src/view/com/composer/drafts/state/queries.ts @@ -1,4 +1,3 @@ -import {useCallback} from 'react' import {AppBskyDraftCreateDraft, type AppBskyDraftDefs} from '@atproto/api' import { useInfiniteQuery, @@ -40,53 +39,46 @@ export function useDraftsQuery() { } /** - * Hook to load a draft's local media for editing. + * Load a draft's local media for editing. * Takes the full Draft object (from DraftSummary) to avoid re-fetching. */ -export function useLoadDraft() { - return useCallback( - async ( - draft: AppBskyDraftDefs.Draft, - ): Promise<{ - loadedMedia: Map - }> => { - // Load local media files - const loadedMedia = new Map() - for (const post of draft.posts) { - // Load images - if (post.embedImages) { - for (const img of post.embedImages) { - try { - const url = await storage.loadMediaFromLocal(img.localRef.path) - loadedMedia.set(img.localRef.path, url) - } catch (e) { - logger.warn('Failed to load draft image', { - path: img.localRef.path, - error: e, - }) - } - } - } - // Load videos - if (post.embedVideos) { - for (const vid of post.embedVideos) { - try { - const url = await storage.loadMediaFromLocal(vid.localRef.path) - loadedMedia.set(vid.localRef.path, url) - } catch (e) { - logger.warn('Failed to load draft video', { - path: vid.localRef.path, - error: e, - }) - } - } +export async function loadDraft(draft: AppBskyDraftDefs.Draft): Promise<{ + loadedMedia: Map +}> { + // Load local media files + const loadedMedia = new Map() + for (const post of draft.posts) { + // Load images + if (post.embedImages) { + for (const img of post.embedImages) { + try { + const url = await storage.loadMediaFromLocal(img.localRef.path) + loadedMedia.set(img.localRef.path, url) + } catch (e) { + logger.warn('Failed to load draft image', { + path: img.localRef.path, + error: e, + }) } } + } + // Load videos + if (post.embedVideos) { + for (const vid of post.embedVideos) { + try { + const url = await storage.loadMediaFromLocal(vid.localRef.path) + loadedMedia.set(vid.localRef.path, url) + } catch (e) { + logger.warn('Failed to load draft video', { + path: vid.localRef.path, + error: e, + }) + } + } + } + } - return {loadedMedia} - }, - [], - ) + return {loadedMedia} } /** @@ -158,12 +150,15 @@ export function useDeleteDraftMutation() { return useMutation({ mutationFn: async ({ draftId, - draft, }: { draftId: string draft: AppBskyDraftDefs.Draft }) => { - // Delete local media files + // Delete from server first - if this fails, we keep local media for retry + await agent.app.bsky.draft.deleteDraft({id: draftId}) + }, + onSuccess: async (_, {draft}) => { + // Only delete local media after server deletion succeeds for (const post of draft.posts) { if (post.embedImages) { for (const img of post.embedImages) { @@ -176,11 +171,6 @@ export function useDeleteDraftMutation() { } } } - - // Delete from server - await agent.app.bsky.draft.deleteDraft({id: draftId}) - }, - onSuccess: () => { queryClient.invalidateQueries({queryKey: DRAFTS_QUERY_KEY}) }, })