refactor: 收口创作直达恢复目标
This commit is contained in:
@@ -409,6 +409,7 @@ import {
|
||||
buildWoodenFishCreationUrlState,
|
||||
hasPuzzleRuntimeUrlStateValue,
|
||||
normalizeCreationUrlValue,
|
||||
resolveCreationUrlRestoreTarget,
|
||||
resolveInitialCreationUrlRestoreDecision,
|
||||
} from './platformCreationUrlStateModel';
|
||||
import { resolvePlatformCreationWorkDeleteConfirmationModel } from './platformCreationWorkDeleteFlow';
|
||||
@@ -12142,21 +12143,17 @@ export function PlatformEntryFlowShellImpl({
|
||||
handledInitialCreationUrlStateRef.current = true;
|
||||
|
||||
const restoreCreationUrlState = async () => {
|
||||
const path = window.location.pathname;
|
||||
const sessionId = normalizeCreationUrlValue(
|
||||
initialCreationUrlState.sessionId,
|
||||
const target = resolveCreationUrlRestoreTarget(
|
||||
window.location.pathname,
|
||||
initialCreationUrlState,
|
||||
);
|
||||
const profileId = normalizeCreationUrlValue(
|
||||
initialCreationUrlState.profileId,
|
||||
);
|
||||
const draftId = normalizeCreationUrlValue(
|
||||
initialCreationUrlState.draftId,
|
||||
);
|
||||
const workId = normalizeCreationUrlValue(initialCreationUrlState.workId);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const { sessionId, profileId, draftId, workId } = target;
|
||||
|
||||
if (path.startsWith('/creation/big-fish')) {
|
||||
const targetSessionId =
|
||||
sessionId ?? workId?.replace(/^big-fish-work-/u, '');
|
||||
if (target.kind === 'big-fish') {
|
||||
const targetSessionId = target.bigFishSessionId;
|
||||
if (targetSessionId) {
|
||||
const matchedWork =
|
||||
(bigFishWorks.length > 0
|
||||
@@ -12176,7 +12173,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/match3d')) {
|
||||
if (target.kind === 'match3d') {
|
||||
const matchedWork =
|
||||
(match3dWorks.length > 0
|
||||
? match3dWorks
|
||||
@@ -12199,7 +12196,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/square-hole')) {
|
||||
if (target.kind === 'square-hole') {
|
||||
const matchedWork =
|
||||
(squareHoleWorks.length > 0
|
||||
? squareHoleWorks
|
||||
@@ -12220,7 +12217,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/puzzle')) {
|
||||
if (target.kind === 'puzzle') {
|
||||
const matchedWork =
|
||||
(puzzleWorks.length > 0
|
||||
? puzzleWorks
|
||||
@@ -12241,7 +12238,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/visual-novel')) {
|
||||
if (target.kind === 'visual-novel') {
|
||||
const matchedWork =
|
||||
(visualNovelWorks.length > 0
|
||||
? visualNovelWorks
|
||||
@@ -12257,7 +12254,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/bark-battle')) {
|
||||
if (target.kind === 'bark-battle') {
|
||||
const matchedWork =
|
||||
(barkBattleWorks.length > 0
|
||||
? barkBattleWorks
|
||||
@@ -12271,7 +12268,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/baby-object-match')) {
|
||||
if (target.kind === 'baby-object-match') {
|
||||
const matchedDraft =
|
||||
(babyObjectMatchDrafts.length > 0
|
||||
? babyObjectMatchDrafts
|
||||
@@ -12288,7 +12285,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/jump-hop')) {
|
||||
if (target.kind === 'jump-hop') {
|
||||
let session: JumpHopSessionSnapshotResponse | null = null;
|
||||
let work: JumpHopWorkProfileResponse | null = null;
|
||||
try {
|
||||
@@ -12316,7 +12313,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
enterCreateTab();
|
||||
setSelectionStage(
|
||||
path.includes('/generating')
|
||||
target.isGeneratingPath
|
||||
? 'jump-hop-generating'
|
||||
: session?.draft || work
|
||||
? 'jump-hop-result'
|
||||
@@ -12330,7 +12327,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith('/creation/wooden-fish')) {
|
||||
if (target.kind === 'wooden-fish') {
|
||||
if (!sessionId) {
|
||||
return;
|
||||
}
|
||||
@@ -12347,7 +12344,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
enterCreateTab();
|
||||
setSelectionStage(
|
||||
path.includes('/generating')
|
||||
target.isGeneratingPath
|
||||
? 'wooden-fish-generating'
|
||||
: session.draft
|
||||
? 'wooden-fish-result'
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
hasCreationUrlStateValue,
|
||||
hasPuzzleRuntimeUrlStateValue,
|
||||
normalizeCreationUrlValue,
|
||||
resolveCreationUrlRestoreTarget,
|
||||
resolveInitialCreationUrlRestoreDecision,
|
||||
} from './platformCreationUrlStateModel';
|
||||
|
||||
@@ -94,6 +95,104 @@ describe('platformCreationUrlStateModel', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('resolves supported creation url restore targets from paths', () => {
|
||||
const state = {
|
||||
sessionId: ' session-1 ',
|
||||
profileId: ' profile-1 ',
|
||||
draftId: ' draft-1 ',
|
||||
workId: ' work-1 ',
|
||||
};
|
||||
const cases = [
|
||||
['/creation/big-fish/result', 'big-fish'],
|
||||
['/creation/match3d/result', 'match3d'],
|
||||
['/creation/square-hole/result', 'square-hole'],
|
||||
['/creation/puzzle/result', 'puzzle'],
|
||||
['/creation/visual-novel/result', 'visual-novel'],
|
||||
['/creation/bark-battle/result', 'bark-battle'],
|
||||
['/creation/baby-object-match/result', 'baby-object-match'],
|
||||
['/creation/jump-hop/result', 'jump-hop'],
|
||||
['/creation/wooden-fish/result', 'wooden-fish'],
|
||||
] as const;
|
||||
|
||||
cases.forEach(([pathname, kind]) => {
|
||||
expect(resolveCreationUrlRestoreTarget(pathname, state)).toMatchObject({
|
||||
kind,
|
||||
sessionId: 'session-1',
|
||||
profileId: 'profile-1',
|
||||
draftId: 'draft-1',
|
||||
workId: 'work-1',
|
||||
isGeneratingPath: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('normalizes creation url restore target values and generating paths', () => {
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/creation/jump-hop/generating', {
|
||||
sessionId: ' ',
|
||||
profileId: ' jump-profile-1 ',
|
||||
draftId: undefined,
|
||||
workId: null,
|
||||
}),
|
||||
).toEqual({
|
||||
kind: 'jump-hop',
|
||||
sessionId: null,
|
||||
profileId: 'jump-profile-1',
|
||||
draftId: null,
|
||||
workId: null,
|
||||
isGeneratingPath: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('derives big fish restore session from work id when needed', () => {
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/creation/big-fish/result', {
|
||||
workId: 'big-fish-work-river',
|
||||
}),
|
||||
).toEqual({
|
||||
kind: 'big-fish',
|
||||
sessionId: null,
|
||||
profileId: null,
|
||||
draftId: null,
|
||||
workId: 'big-fish-work-river',
|
||||
isGeneratingPath: false,
|
||||
bigFishSessionId: 'river',
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/creation/big-fish/result', {
|
||||
sessionId: 'big-fish-session-carp',
|
||||
workId: 'big-fish-work-river',
|
||||
}),
|
||||
).toMatchObject({
|
||||
kind: 'big-fish',
|
||||
bigFishSessionId: 'big-fish-session-carp',
|
||||
});
|
||||
});
|
||||
|
||||
test('keeps unsupported creation paths without a concrete restore target', () => {
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/creation/rpg/result', {
|
||||
sessionId: 'rpg-session-1',
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/creation/unknown/result', {
|
||||
sessionId: 'unknown-session-1',
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/creation/big-fishery/result', {
|
||||
sessionId: 'big-fish-session-1',
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
resolveCreationUrlRestoreTarget('/works/detail', {
|
||||
workId: 'work-1',
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('builds creation restore state for core session based plays', () => {
|
||||
expect(
|
||||
buildBigFishCreationUrlState({
|
||||
|
||||
@@ -60,6 +60,93 @@ export function buildPuzzleRuntimeUrlStateKey(state: PuzzleRuntimeUrlState) {
|
||||
].join('|');
|
||||
}
|
||||
|
||||
export type CreationUrlRestoreTargetKind =
|
||||
| 'big-fish'
|
||||
| 'match3d'
|
||||
| 'square-hole'
|
||||
| 'puzzle'
|
||||
| 'visual-novel'
|
||||
| 'bark-battle'
|
||||
| 'baby-object-match'
|
||||
| 'jump-hop'
|
||||
| 'wooden-fish';
|
||||
|
||||
type CreationUrlRestoreTargetBase = {
|
||||
kind: CreationUrlRestoreTargetKind;
|
||||
sessionId: string | null;
|
||||
profileId: string | null;
|
||||
draftId: string | null;
|
||||
workId: string | null;
|
||||
isGeneratingPath: boolean;
|
||||
};
|
||||
|
||||
export type CreationUrlRestoreTarget =
|
||||
| (CreationUrlRestoreTargetBase & {
|
||||
kind: 'big-fish';
|
||||
bigFishSessionId: string | null;
|
||||
})
|
||||
| (CreationUrlRestoreTargetBase & {
|
||||
kind: Exclude<CreationUrlRestoreTargetKind, 'big-fish'>;
|
||||
});
|
||||
|
||||
type NonBigFishCreationUrlRestoreTarget = Extract<
|
||||
CreationUrlRestoreTarget,
|
||||
{ kind: Exclude<CreationUrlRestoreTargetKind, 'big-fish'> }
|
||||
>;
|
||||
|
||||
const CREATION_URL_RESTORE_TARGET_ROUTES = [
|
||||
['/creation/big-fish', 'big-fish'],
|
||||
['/creation/match3d', 'match3d'],
|
||||
['/creation/square-hole', 'square-hole'],
|
||||
['/creation/puzzle', 'puzzle'],
|
||||
['/creation/visual-novel', 'visual-novel'],
|
||||
['/creation/bark-battle', 'bark-battle'],
|
||||
['/creation/baby-object-match', 'baby-object-match'],
|
||||
['/creation/jump-hop', 'jump-hop'],
|
||||
['/creation/wooden-fish', 'wooden-fish'],
|
||||
] as const satisfies readonly (readonly [
|
||||
string,
|
||||
CreationUrlRestoreTargetKind,
|
||||
])[];
|
||||
|
||||
export function resolveCreationUrlRestoreTarget(
|
||||
pathname: string | undefined,
|
||||
state: CreationUrlState,
|
||||
): CreationUrlRestoreTarget | null {
|
||||
const path = pathname?.trim() ?? '';
|
||||
const route = CREATION_URL_RESTORE_TARGET_ROUTES.find(([prefix]) =>
|
||||
path === prefix || path.startsWith(`${prefix}/`),
|
||||
);
|
||||
if (!route) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const kind = route[1];
|
||||
const sessionId = normalizeCreationUrlValue(state.sessionId);
|
||||
const profileId = normalizeCreationUrlValue(state.profileId);
|
||||
const draftId = normalizeCreationUrlValue(state.draftId);
|
||||
const workId = normalizeCreationUrlValue(state.workId);
|
||||
const base = {
|
||||
kind,
|
||||
sessionId,
|
||||
profileId,
|
||||
draftId,
|
||||
workId,
|
||||
isGeneratingPath: path.includes('/generating'),
|
||||
};
|
||||
|
||||
if (kind === 'big-fish') {
|
||||
return {
|
||||
...base,
|
||||
kind,
|
||||
bigFishSessionId:
|
||||
sessionId ?? workId?.replace(/^big-fish-work-/u, '') ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
return base as NonBigFishCreationUrlRestoreTarget;
|
||||
}
|
||||
|
||||
export type InitialCreationUrlRestoreDecision =
|
||||
| { type: 'skip' }
|
||||
| { type: 'mark-handled' }
|
||||
|
||||
Reference in New Issue
Block a user