refactor: 收口创作恢复身份匹配
This commit is contained in:
@@ -408,9 +408,16 @@ import {
|
||||
buildVisualNovelCreationUrlState,
|
||||
buildWoodenFishCreationUrlState,
|
||||
hasPuzzleRuntimeUrlStateValue,
|
||||
matchesBabyObjectMatchCreationUrlRestoreTarget,
|
||||
matchesBarkBattleCreationUrlRestoreTarget,
|
||||
matchesBigFishCreationUrlRestoreTarget,
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget,
|
||||
matchesVisualNovelCreationUrlRestoreTarget,
|
||||
normalizeCreationUrlValue,
|
||||
resolveCreationUrlRestoreTarget,
|
||||
resolveInitialCreationUrlRestoreDecision,
|
||||
resolveJumpHopCreationUrlRestoreStage,
|
||||
resolveWoodenFishCreationUrlRestoreStage,
|
||||
} from './platformCreationUrlStateModel';
|
||||
import { resolvePlatformCreationWorkDeleteConfirmationModel } from './platformCreationWorkDeleteFlow';
|
||||
import {
|
||||
@@ -12150,7 +12157,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const { sessionId, profileId, draftId, workId } = target;
|
||||
const { sessionId, profileId } = target;
|
||||
|
||||
if (target.kind === 'big-fish') {
|
||||
const targetSessionId = target.bigFishSessionId;
|
||||
@@ -12159,10 +12166,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
(bigFishWorks.length > 0
|
||||
? bigFishWorks
|
||||
: (await listBigFishWorks().catch(() => ({ items: [] }))).items
|
||||
).find(
|
||||
(item) =>
|
||||
item.sourceSessionId === targetSessionId ||
|
||||
item.workId === workId,
|
||||
).find((item) =>
|
||||
matchesBigFishCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedWork) {
|
||||
await openBigFishDraft(matchedWork);
|
||||
@@ -12180,11 +12185,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
: mapMatch3DWorksForRuntimeUi(
|
||||
(await listMatch3DWorks().catch(() => ({ items: [] }))).items,
|
||||
)
|
||||
).find(
|
||||
(item) =>
|
||||
item.sourceSessionId === sessionId ||
|
||||
item.profileId === profileId ||
|
||||
item.workId === workId,
|
||||
).find((item) =>
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedWork) {
|
||||
await openMatch3DDraft(matchedWork, { forceDraft: true });
|
||||
@@ -12201,11 +12203,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
(squareHoleWorks.length > 0
|
||||
? squareHoleWorks
|
||||
: (await listSquareHoleWorks().catch(() => ({ items: [] }))).items
|
||||
).find(
|
||||
(item) =>
|
||||
item.sourceSessionId === sessionId ||
|
||||
item.profileId === profileId ||
|
||||
item.workId === workId,
|
||||
).find((item) =>
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedWork) {
|
||||
await openSquareHoleDraft(matchedWork, { forceDraft: true });
|
||||
@@ -12222,11 +12221,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
(puzzleWorks.length > 0
|
||||
? puzzleWorks
|
||||
: (await listPuzzleWorks().catch(() => ({ items: [] }))).items
|
||||
).find(
|
||||
(item) =>
|
||||
item.sourceSessionId === sessionId ||
|
||||
item.profileId === profileId ||
|
||||
item.workId === workId,
|
||||
).find((item) =>
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedWork) {
|
||||
await openPuzzleDraft(matchedWork);
|
||||
@@ -12243,7 +12239,9 @@ export function PlatformEntryFlowShellImpl({
|
||||
(visualNovelWorks.length > 0
|
||||
? visualNovelWorks
|
||||
: (await listVisualNovelWorks().catch(() => ({ works: [] }))).works
|
||||
).find((item) => item.profileId === profileId) ?? null;
|
||||
).find((item) =>
|
||||
matchesVisualNovelCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedWork) {
|
||||
await openVisualNovelDraft(matchedWork, { forceDraft: true });
|
||||
return;
|
||||
@@ -12259,8 +12257,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
(barkBattleWorks.length > 0
|
||||
? barkBattleWorks
|
||||
: (await listBarkBattleWorks().catch(() => ({ items: [] }))).items
|
||||
).find(
|
||||
(item) => item.workId === workId || item.draftId === draftId,
|
||||
).find((item) =>
|
||||
matchesBarkBattleCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedWork) {
|
||||
openBarkBattleDraft(matchedWork, { forceDraft: true });
|
||||
@@ -12273,11 +12271,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
(babyObjectMatchDrafts.length > 0
|
||||
? babyObjectMatchDrafts
|
||||
: await listLocalBabyObjectMatchDrafts().catch(() => [])
|
||||
).find(
|
||||
(item) =>
|
||||
item.profileId === profileId ||
|
||||
item.draftId === draftId ||
|
||||
item.profileId === workId,
|
||||
).find((item) =>
|
||||
matchesBabyObjectMatchCreationUrlRestoreTarget(item, target),
|
||||
) ?? null;
|
||||
if (matchedDraft) {
|
||||
openBabyObjectMatchDraft(matchedDraft);
|
||||
@@ -12313,11 +12308,11 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
enterCreateTab();
|
||||
setSelectionStage(
|
||||
target.isGeneratingPath
|
||||
? 'jump-hop-generating'
|
||||
: session?.draft || work
|
||||
? 'jump-hop-result'
|
||||
: 'jump-hop-workspace',
|
||||
resolveJumpHopCreationUrlRestoreStage({
|
||||
isGeneratingPath: target.isGeneratingPath,
|
||||
hasRestoredDraft: Boolean(session?.draft),
|
||||
hasRestoredWork: Boolean(work),
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
setJumpHopError(
|
||||
@@ -12344,11 +12339,10 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
enterCreateTab();
|
||||
setSelectionStage(
|
||||
target.isGeneratingPath
|
||||
? 'wooden-fish-generating'
|
||||
: session.draft
|
||||
? 'wooden-fish-result'
|
||||
: 'wooden-fish-workspace',
|
||||
resolveWoodenFishCreationUrlRestoreStage({
|
||||
isGeneratingPath: target.isGeneratingPath,
|
||||
hasRestoredDraft: Boolean(session.draft),
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
setWoodenFishError(
|
||||
|
||||
@@ -31,9 +31,16 @@ import {
|
||||
buildWoodenFishCreationUrlState,
|
||||
hasCreationUrlStateValue,
|
||||
hasPuzzleRuntimeUrlStateValue,
|
||||
matchesBabyObjectMatchCreationUrlRestoreTarget,
|
||||
matchesBarkBattleCreationUrlRestoreTarget,
|
||||
matchesBigFishCreationUrlRestoreTarget,
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget,
|
||||
matchesVisualNovelCreationUrlRestoreTarget,
|
||||
normalizeCreationUrlValue,
|
||||
resolveCreationUrlRestoreTarget,
|
||||
resolveInitialCreationUrlRestoreDecision,
|
||||
resolveJumpHopCreationUrlRestoreStage,
|
||||
resolveWoodenFishCreationUrlRestoreStage,
|
||||
} from './platformCreationUrlStateModel';
|
||||
|
||||
describe('platformCreationUrlStateModel', () => {
|
||||
@@ -193,6 +200,129 @@ describe('platformCreationUrlStateModel', () => {
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('matches restore targets against work and draft identities', () => {
|
||||
const bigFishTarget = resolveCreationUrlRestoreTarget(
|
||||
'/creation/big-fish/result',
|
||||
{
|
||||
workId: 'big-fish-work-river',
|
||||
},
|
||||
);
|
||||
expect(bigFishTarget?.kind).toBe('big-fish');
|
||||
if (bigFishTarget?.kind !== 'big-fish') {
|
||||
throw new Error('big fish target expected');
|
||||
}
|
||||
expect(
|
||||
matchesBigFishCreationUrlRestoreTarget(
|
||||
{ sourceSessionId: 'river' },
|
||||
bigFishTarget,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesBigFishCreationUrlRestoreTarget(
|
||||
{ workId: 'big-fish-work-river' },
|
||||
bigFishTarget,
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
const target = {
|
||||
sessionId: 'session-1',
|
||||
profileId: 'profile-1',
|
||||
draftId: 'draft-1',
|
||||
workId: 'work-1',
|
||||
};
|
||||
expect(
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(
|
||||
{ sourceSessionId: 'session-1' },
|
||||
target,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(
|
||||
{ profileId: 'profile-1' },
|
||||
target,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(
|
||||
{ workId: 'work-1' },
|
||||
target,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesVisualNovelCreationUrlRestoreTarget(
|
||||
{ profileId: 'profile-1' },
|
||||
target,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesBarkBattleCreationUrlRestoreTarget(
|
||||
{ draftId: 'draft-1' },
|
||||
target,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesBabyObjectMatchCreationUrlRestoreTarget(
|
||||
{ profileId: 'work-1' },
|
||||
target,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matchesSessionProfileWorkCreationUrlRestoreTarget(
|
||||
{ sourceSessionId: null, profileId: null, workId: null },
|
||||
{ sessionId: null, profileId: null, workId: null },
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
matchesBarkBattleCreationUrlRestoreTarget(
|
||||
{ workId: null, draftId: null },
|
||||
{ workId: null, draftId: null },
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('resolves work backed restore stages', () => {
|
||||
expect(
|
||||
resolveJumpHopCreationUrlRestoreStage({
|
||||
isGeneratingPath: true,
|
||||
hasRestoredDraft: false,
|
||||
hasRestoredWork: true,
|
||||
}),
|
||||
).toBe('jump-hop-generating');
|
||||
expect(
|
||||
resolveJumpHopCreationUrlRestoreStage({
|
||||
isGeneratingPath: false,
|
||||
hasRestoredDraft: false,
|
||||
hasRestoredWork: true,
|
||||
}),
|
||||
).toBe('jump-hop-result');
|
||||
expect(
|
||||
resolveJumpHopCreationUrlRestoreStage({
|
||||
isGeneratingPath: false,
|
||||
hasRestoredDraft: false,
|
||||
hasRestoredWork: false,
|
||||
}),
|
||||
).toBe('jump-hop-workspace');
|
||||
|
||||
expect(
|
||||
resolveWoodenFishCreationUrlRestoreStage({
|
||||
isGeneratingPath: true,
|
||||
hasRestoredDraft: true,
|
||||
}),
|
||||
).toBe('wooden-fish-generating');
|
||||
expect(
|
||||
resolveWoodenFishCreationUrlRestoreStage({
|
||||
isGeneratingPath: false,
|
||||
hasRestoredDraft: true,
|
||||
}),
|
||||
).toBe('wooden-fish-result');
|
||||
expect(
|
||||
resolveWoodenFishCreationUrlRestoreStage({
|
||||
isGeneratingPath: false,
|
||||
hasRestoredDraft: false,
|
||||
}),
|
||||
).toBe('wooden-fish-workspace');
|
||||
});
|
||||
|
||||
test('builds creation restore state for core session based plays', () => {
|
||||
expect(
|
||||
buildBigFishCreationUrlState({
|
||||
|
||||
@@ -20,6 +20,7 @@ import type {
|
||||
WoodenFishSessionSnapshotResponse,
|
||||
WoodenFishWorkProfileResponse,
|
||||
} from '../../services/wooden-fish/woodenFishClient';
|
||||
import type { SelectionStage } from './platformEntryTypes';
|
||||
import {
|
||||
buildPuzzleResultProfileId,
|
||||
buildPuzzleResultWorkId,
|
||||
@@ -80,19 +81,43 @@ type CreationUrlRestoreTargetBase = {
|
||||
isGeneratingPath: boolean;
|
||||
};
|
||||
|
||||
export type CreationUrlRestoreTarget =
|
||||
| (CreationUrlRestoreTargetBase & {
|
||||
kind: 'big-fish';
|
||||
bigFishSessionId: string | null;
|
||||
})
|
||||
| (CreationUrlRestoreTargetBase & {
|
||||
kind: Exclude<CreationUrlRestoreTargetKind, 'big-fish'>;
|
||||
});
|
||||
export type BigFishCreationUrlRestoreTarget = CreationUrlRestoreTargetBase & {
|
||||
kind: 'big-fish';
|
||||
bigFishSessionId: string | null;
|
||||
};
|
||||
|
||||
type NonBigFishCreationUrlRestoreTarget = Extract<
|
||||
CreationUrlRestoreTarget,
|
||||
{ kind: Exclude<CreationUrlRestoreTargetKind, 'big-fish'> }
|
||||
>;
|
||||
type NonBigFishCreationUrlRestoreTarget = CreationUrlRestoreTargetBase & {
|
||||
kind: Exclude<CreationUrlRestoreTargetKind, 'big-fish'>;
|
||||
};
|
||||
|
||||
export type CreationUrlRestoreTarget =
|
||||
| BigFishCreationUrlRestoreTarget
|
||||
| NonBigFishCreationUrlRestoreTarget;
|
||||
|
||||
export type BigFishRestoreWorkIdentity = {
|
||||
sourceSessionId?: string | null;
|
||||
workId?: string | null;
|
||||
};
|
||||
|
||||
export type SessionProfileWorkRestoreIdentity = {
|
||||
sourceSessionId?: string | null;
|
||||
profileId?: string | null;
|
||||
workId?: string | null;
|
||||
};
|
||||
|
||||
export type ProfileRestoreWorkIdentity = {
|
||||
profileId?: string | null;
|
||||
};
|
||||
|
||||
export type BarkBattleRestoreWorkIdentity = {
|
||||
workId?: string | null;
|
||||
draftId?: string | null;
|
||||
};
|
||||
|
||||
export type BabyObjectMatchRestoreDraftIdentity = {
|
||||
profileId?: string | null;
|
||||
draftId?: string | null;
|
||||
};
|
||||
|
||||
const CREATION_URL_RESTORE_TARGET_ROUTES = [
|
||||
['/creation/big-fish', 'big-fish'],
|
||||
@@ -147,6 +172,89 @@ export function resolveCreationUrlRestoreTarget(
|
||||
return base as NonBigFishCreationUrlRestoreTarget;
|
||||
}
|
||||
|
||||
function matchesRestoreValue(
|
||||
itemValue: string | null | undefined,
|
||||
targetValue: string | null,
|
||||
) {
|
||||
return Boolean(targetValue && itemValue === targetValue);
|
||||
}
|
||||
|
||||
export function matchesBigFishCreationUrlRestoreTarget(
|
||||
item: BigFishRestoreWorkIdentity,
|
||||
target: BigFishCreationUrlRestoreTarget,
|
||||
) {
|
||||
return (
|
||||
matchesRestoreValue(item.sourceSessionId, target.bigFishSessionId) ||
|
||||
matchesRestoreValue(item.workId, target.workId)
|
||||
);
|
||||
}
|
||||
|
||||
export function matchesSessionProfileWorkCreationUrlRestoreTarget(
|
||||
item: SessionProfileWorkRestoreIdentity,
|
||||
target: Pick<CreationUrlRestoreTarget, 'sessionId' | 'profileId' | 'workId'>,
|
||||
) {
|
||||
return (
|
||||
matchesRestoreValue(item.sourceSessionId, target.sessionId) ||
|
||||
matchesRestoreValue(item.profileId, target.profileId) ||
|
||||
matchesRestoreValue(item.workId, target.workId)
|
||||
);
|
||||
}
|
||||
|
||||
export function matchesVisualNovelCreationUrlRestoreTarget(
|
||||
item: ProfileRestoreWorkIdentity,
|
||||
target: Pick<CreationUrlRestoreTarget, 'profileId'>,
|
||||
) {
|
||||
return matchesRestoreValue(item.profileId, target.profileId);
|
||||
}
|
||||
|
||||
export function matchesBarkBattleCreationUrlRestoreTarget(
|
||||
item: BarkBattleRestoreWorkIdentity,
|
||||
target: Pick<CreationUrlRestoreTarget, 'workId' | 'draftId'>,
|
||||
) {
|
||||
return (
|
||||
matchesRestoreValue(item.workId, target.workId) ||
|
||||
matchesRestoreValue(item.draftId, target.draftId)
|
||||
);
|
||||
}
|
||||
|
||||
export function matchesBabyObjectMatchCreationUrlRestoreTarget(
|
||||
item: BabyObjectMatchRestoreDraftIdentity,
|
||||
target: Pick<CreationUrlRestoreTarget, 'profileId' | 'draftId' | 'workId'>,
|
||||
) {
|
||||
return (
|
||||
matchesRestoreValue(item.profileId, target.profileId) ||
|
||||
matchesRestoreValue(item.draftId, target.draftId) ||
|
||||
matchesRestoreValue(item.profileId, target.workId)
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveJumpHopCreationUrlRestoreStage(params: {
|
||||
isGeneratingPath: boolean;
|
||||
hasRestoredDraft: boolean;
|
||||
hasRestoredWork: boolean;
|
||||
}): SelectionStage {
|
||||
if (params.isGeneratingPath) {
|
||||
return 'jump-hop-generating';
|
||||
}
|
||||
|
||||
return params.hasRestoredDraft || params.hasRestoredWork
|
||||
? 'jump-hop-result'
|
||||
: 'jump-hop-workspace';
|
||||
}
|
||||
|
||||
export function resolveWoodenFishCreationUrlRestoreStage(params: {
|
||||
isGeneratingPath: boolean;
|
||||
hasRestoredDraft: boolean;
|
||||
}): SelectionStage {
|
||||
if (params.isGeneratingPath) {
|
||||
return 'wooden-fish-generating';
|
||||
}
|
||||
|
||||
return params.hasRestoredDraft
|
||||
? 'wooden-fish-result'
|
||||
: 'wooden-fish-workspace';
|
||||
}
|
||||
|
||||
export type InitialCreationUrlRestoreDecision =
|
||||
| { type: 'skip' }
|
||||
| { type: 'mark-handled' }
|
||||
|
||||
Reference in New Issue
Block a user