diff --git a/frontend/src/screens/ProfilesScreen.tsx b/frontend/src/screens/ProfilesScreen.tsx index 87045b1..92b02d7 100644 --- a/frontend/src/screens/ProfilesScreen.tsx +++ b/frontend/src/screens/ProfilesScreen.tsx @@ -9,6 +9,7 @@ import { Icon } from '../components/Icon'; import { Modal } from '../components/Modal'; import { ShowSecretKeyModal } from '../components/ShowSecretKeyModal'; import { formatDate, shortenNpub } from '../lib/format'; +import type { MetadataPublishReport } from '../lib/types'; import { useApp } from '../state/AppProvider'; interface ProfilesScreenProps { @@ -329,6 +330,29 @@ function nip05Problem(value: string): string | null { return null; } +async function runModalSave(options: { + npub: string; + perform: () => Promise; + successMessage: (report: MetadataPublishReport) => string; + onSaved: (message: string) => void; + onError: (message: string | null) => void; + onSavingChange: (npub: string | null) => void; + setSaving: (saving: boolean) => void; +}): Promise { + options.onError(null); + options.setSaving(true); + options.onSavingChange(options.npub); + try { + const report = await options.perform(); + options.onSaved(options.successMessage(report)); + } catch (err) { + options.onError(err instanceof Error ? err.message : String(err)); + } finally { + options.setSaving(false); + options.onSavingChange(null); + } +} + function Nip05Modal({ target, onClose, @@ -352,24 +376,20 @@ function Nip05Modal({ const canSave = changed && !problem; const save = async (next: string | null) => { - onError(null); - setSaving(true); - onSavingChange(target.npub); - try { - const report = await setNip05(target.npub, next); - onSaved( + await runModalSave({ + npub: target.npub, + perform: () => setNip05(target.npub, next), + successMessage: (report) => report.failed.length === 0 ? next ? `NIP-05 "${next}" published to ${report.succeeded.length} relay(s). Remember it must also be served from your domain (see docs/NIP-05.md).` : 'NIP-05 removed and the change published.' : `NIP-05 saved for "${target.label}", but ${report.failed.length} relay(s) did not accept it. Use "Publish name" to retry.`, - ); - } catch (err) { - onError(err instanceof Error ? err.message : String(err)); - } finally { - setSaving(false); - onSavingChange(null); - } + onSaved, + onError, + onSavingChange, + setSaving, + }); }; return ( @@ -440,22 +460,18 @@ function RenameModal({ if (!canSave) { return; } - onError(null); - setSaving(true); - onSavingChange(target.npub); - try { - const report = await renameProfile(target.npub, trimmed); - onSaved( + await runModalSave({ + npub: target.npub, + perform: () => renameProfile(target.npub, trimmed), + successMessage: (report) => report.failed.length === 0 ? `Renamed to "${trimmed}" and published to ${report.succeeded.length} relay(s). It may take a minute to appear on other clients.` : `Renamed to "${trimmed}", but ${report.failed.length} relay(s) did not accept it. Use "Publish name" to retry.`, - ); - } catch (err) { - onError(err instanceof Error ? err.message : String(err)); - } finally { - setSaving(false); - onSavingChange(null); - } + onSaved, + onError, + onSavingChange, + setSaving, + }); }; return ( @@ -514,22 +530,18 @@ function PictureModal({ const [saving, setSaving] = useState(false); const save = async (nextUrl: string | null) => { - onError(null); - setSaving(true); - onSavingChange(target.npub); - try { - const report = await setProfilePicture(target.npub, nextUrl); - onSaved( + await runModalSave({ + npub: target.npub, + perform: () => setProfilePicture(target.npub, nextUrl), + successMessage: (report) => report.failed.length === 0 ? `Picture for "${target.label}" published to ${report.succeeded.length} relay(s).` : `Picture saved for "${target.label}", but ${report.failed.length} relay(s) did not accept it. Use "Publish name" to retry.`, - ); - } catch (err) { - onError(err instanceof Error ? err.message : String(err)); - } finally { - setSaving(false); - onSavingChange(null); - } + onSaved, + onError, + onSavingChange, + setSaving, + }); }; const onUpload = async () => {