desktop editors: edit in place what App Store Connect and Play Console let the owner edit (listings per language for both stores with live counters and the check / scan rules, store details, App info, age rating, App Review, Play store settings, Data safety and App Privacy answers, promotion blocks, catalog names / prices / offers, TestFlight information, scene order); storebound edit (project.edit) saves into the config by path keeping comments and formatting, the listing files and the review contact, dry run with the diff and the checks first; Apply shows each store's dry run in the window; unsaved edits survive tab switches with undo / redo; tests/edit.test.ts, apps/desktop/tests/edits.test.ts, boot check editor case
This commit is contained in:
parent
714352ec18
commit
3cea2af4e1
37 changed files with 3020 additions and 54 deletions
|
|
@ -23,6 +23,8 @@ import { PricesTab } from './tabs/Prices';
|
|||
import { ReleasesTab } from './tabs/Releases';
|
||||
import { ReviewsTab } from './tabs/Reviews';
|
||||
import { TestFlightTab } from './tabs/TestFlight';
|
||||
import { EDIT_TABS, TabEditor, useUnsavedGuard } from './editors/TabEditor';
|
||||
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');
|
||||
export const PLAY_CONSOLE = 'https://play.google.com/console/';
|
||||
|
|
@ -99,6 +101,8 @@ export function AppView({ app, tab }: { app: UnifiedApp; tab: AppTab }) {
|
|||
const android = e?.app?.platforms.android ?? (app.android ? { packageName: app.android.app.id } : null);
|
||||
const name = (app.project && e?.app?.name) || app.name;
|
||||
const tabs = tabsFor(!!app.project);
|
||||
const ed = useEdits();
|
||||
useUnsavedGuard();
|
||||
const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
|
||||
const studio = d.studios.find(s => s.id === app.studio) ?? null;
|
||||
const setTab = (x: AppTab) => nav.go({ screen: 'app', appId: app.key, tab: x });
|
||||
|
|
@ -146,6 +150,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]) })} />}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -154,7 +159,7 @@ export function AppView({ app, tab }: { app: UnifiedApp; tab: AppTab }) {
|
|||
{tab === 'releases' && <ReleasesTab app={app} />}
|
||||
{tab === 'catalog' && app.project && <CatalogTab project={app.project} />}
|
||||
{tab === 'prices' && app.project && <PricesTab project={app.project} />}
|
||||
{tab === 'listings' && app.project && <ListingsTab project={app.project} />}
|
||||
{tab === 'listings' && app.project && <><TabEditor tab={tab} project={app.project} /><ListingsTab project={app.project} /></>}
|
||||
{tab === 'art' && app.project && <ArtTab project={app.project} />}
|
||||
{tab === 'health' && <HealthTab app={app} />}
|
||||
{tab === 'reviews' && <ReviewsTab app={app} />}
|
||||
|
|
@ -162,6 +167,7 @@ export function AppView({ app, tab }: { app: UnifiedApp; tab: AppTab }) {
|
|||
{tab === 'growth' && <GrowthTab app={app} />}
|
||||
{tab === 'appinfo' && app.project && <AppInfoTab project={app.project} />}
|
||||
{tab === 'checks' && app.project && <ChecksTab project={app.project} />}
|
||||
{tab !== 'listings' && app.project && !app.project.missing && EDIT_TABS[tab] && <TabEditor tab={tab} project={app.project} />}
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</>}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue