2025-05-28 15:36:51 -07:00

382 lines
11 KiB
TypeScript

import { uniqueId } from "lodash";
import { call, put, select, takeEvery } from "redux-saga/effects";
import {
rulesEngineSelectors,
characterActionTypes,
characterActions,
syncTransactionActions,
syncTransactionSelectors,
ApiAdapterUtils,
ApiRequests,
UnpackMakeApiResponseData,
ruleDataActions,
SagaHelpers,
characterEnvSelectors,
Constants,
RaceUtils,
} from "@dndbeyond/character-rules-engine/es";
import { BuilderMethod, RouteKey } from "~/subApps/builder/constants";
import { appEnvActions } from "../../Shared/actions";
import { appEnvSelectors } from "../../Shared/selectors";
import appConfig from "../../config";
import {
builderActions,
builderActionTypes,
BuilderAction,
BuilderMethodSetAction,
QuickBuildRequestAction,
RandomBuildRequestAction,
StepBuildRequestAction,
SuggestedNamesRequestAction,
} from "../actions";
import * as navConfig from "../config/navigation";
import { getRouteDefPath } from "../config/navigation";
import { builderSelectors } from "../selectors";
import { NavigationUtils } from "../utils";
const syncActions = [
builderActionTypes.CHARACTER_LOAD_REQUEST,
builderActionTypes.QUICK_BUILD_REQUEST,
builderActionTypes.RANDOM_BUILD_REQUEST,
builderActionTypes.STEP_BUILD_REQUEST,
builderActionTypes.BUILDER_METHOD_SET,
builderActionTypes.SUGGESTED_NAMES_REQUEST,
];
export default function* saga() {
yield takeEvery(syncActions, syncFilter);
yield takeEvery(
Object.keys(characterActionTypes).map((key) => characterActionTypes[key]),
characterTypesFilter
);
yield takeEvery(
Object.keys(builderActionTypes).map((key) => builderActionTypes[key]),
filter
);
}
function* characterTypesFilter(action: any) {
switch (action.type) {
case characterActionTypes.RACE_CHOOSE_POST_ACTION: {
// yield put(push(getRouteDefPath(RouteKey.RACE_MANAGE)));
const characterId = yield select((state: any) =>
rulesEngineSelectors.getId(state)
);
const navigate = yield select(
(state: any) => state.routeControls.navigate
);
navigate(
getRouteDefPath(RouteKey.RACE_MANAGE).replace(
":characterId",
characterId
)
);
break;
}
case characterActionTypes.CLASS_ADD_POST_ACTION: {
// yield put(push(getRouteDefPath(RouteKey.CLASS_MANAGE)));
const characterId = yield select((state: any) =>
rulesEngineSelectors.getId(state)
);
const navigate = yield select(
(state: any) => state.routeControls.navigate
);
navigate(
getRouteDefPath(RouteKey.CLASS_MANAGE).replace(
":characterId",
characterId
)
);
break;
}
case characterActionTypes.CLASS_REMOVE_POST_ACTION: {
let classes = yield select(rulesEngineSelectors.getClasses);
if (classes.length === 0) {
// yield put(push(getRouteDefPath(RouteKey.CLASS_CHOOSE)));
const characterId = yield select((state: any) =>
rulesEngineSelectors.getId(state)
);
const navigate = yield select(
(state: any) => state.routeControls.navigate
);
navigate(
getRouteDefPath(RouteKey.CLASS_CHOOSE).replace(
":characterId",
characterId
)
);
}
break;
}
case characterActionTypes.CHARACTER_LOAD_POST_ACTION: {
yield put(builderActions.characterLoadingSetCommit(false));
yield put(builderActions.characterLoadedSetCommit(true));
const builderMethod: ReturnType<
typeof builderSelectors.getBuilderMethod
> = yield select(builderSelectors.getBuilderMethod);
const context: ReturnType<typeof characterEnvSelectors.getContext> =
yield select(characterEnvSelectors.getContext);
if (
builderMethod === BuilderMethod.STEP_BY_STEP &&
context === Constants.AppContextTypeEnum.BUILDER
) {
const configuration: ReturnType<
typeof rulesEngineSelectors.getCharacterConfiguration
> = yield select(rulesEngineSelectors.getCharacterConfiguration);
const stepByStepInitialPage = configuration.showHelpText
? RouteKey.HOME_HELP
: RouteKey.HOME_BASIC_INFO;
const isCurrentRouteInRoutePathing = yield select(
NavigationUtils.checkIsCurrentRouteInRoutePathing
);
// TODO routes this needs fixed
// yield put(push(navConfig.getRouteDefPath(stepByStepInitialPage)));
if (!isCurrentRouteInRoutePathing) {
const navigate = yield select(
(state: any) => state.routeControls.navigate
);
navigate(
navConfig
.getRouteDefPath(stepByStepInitialPage)
.replace(":characterId", action.payload.characterId)
);
}
// window.location = navConfig.getRouteDefPath(stepByStepInitialPage).replace(':characterId', action.payload.characterId);
// }
}
break;
}
}
}
function* filter(action: BuilderAction) {
switch (action.type) {
case builderActionTypes.SHOW_HELP_TEXT_SET:
yield call(ApiRequests.putCharacterHelpText, action.payload);
yield put(characterActions.showHelpTextSet(action.payload.showHelpText));
if (action.payload.showHelpText) {
const currentSectionHelpRoutePath = yield select(
NavigationUtils.getCurrentSectionHelpRoutePath
);
if (currentSectionHelpRoutePath !== null) {
const characterId = yield select((state: any) =>
rulesEngineSelectors.getId(state)
);
const navigate = yield select(
(state: any) => state.routeControls.navigate
);
navigate(
currentSectionHelpRoutePath.replace(":characterId", characterId)
);
// yield put(push(currentSectionHelpRoutePath));
}
} else {
const availablePathRedirect = yield select(
NavigationUtils.getAvailablePathRedirect
);
if (availablePathRedirect !== null) {
const characterId = yield select((state: any) =>
rulesEngineSelectors.getId(state)
);
const navigate = yield select(
(state: any) => state.routeControls.navigate
);
navigate(availablePathRedirect.replace(":characterId", characterId));
// yield put(push(availablePathRedirect));
}
}
break;
}
}
function* syncFilter(action: BuilderAction) {
const isSyncTransactionActive = yield select(
syncTransactionSelectors.getActive
);
let transactionInitiatorId;
if (!isSyncTransactionActive) {
transactionInitiatorId = uniqueId();
yield put(syncTransactionActions.activate(transactionInitiatorId));
}
switch (action.type) {
case builderActionTypes.QUICK_BUILD_REQUEST:
yield call(handleQuickBuildRequest, action);
break;
case builderActionTypes.RANDOM_BUILD_REQUEST:
yield call(handleRandomBuildRequest, action);
break;
case builderActionTypes.STEP_BUILD_REQUEST:
yield call(handleStepBuildRequest, action);
break;
case builderActionTypes.CHARACTER_LOAD_REQUEST:
yield call(handleLoadCharacterRequest, action);
break;
case builderActionTypes.BUILDER_METHOD_SET:
yield call(handleBuilderMethodSet, action);
break;
case builderActionTypes.SUGGESTED_NAMES_REQUEST:
yield call(handleSuggestedNamesRequest, action);
break;
}
switch (action.type) {
case builderActionTypes.QUICK_BUILD_REQUEST:
case builderActionTypes.RANDOM_BUILD_REQUEST:
break;
default:
let syncTransactionInitiator = yield select(
syncTransactionSelectors.getInitiator
);
if (syncTransactionInitiator === transactionInitiatorId) {
yield put(syncTransactionActions.deactivate());
}
break;
}
}
function* handleBuilderMethodSet(action: BuilderMethodSetAction) {
const response = yield call(ApiRequests.getCharacterRuleData, {
params: { v: appConfig.version },
});
const data: UnpackMakeApiResponseData<
typeof ApiRequests.getCharacterRuleData
> | null = ApiAdapterUtils.getResponseData(response);
if (data !== null) {
yield put(ruleDataActions.dataSet(data));
}
yield put(builderActions.builderMethodSetCommit(action.payload));
}
function* handleQuickBuildRequest(action: QuickBuildRequestAction) {
const characterId: UnpackMakeApiResponseData<
typeof ApiRequests.postCharacterBuilderQuickBuild
> = yield call(
SagaHelpers.getApiRequestData,
ApiRequests.postCharacterBuilderQuickBuild,
action.payload
);
// if (data.success) {
const characterUrl = NavigationUtils.getCharacterBuilderUrl(characterId);
const initialPath = navConfig.getRouteDefPath(RouteKey.WHATS_NEXT);
// todo just a soft navigation
window.location = `${characterUrl}${initialPath}` as any;
// } else {
//TODO do something with error
// }
}
function* handleRandomBuildRequest(action: RandomBuildRequestAction) {
const characterId: UnpackMakeApiResponseData<
typeof ApiRequests.postCharacterBuilderRandomBuild
> = yield call(
SagaHelpers.getApiRequestData,
ApiRequests.postCharacterBuilderRandomBuild,
action.payload
);
// if (data.success) {
const characterUrl = NavigationUtils.getCharacterBuilderUrl(characterId);
const initialPath = navConfig.getRouteDefPath(RouteKey.WHATS_NEXT);
window.location = `${characterUrl}#${initialPath}` as any;
// } else {
//TODO do something with error
// }
}
function* handleStepBuildRequest(action: StepBuildRequestAction) {
yield put(builderActions.characterLoadingSetCommit(true));
//TODO fix with common refactor for populating character
const characterId: UnpackMakeApiResponseData<
typeof ApiRequests.postCharacterBuilderStandardBuild
> = yield call(
SagaHelpers.getApiRequestData,
ApiRequests.postCharacterBuilderStandardBuild,
action.payload
);
yield put(appEnvActions.dataSet({ characterId }));
yield put(
builderActions.builderMethodSetCommit({
method: BuilderMethod.STEP_BY_STEP,
})
);
yield select(appEnvSelectors.getUsername);
/* eslint-disable-next-line */
yield put(
characterActions.characterLoad(characterId, { v: appConfig.version })
);
}
function* handleLoadCharacterRequest(action: BuilderAction) {
yield put(builderActions.characterLoadingSetCommit(true));
const characterId: ReturnType<typeof appEnvSelectors.getCharacterId> =
yield select(appEnvSelectors.getCharacterId);
if (characterId === null) {
// TODO do something
return;
}
try {
yield put(
builderActions.builderMethodSetCommit({
method: BuilderMethod.STEP_BY_STEP,
})
);
yield put(
characterActions.characterLoad(characterId, { v: appConfig.version })
);
} catch (e) {
// TODO handle failure in builder init process
}
}
/**
*
* @param action
*/
export function* handleSuggestedNamesRequest(
action: SuggestedNamesRequestAction
) {
const species: ReturnType<typeof rulesEngineSelectors.getRace> = yield select(
rulesEngineSelectors.getRace
);
let reqParams: ApiRequests.GetSuggestedNames_RequestData = {
count: 5,
};
if (species !== null) {
reqParams = {
...reqParams,
raceDefinitionKey: RaceUtils.getDefinitionKey(species),
};
}
const names: UnpackMakeApiResponseData<typeof ApiRequests.getSuggestedNames> =
yield call(SagaHelpers.getApiRequestData, ApiRequests.getSuggestedNames, {
params: reqParams,
});
yield put(builderActions.suggestedNamesSet(names));
}