Skip to content

Commit

Permalink
Rework earning quest edition
Browse files Browse the repository at this point in the history
  • Loading branch information
Palbolsky committed Jan 10, 2025
1 parent 8a7993b commit 5b00fa7
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 38 deletions.
8 changes: 7 additions & 1 deletion src/views/components/database/quest/QuestEarnings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ type QuestEarningsProps = {
export const QuestEarnings = ({ quest, dialogsRef, setEarningIndex }: QuestEarningsProps) => {
const { projectDataValues: quests } = useProjectQuests();
const { t } = useTranslation('database_quests');

const editEarning = (index: number) => {
dialogsRef.current?.openDialog('earning');
setEarningIndex(index);
};

return (
<DataBlockEditor
size="full"
Expand All @@ -25,7 +31,7 @@ export const QuestEarnings = ({ quest, dialogsRef, setEarningIndex }: QuestEarni
disabledDeletion={quest.earnings.length === 0}
disabledImport={Object.keys(quests).length <= 1}
>
<QuestEarningsTable quest={quest} setEarningIndex={setEarningIndex} />
<QuestEarningsTable quest={quest} editEarning={editEarning} />
</DataBlockEditor>
);
};
91 changes: 67 additions & 24 deletions src/views/components/database/quest/editors/QuestEarningEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,94 @@
import { useRefreshUI } from '@components/editor';
import { Editor } from '@components/editor/Editor';
import { InputContainer, InputWithTopLabelContainer, Label } from '@components/inputs';
import { SelectCustomSimple } from '@components/SelectCustom';
import { QUEST_EARNINGS, StudioQuest, StudioQuestEarningType } from '@modelEntities/quest';
import { createQuestEarning } from '@utils/entityCreation';
import { QUEST_EARNINGS, StudioQuestEarningType } from '@modelEntities/quest';
import { padStr } from '@utils/PadStr';
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { TFunction } from 'i18next';
import { QuestEarningItem, QuestEarningMoney, QuestEarningPokemon } from './earnings';
import { EditorHandlingClose, useEditorHandlingClose } from '@components/editor/useHandleCloseEditor';
import { useQuestPage } from '@src/hooks/usePage';
import { useUpdateQuest } from './useUpdateQuest';
import { useEarningQuest } from './useEarningQuest';
import { cloneEntity } from '@utils/cloneEntity';
import { assertUnreachable } from '@utils/assertUnreachable';
import { cleanNaNValue } from '@utils/cleanNaNValue';
import { Select } from '@ds/Select';
import React, { forwardRef, useMemo } from 'react';

const earningCategoryEntries = (t: TFunction<'database_quests'>) => QUEST_EARNINGS.map((earning) => ({ value: earning, label: t(earning) }));

type QuestEarningEditorProps = {
quest: StudioQuest;
earningIndex: number;
};

export const QuestEarningEditor = ({ quest, earningIndex }: QuestEarningEditorProps) => {
export const QuestEarningEditor = forwardRef<EditorHandlingClose, QuestEarningEditorProps>(({ earningIndex }, ref) => {
const { t } = useTranslation('database_quests');
const refreshUI = useRefreshUI();
const { quest } = useQuestPage();
const updateQuest = useUpdateQuest(quest);
const { earning, refs, updateEarning, isValid } = useEarningQuest(quest.earnings[earningIndex]);
const earningOptions = useMemo(() => earningCategoryEntries(t), [t]);
const earning = quest.earnings[earningIndex];
const earningMethodName = earning.earningMethodName;

const changeEarning = (value: StudioQuestEarningType) => {
if (value === quest.earnings[earningIndex].earningMethodName) return;
quest.earnings[earningIndex] = createQuestEarning(value);
if (value === earningMethodName) return;

updateEarning(value);
};

const canClose = () => isValid;

const onClose = () => {
if (!canClose()) return;

const newEarning = cloneEntity(earning);
const oldEarning = quest.earnings[earningIndex];
const isSameMethodName = newEarning.earningMethodName === oldEarning.earningMethodName;
switch (earningMethodName) {
case 'earning_money': {
if (!refs.inputRef.current) return;

const backupValue = isSameMethodName ? (oldEarning.earningArgs[0] as number) : 100;
newEarning.earningArgs[0] = cleanNaNValue(refs.inputRef.current.valueAsNumber, backupValue);
break;
}
case 'earning_item': {
if (!refs.entityRef.current || !refs.inputRef.current) return;

const backupValue = isSameMethodName ? (oldEarning.earningArgs[1] as number) : 1;
newEarning.earningArgs[0] = refs.entityRef.current;
newEarning.earningArgs[1] = cleanNaNValue(refs.inputRef.current.valueAsNumber, backupValue);
break;
}
case 'earning_pokemon':
case 'earning_egg': {
if (!refs.entityRef.current) return;

newEarning.earningArgs[0] = refs.entityRef.current;
break;
}
default:
assertUnreachable(earningMethodName);
}
const updatedEarnings = cloneEntity(quest.earnings);
updatedEarnings[earningIndex] = cloneEntity(newEarning);
updateQuest({ earnings: updatedEarnings });
};

useEditorHandlingClose(ref, onClose, canClose);

return (
<Editor type="edit" title={t('earning_title', { id: padStr(earningIndex + 1, 2) })}>
<InputContainer>
<InputWithTopLabelContainer>
<Label htmlFor="earning-type">{t('earning_type')}</Label>
<SelectCustomSimple
id={'earning-type-select'}
value={earning.earningMethodName}
options={earningOptions}
onChange={(value) => refreshUI(changeEarning(value as StudioQuestEarningType))}
noTooltip
/>
<Label htmlFor="earning-method-name">{t('earning_type')}</Label>
<Select name="earning-method-name" value={earning.earningMethodName} options={earningOptions} onChange={changeEarning} />
</InputWithTopLabelContainer>
{earning.earningMethodName === 'earning_money' && <QuestEarningMoney earning={earning} />}
{earning.earningMethodName === 'earning_item' && <QuestEarningItem earning={earning} />}
{earning.earningMethodName === 'earning_pokemon' && <QuestEarningPokemon earning={earning} />}
{earning.earningMethodName === 'earning_egg' && <QuestEarningPokemon earning={earning} />}
{earningMethodName === 'earning_money' && <QuestEarningMoney earning={earning} refs={refs} />}
{earningMethodName === 'earning_item' && <QuestEarningItem earning={earning} refs={refs} />}
{earningMethodName === 'earning_pokemon' && <QuestEarningPokemon earning={earning} refs={refs} />}
{earningMethodName === 'earning_egg' && <QuestEarningPokemon earning={earning} refs={refs} />}
</InputContainer>
</Editor>
);
};
});
QuestEarningEditor.displayName = 'QuestEarningEditor';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { DarkButton, PrimaryButton } from '@components/buttons';
import { Editor } from '@components/editor/Editor';
import { InputContainer, InputWithTopLabelContainer, Label } from '@components/inputs';
import { QUEST_EARNINGS, StudioQuestEarningType } from '@modelEntities/quest';
import { createQuestEarning } from '@utils/entityCreation';
import { useTranslation } from 'react-i18next';
import { TFunction } from 'i18next';
import { QuestEarningItem, QuestEarningMoney, QuestEarningPokemon } from './earnings';
Expand Down Expand Up @@ -35,15 +34,15 @@ export const QuestNewEarningEditor = forwardRef<EditorHandlingClose, QuestNewEar
const { quest } = useQuestPage();
const updateQuest = useUpdateQuest(quest);
const earningOptions = useMemo(() => earningCategoryEntries(t), [t]);
const { earning, refs, updateEarning, checkIsValid, isValid } = useEarningQuest(createQuestEarning('earning_money'));
const { earning, refs, updateEarning, checkIsValid, isValid } = useEarningQuest();
const earningMethodName = earning.earningMethodName;

useEditorHandlingClose(ref);

const changeEarning = (value: StudioQuestEarningType) => {
if (value === earning.earningMethodName) return;

updateEarning(createQuestEarning(value));
updateEarning(value);
};

const onClickNew = () => {
Expand Down Expand Up @@ -82,8 +81,8 @@ export const QuestNewEarningEditor = forwardRef<EditorHandlingClose, QuestNewEar
<Editor type="creation" title={t('earning')}>
<InputContainer>
<InputWithTopLabelContainer>
<Label htmlFor="earning-type">{t('earning_type')}</Label>
<Select id="earning-type" value={earning.earningMethodName} options={earningOptions} onChange={changeEarning} />
<Label htmlFor="earning-method-name">{t('earning_type')}</Label>
<Select name="earning-method-name" value={earning.earningMethodName} options={earningOptions} onChange={changeEarning} />
</InputWithTopLabelContainer>
{earningMethodName === 'earning_money' && <QuestEarningMoney earning={earning} refs={refs} checkIsValid={checkIsValid} />}
{earningMethodName === 'earning_item' && <QuestEarningItem earning={earning} refs={refs} checkIsValid={checkIsValid} />}
Expand Down
16 changes: 11 additions & 5 deletions src/views/components/database/quest/editors/useEarningQuest.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { DbSymbol } from '@modelEntities/dbSymbol';
import { StudioQuestEarning } from '@modelEntities/quest';
import { StudioQuestEarning, StudioQuestEarningType } from '@modelEntities/quest';
import { assertUnreachable } from '@utils/assertUnreachable';
import { cloneEntity } from '@utils/cloneEntity';
import { createQuestEarning } from '@utils/entityCreation';
import { useRef, useState } from 'react';

export const useEarningQuest = (initialEarning: StudioQuestEarning) => {
const [earning, setEarning] = useState(initialEarning);
const initializeEarning = (initialEarning?: StudioQuestEarning): StudioQuestEarning => {
return initialEarning ? cloneEntity(initialEarning) : createQuestEarning('earning_money');
};

export const useEarningQuest = (initialEarning?: StudioQuestEarning) => {
const [earning, setEarning] = useState(initializeEarning(initialEarning));
const [isValid, setIsValid] = useState<boolean>(true);
const entityRef = useRef<DbSymbol | undefined>();
const inputRef = useRef<HTMLInputElement>(null);
Expand All @@ -24,8 +30,8 @@ export const useEarningQuest = (initialEarning: StudioQuestEarning) => {
return setIsValid(true);
};

const updateEarning = (earning: StudioQuestEarning) => {
setEarning(earning);
const updateEarning = (earningMethod: StudioQuestEarningType) => {
setEarning(createQuestEarning(earningMethod));
setIsValid(true);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { useUpdateQuest } from '../editors/useUpdateQuest';

type QuestEarningsTableProps = {
quest: StudioQuest;
setEarningIndex: (index: number) => void;
editEarning: (index: number) => void;
};

export const QuestEarningsTable = ({ quest, setEarningIndex }: QuestEarningsTableProps) => {
export const QuestEarningsTable = ({ quest, editEarning }: QuestEarningsTableProps) => {
const updateQuest = useUpdateQuest(quest);
const { t } = useTranslation('database_quests');

Expand All @@ -27,7 +27,7 @@ export const QuestEarningsTable = ({ quest, setEarningIndex }: QuestEarningsTabl
<RenderEarning
key={`earning-${index}`}
earning={earning}
onClickEdit={() => setEarningIndex(index)}
onClickEdit={() => editEarning(index)}
onClickDelete={() => {
const newEarnings = cloneEntity(quest.earnings);
newEarnings.splice(index, 1);
Expand Down

0 comments on commit 5b00fa7

Please sign in to comment.