refactor: share modal save lifecycle

This commit is contained in:
Avi 2026-08-25 11:04:20 -05:00
commit 7098e75ca3

View file

@ -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<MetadataPublishReport>;
successMessage: (report: MetadataPublishReport) => string;
onSaved: (message: string) => void;
onError: (message: string | null) => void;
onSavingChange: (npub: string | null) => void;
setSaving: (saving: boolean) => void;
}): Promise<void> {
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 () => {