refactor: 深化公开作品详情状态策略
This commit is contained in:
@@ -516,7 +516,9 @@ import {
|
||||
type RecommendRuntimeKind,
|
||||
} from './platformPublicGalleryFlow';
|
||||
import {
|
||||
resolveActivePlatformPublicWorkAuthorEntry,
|
||||
resolvePlatformPublicWorkActionMode,
|
||||
resolvePlatformPublicWorkDetailOpenDecision,
|
||||
resolvePlatformPublicWorkDetailOpenStrategy,
|
||||
} from './platformPublicWorkDetailFlow';
|
||||
import {
|
||||
@@ -10908,20 +10910,19 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
const openPublicWorkDetail = useCallback(
|
||||
(entry: PlatformPublicGalleryCard) => {
|
||||
if (!canExposePublicWork(entry)) {
|
||||
setSelectedPublicWorkDetail(null);
|
||||
setPublicWorkDetailError(EDUTAINMENT_HIDDEN_MESSAGE);
|
||||
setSelectionStage('platform');
|
||||
const decision = resolvePlatformPublicWorkDetailOpenDecision(entry);
|
||||
if (decision.type === 'blocked') {
|
||||
setSelectedPublicWorkDetail(decision.selectedDetail);
|
||||
setPublicWorkDetailError(decision.errorMessage);
|
||||
setSelectionStage(decision.selectionStage);
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedPublicWorkDetail(entry);
|
||||
setPublicWorkDetailError(null);
|
||||
setSelectionStage('work-detail');
|
||||
if (entry.publicWorkCode?.trim()) {
|
||||
pushAppHistoryPath(
|
||||
buildPublicWorkStagePath('work-detail', entry.publicWorkCode),
|
||||
);
|
||||
setSelectedPublicWorkDetail(decision.selectedDetail);
|
||||
setPublicWorkDetailError(decision.errorMessage);
|
||||
setSelectionStage(decision.selectionStage);
|
||||
if (decision.historyPath) {
|
||||
pushAppHistoryPath(decision.historyPath);
|
||||
}
|
||||
},
|
||||
[setSelectionStage],
|
||||
@@ -11118,14 +11119,11 @@ export function PlatformEntryFlowShellImpl({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const detailEntry =
|
||||
selectionStage === 'work-detail'
|
||||
? selectedPublicWorkDetail
|
||||
: selectionStage === 'detail' &&
|
||||
selectedDetailEntry &&
|
||||
selectedDetailEntry.visibility !== 'draft'
|
||||
? mapRpgGalleryCardToPublicWorkDetail(selectedDetailEntry)
|
||||
: null;
|
||||
const detailEntry = resolveActivePlatformPublicWorkAuthorEntry({
|
||||
selectionStage,
|
||||
selectedPublicWorkDetail,
|
||||
selectedRpgDetailEntry: selectedDetailEntry,
|
||||
});
|
||||
|
||||
if (!detailEntry) {
|
||||
clearSelectedPublicWorkAuthor();
|
||||
|
||||
@@ -10,7 +10,9 @@ import {
|
||||
getPlatformPublicWorkDetailKind,
|
||||
type PlatformPublicWorkDetailKind,
|
||||
type PlatformPublicWorkDetailOpenStrategy,
|
||||
resolveActivePlatformPublicWorkAuthorEntry,
|
||||
resolvePlatformPublicWorkActionMode,
|
||||
resolvePlatformPublicWorkDetailOpenDecision,
|
||||
resolvePlatformPublicWorkDetailOpenStrategy,
|
||||
} from './platformPublicWorkDetailFlow';
|
||||
|
||||
@@ -227,3 +229,91 @@ test('platform public work detail flow resolves edit mode only for owned works',
|
||||
expect(resolvePlatformPublicWorkActionMode(entry, 'user-2')).toBe('remix');
|
||||
expect(resolvePlatformPublicWorkActionMode(entry, null)).toBe('remix');
|
||||
});
|
||||
|
||||
test('platform public work detail flow resolves direct open decision', () => {
|
||||
const entry = buildTypedEntry('match3d', {
|
||||
publicWorkCode: ' M3D-001 ',
|
||||
});
|
||||
const buildWorkDetailPath = (publicWorkCode: string) =>
|
||||
`/works/detail?work=${publicWorkCode.trim()}`;
|
||||
|
||||
expect(
|
||||
resolvePlatformPublicWorkDetailOpenDecision(entry, {
|
||||
buildWorkDetailPath,
|
||||
}),
|
||||
).toEqual({
|
||||
type: 'open',
|
||||
selectedDetail: entry,
|
||||
errorMessage: null,
|
||||
selectionStage: 'work-detail',
|
||||
historyPath: '/works/detail?work=M3D-001',
|
||||
});
|
||||
expect(
|
||||
resolvePlatformPublicWorkDetailOpenDecision(
|
||||
buildTypedEntry('match3d', { publicWorkCode: ' ' }),
|
||||
{
|
||||
buildWorkDetailPath,
|
||||
},
|
||||
),
|
||||
).toEqual({
|
||||
type: 'open',
|
||||
selectedDetail: buildTypedEntry('match3d', { publicWorkCode: ' ' }),
|
||||
errorMessage: null,
|
||||
selectionStage: 'work-detail',
|
||||
historyPath: null,
|
||||
});
|
||||
expect(
|
||||
resolvePlatformPublicWorkDetailOpenDecision(entry, {
|
||||
canExposeEntry: () => false,
|
||||
hiddenMessage: '隐藏',
|
||||
buildWorkDetailPath,
|
||||
}),
|
||||
).toEqual({
|
||||
type: 'blocked',
|
||||
selectedDetail: null,
|
||||
errorMessage: '隐藏',
|
||||
selectionStage: 'platform',
|
||||
historyPath: null,
|
||||
});
|
||||
});
|
||||
|
||||
test('platform public work detail flow selects author lookup entry by stage', () => {
|
||||
const selectedPublicWorkDetail = buildTypedEntry('puzzle');
|
||||
const publishedRpgEntry = buildRpgEntry({
|
||||
visibility: 'published',
|
||||
profileId: 'published-rpg-profile',
|
||||
});
|
||||
const draftRpgEntry = buildRpgEntry({
|
||||
visibility: 'draft',
|
||||
profileId: 'draft-rpg-profile',
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveActivePlatformPublicWorkAuthorEntry({
|
||||
selectionStage: 'work-detail',
|
||||
selectedPublicWorkDetail,
|
||||
selectedRpgDetailEntry: publishedRpgEntry,
|
||||
}),
|
||||
).toBe(selectedPublicWorkDetail);
|
||||
expect(
|
||||
resolveActivePlatformPublicWorkAuthorEntry({
|
||||
selectionStage: 'detail',
|
||||
selectedPublicWorkDetail: null,
|
||||
selectedRpgDetailEntry: publishedRpgEntry,
|
||||
}),
|
||||
).toBe(publishedRpgEntry);
|
||||
expect(
|
||||
resolveActivePlatformPublicWorkAuthorEntry({
|
||||
selectionStage: 'detail',
|
||||
selectedPublicWorkDetail: null,
|
||||
selectedRpgDetailEntry: draftRpgEntry,
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
resolveActivePlatformPublicWorkAuthorEntry({
|
||||
selectionStage: 'platform',
|
||||
selectedPublicWorkDetail,
|
||||
selectedRpgDetailEntry: publishedRpgEntry,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
|
||||
import { buildPublicWorkStagePath } from '../../routing/appPageRoutes';
|
||||
import {
|
||||
isBarkBattleGalleryEntry,
|
||||
isBigFishGalleryEntry,
|
||||
@@ -11,6 +12,10 @@ import {
|
||||
isWoodenFishGalleryEntry,
|
||||
type PlatformPublicGalleryCard,
|
||||
} from '../rpg-entry/rpgEntryWorldPresentation';
|
||||
import {
|
||||
canExposePublicWork,
|
||||
EDUTAINMENT_HIDDEN_MESSAGE,
|
||||
} from './platformEdutainmentVisibility';
|
||||
|
||||
export type PlatformPublicWorkDetailKind =
|
||||
| 'bark-battle'
|
||||
@@ -55,6 +60,34 @@ export type PlatformPublicWorkDetailOpenStrategy =
|
||||
|
||||
export type PlatformPublicWorkActionMode = 'edit' | 'remix';
|
||||
|
||||
export type PlatformPublicWorkDetailOpenDecision =
|
||||
| {
|
||||
type: 'blocked';
|
||||
selectedDetail: null;
|
||||
errorMessage: string;
|
||||
selectionStage: 'platform';
|
||||
historyPath: null;
|
||||
}
|
||||
| {
|
||||
type: 'open';
|
||||
selectedDetail: PlatformPublicGalleryCard;
|
||||
errorMessage: null;
|
||||
selectionStage: 'work-detail';
|
||||
historyPath: string | null;
|
||||
};
|
||||
|
||||
export type PlatformPublicWorkDetailOpenDecisionDeps = {
|
||||
canExposeEntry?: (entry: PlatformPublicGalleryCard) => boolean;
|
||||
hiddenMessage?: string;
|
||||
buildWorkDetailPath?: (publicWorkCode: string) => string;
|
||||
};
|
||||
|
||||
export type ActivePlatformPublicWorkAuthorEntryInput = {
|
||||
selectionStage: string;
|
||||
selectedPublicWorkDetail: PlatformPublicGalleryCard | null;
|
||||
selectedRpgDetailEntry: CustomWorldGalleryCard | null;
|
||||
};
|
||||
|
||||
export function isRpgPublicWorkDetailEntry(
|
||||
entry: PlatformPublicGalleryCard,
|
||||
): entry is CustomWorldGalleryCard {
|
||||
@@ -188,3 +221,57 @@ export function resolvePlatformPublicWorkActionMode(
|
||||
? 'edit'
|
||||
: 'remix';
|
||||
}
|
||||
|
||||
export function resolvePlatformPublicWorkDetailOpenDecision(
|
||||
entry: PlatformPublicGalleryCard,
|
||||
deps: PlatformPublicWorkDetailOpenDecisionDeps = {},
|
||||
): PlatformPublicWorkDetailOpenDecision {
|
||||
const canExposeEntry = deps.canExposeEntry ?? canExposePublicWork;
|
||||
const hiddenMessage = deps.hiddenMessage ?? EDUTAINMENT_HIDDEN_MESSAGE;
|
||||
const buildWorkDetailPath =
|
||||
deps.buildWorkDetailPath ??
|
||||
((publicWorkCode: string) =>
|
||||
buildPublicWorkStagePath('work-detail', publicWorkCode));
|
||||
|
||||
if (!canExposeEntry(entry)) {
|
||||
return {
|
||||
type: 'blocked',
|
||||
selectedDetail: null,
|
||||
errorMessage: hiddenMessage,
|
||||
selectionStage: 'platform',
|
||||
historyPath: null,
|
||||
};
|
||||
}
|
||||
|
||||
const publicWorkCode = entry.publicWorkCode?.trim()
|
||||
? entry.publicWorkCode
|
||||
: null;
|
||||
|
||||
return {
|
||||
type: 'open',
|
||||
selectedDetail: entry,
|
||||
errorMessage: null,
|
||||
selectionStage: 'work-detail',
|
||||
historyPath: publicWorkCode ? buildWorkDetailPath(publicWorkCode) : null,
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveActivePlatformPublicWorkAuthorEntry({
|
||||
selectionStage,
|
||||
selectedPublicWorkDetail,
|
||||
selectedRpgDetailEntry,
|
||||
}: ActivePlatformPublicWorkAuthorEntryInput): PlatformPublicGalleryCard | null {
|
||||
if (selectionStage === 'work-detail') {
|
||||
return selectedPublicWorkDetail;
|
||||
}
|
||||
|
||||
if (
|
||||
selectionStage === 'detail' &&
|
||||
selectedRpgDetailEntry &&
|
||||
selectedRpgDetailEntry.visibility !== 'draft'
|
||||
) {
|
||||
return selectedRpgDetailEntry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user