feat(settings): move account json editing to dedicated full editor route

This commit is contained in:
plebeius
2026-02-24 20:33:07 +08:00
parent dc43a8438e
commit fb9443a0f8
47 changed files with 852 additions and 219 deletions
@@ -0,0 +1,67 @@
import { describe, it, expect } from 'vitest';
import { buildEditableAccountJson, safeParseAccountJson, buildSavePayload } from '../account-editor-utils';
describe('buildEditableAccountJson', () => {
it('strips runtime-only fields from account', () => {
const account = {
id: 'abc',
name: 'Account 1',
author: { address: '0x123', shortAddress: '0x1...3', avatar: { url: 'https://example.com' } },
plebbit: { someOption: true },
karma: 42,
plebbitReactOptions: { foo: 'bar' },
unreadNotificationCount: 5,
};
const result = JSON.parse(buildEditableAccountJson(account));
expect(result.account.id).toBe('abc');
expect(result.account.name).toBe('Account 1');
expect(result.account.author.address).toBe('0x123');
expect(result.account.author.avatar).toBeUndefined();
expect(result.account.plebbit).toBeUndefined();
expect(result.account.karma).toBeUndefined();
expect(result.account.plebbitReactOptions).toBeUndefined();
expect(result.account.unreadNotificationCount).toBeUndefined();
});
it('handles undefined account', () => {
const result = buildEditableAccountJson(undefined);
expect(result).toBeTruthy();
const parsed = JSON.parse(result);
expect(parsed.account).toBeDefined();
});
});
describe('safeParseAccountJson', () => {
it('parses valid account JSON', () => {
const result = safeParseAccountJson('{"account": {"name": "test"}}');
expect(result).toEqual({ account: { name: 'test' } });
});
it('returns null for invalid JSON', () => {
expect(safeParseAccountJson('not json')).toBeNull();
});
it('returns null for JSON without account key', () => {
expect(safeParseAccountJson('{"name": "test"}')).toBeNull();
});
it('returns null for non-object account', () => {
expect(safeParseAccountJson('{"account": "string"}')).toBeNull();
});
});
describe('buildSavePayload', () => {
it('preserves original account id', () => {
const parsed = { account: { name: 'updated', id: 'wrong-id' } };
const result = buildSavePayload(parsed, 'original-id');
expect(result.id).toBe('original-id');
expect(result.name).toBe('updated');
});
it('handles undefined original id', () => {
const parsed = { account: { name: 'test' } };
const result = buildSavePayload(parsed, undefined);
expect(result.id).toBeUndefined();
expect(result.name).toBe('test');
});
});
+47
View File
@@ -0,0 +1,47 @@
import stringify from 'json-stringify-pretty-compact';
type AccountLike = {
id?: string;
name?: string;
author?: { address?: string; shortAddress?: string; avatar?: unknown };
plebbit?: unknown;
karma?: unknown;
plebbitReactOptions?: unknown;
unreadNotificationCount?: unknown;
[key: string]: unknown;
};
/**
* Build the editable JSON string for an account, stripping runtime-only fields.
*/
export const buildEditableAccountJson = (account: AccountLike | undefined): string =>
stringify({
account: {
...account,
author: { ...account?.author, avatar: undefined },
plebbit: undefined,
karma: undefined,
plebbitReactOptions: undefined,
unreadNotificationCount: undefined,
},
});
export const safeParseAccountJson = (text: string): { account: Record<string, unknown> } | null => {
try {
const parsed = JSON.parse(text);
if (parsed && typeof parsed === 'object' && parsed.account && typeof parsed.account === 'object') {
return parsed as { account: Record<string, unknown> };
}
return null;
} catch {
return null;
}
};
/**
* Build a save-ready account payload, preserving the original account id.
*/
export const buildSavePayload = (parsed: { account: Record<string, unknown> }, originalId: string | undefined): Record<string, unknown> => ({
...parsed.account,
id: originalId,
});