store-only apps edit their listing on the store (storebound listing live / set: old -> new per field with the checks, a PATCH of only the edited fields; serve listing.set is the one store-only write, its token bound to the store ids; policy.rs STORE_ONLY_WRITES, write_with_confirm for store targets); screenshot captions per language and scene edited as a text edit of the shots copy JSON (JSON files keep their layout); Play content rating, target audience and App content answers in App info; docs/console-parity.md after the editors (73 rows: 55 complete, 18 with the reason) and tests/console-parity.test.ts keeping it honest

This commit is contained in:
CRTkafa 2026-10-14 00:53:38 +08:00
parent 3cea2af4e1
commit 7ac028421a
33 changed files with 852 additions and 157 deletions

View file

@ -24,6 +24,7 @@ import { ReleasesTab } from './tabs/Releases';
import { ReviewsTab } from './tabs/Reviews';
import { TestFlightTab } from './tabs/TestFlight';
import { EDIT_TABS, TabEditor, useUnsavedGuard } from './editors/TabEditor';
import { StoreListingEditor } from './editors/StoreListingEditor';
import { useEdits } from '../ui/Editor';
export const ascUrl = (appId: string | null | undefined): string => (appId ? `https://appstoreconnect.apple.com/apps/${encodeURIComponent(appId)}/distribution` : 'https://appstoreconnect.apple.com/apps');
@ -150,7 +151,7 @@ export function AppView({ app, tab }: { app: UnifiedApp; tab: AppTab }) {
{tabs.map((x, i) => (
<button key={x} ref={el => { tabRefs.current[i] = el; }} role="tab" id={`tab-${x}`} aria-selected={tab === x} aria-controls="tabpanel" tabIndex={tab === x ? 0 : -1} className="tab" onClick={() => setTab(x)}>
<Icon name={TAB_ICON[x]} />{t(TAB_KEY[x])}
{app.project && EDIT_TABS[x] && ed.count(app.project.id, EDIT_TABS[x]) > 0 && <span className="ed-dot" title={t('ed.unsaved', { count: ed.count(app.project.id, EDIT_TABS[x]) })} />}
{EDIT_TABS[x] && ed.count(app.project?.id ?? app.target, EDIT_TABS[x]) > 0 && <span className="ed-dot" title={t('ed.unsaved', { count: ed.count(app.project?.id ?? app.target, EDIT_TABS[x]) })} />}
</button>
))}
</div>
@ -160,6 +161,7 @@ export function AppView({ app, tab }: { app: UnifiedApp; tab: AppTab }) {
{tab === 'catalog' && app.project && <CatalogTab project={app.project} />}
{tab === 'prices' && app.project && <PricesTab project={app.project} />}
{tab === 'listings' && app.project && <><TabEditor tab={tab} project={app.project} /><ListingsTab project={app.project} /></>}
{tab === 'listings' && !app.project && <StoreListingEditor app={app} />}
{tab === 'art' && app.project && <ArtTab project={app.project} />}
{tab === 'health' && <HealthTab app={app} />}
{tab === 'reviews' && <ReviewsTab app={app} />}