Skip to content
This repository has been archived by the owner on Mar 23, 2022. It is now read-only.

Commit

Permalink
Merge pull request #192 from RaenonX-DL/dev
Browse files Browse the repository at this point in the history
v2.9.2 Release
  • Loading branch information
RaenonX authored Jul 7, 2021
2 parents 84344b1 + 24f6300 commit 4cf75cb
Show file tree
Hide file tree
Showing 48 changed files with 660 additions and 234 deletions.
2 changes: 2 additions & 0 deletions doc/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ such as [quick reference](/doc/quickReference.md).

`[R]` means required; `[O]` means optional.

**These syntaxes must not nest with general markdown syntaxes.

### Text coloring

```
Expand Down
23 changes: 16 additions & 7 deletions pages/[lang]/thanks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,33 @@ const SpecialThanks = () => {
</a>
</h3>
<ul>
<li>
桜井みゆき&nbsp;
<Badge variant="primary">{t((t) => t.donation.tierSSS)}</Badge>&nbsp;
<Badge variant="orange">{t((t) => t.misc.omGroup)}</Badge>
</li>
<li>
Yu&nbsp;
<Badge variant="primary">{t((t) => t.donation.tierSSS)}</Badge>
</li>
<li>
Andy&nbsp;
<Badge variant="info">{t((t) => t.donation.tierS2)}</Badge>&nbsp;
<Badge variant="secondary">{t((t) => t.donation.tierS2)}</Badge>&nbsp;
<Badge variant="orange">{t((t) => t.misc.omMember)}</Badge>
</li>
<li>
Ellie&nbsp;
<Badge variant="info">{t((t) => t.donation.tierS2)}</Badge>&nbsp;
<Badge variant="secondary">{t((t) => t.donation.tierS2)}</Badge>&nbsp;
<Badge variant="orange">{t((t) => t.misc.omMember)}</Badge>
</li>
<li>
Piglet&nbsp;/&nbsp;ピグレット
<Badge variant="info">{t((t) => t.donation.tierS1)}</Badge>&nbsp;
<Badge variant="orange">{t((t) => t.misc.omGroup)}</Badge>
皮皮熊艹&nbsp;
<Badge variant="secondary">{t((t) => t.donation.tierS2)}</Badge>&nbsp;
<Badge variant="orange">{t((t) => t.misc.omMember)}</Badge>
</li>
<li>
皮皮熊艹&nbsp;
<Badge variant="info">{t((t) => t.donation.tierS2)}</Badge>&nbsp;
Piglet&nbsp;/&nbsp;ピグレット
<Badge variant="info">{t((t) => t.donation.tierS1)}</Badge>&nbsp;
<Badge variant="orange">{t((t) => t.misc.omMember)}</Badge>
</li>
<li>
Expand Down
Binary file removed public/favicon.ico
Binary file not shown.
Binary file modified public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/logo512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
"short_name": "龍絆攻略站 by OM",
"name": "龍絆攻略站 by OM",
"icons": [
{
"src": "favicon.ico",
"sizes": "256x256 128x128 64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
Expand Down
2 changes: 1 addition & 1 deletion src/api-def
31 changes: 0 additions & 31 deletions src/components/elements/gameData/skillAtk/hooks/preset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,35 +113,4 @@ describe('Input preset hook', () => {
await waitFor(() => expect(result.current.getPresetStatus.fetched).toBeTruthy());
expect(gaEvent).toHaveBeenCalledTimes(1);
});

it('does not have 2 preset IDs in the new link if created twice', async () => {
jest.spyOn(ApiRequestSender, 'getPresetAtkSkill').mockResolvedValue({
code: ApiResponseCode.SUCCESS,
success: true,
preset: {a: true},
});
jest.spyOn(ApiRequestSender, 'setPresetAtkSkill').mockResolvedValue({
code: ApiResponseCode.SUCCESS,
success: true,
presetId: 'preset2',
});
// @ts-ignore
delete window.location;
// @ts-ignore
window.location = {
href: `http://localhost/?${PRESET_QUERY_NAME}=preset`,
};

const {result} = renderReactHook(
() => useAtkSkillInput(fnOnNotLoggedIn),
{
hasSession: true,
routerOptions: {query: {[PRESET_QUERY_NAME]: 'preset'}},
},
);

result.current.makePreset();
await waitFor(() => expect(result.current.makePresetLink).not.toBeNull());
expect(new URL(result.current.makePresetLink || '').searchParams.getAll(PRESET_QUERY_NAME).length).toBe(1);
});
});
48 changes: 4 additions & 44 deletions src/components/elements/gameData/skillAtk/hooks/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {AppReactContext} from '../../../../../context/app/main';
import {useNextRouter} from '../../../../../utils/router';
import {ApiRequestSender} from '../../../../../utils/services/api/requestSender';
import {GoogleAnalytics} from '../../../../../utils/services/ga';
import {FetchStatus, FetchStatusSimple, isNotFetched} from '../../../common/fetch';
import {FetchStatusSimple, isNotFetched} from '../../../common/fetch';
import {InputPanelCommonProps} from '../../../input/types';
import {InputData} from '../in/types';
import {generateInputData, overwriteInputData} from '../in/utils/inputData';
Expand All @@ -14,14 +14,12 @@ export const PRESET_QUERY_NAME = 'preset';

type UseAtkSkillInputReturn = InputPanelCommonProps<InputData> & {
getPresetStatus: FetchStatusSimple,
makePresetLink: string | null,
makePreset: () => void,
}

// This input data is expect to change frequently.
// Therefore, it should not be used in expensive component, such as ATK skill output,
// because every change triggers a re-render.
export const useAtkSkillInput = (onNotLoggedIn?: () => void): UseAtkSkillInputReturn => {
export const useAtkSkillInput = (onNotLoggedIn: () => void): UseAtkSkillInputReturn => {
const {query} = useNextRouter();
const presetId = query[PRESET_QUERY_NAME];

Expand All @@ -32,38 +30,6 @@ export const useAtkSkillInput = (onNotLoggedIn?: () => void): UseAtkSkillInputRe
fetched: !presetId,
fetching: false,
});
const [makePresetStatus, setMakePresetStatus] = React.useState<FetchStatus<string | null>>({
fetched: false,
fetching: false,
data: null,
});

const onNotLoggedInInternal = () => {
if (onNotLoggedIn) {
onNotLoggedIn();
} else {
console.error('User not logged in, action prohibited.');
}
};

const makePreset = () => {
setMakePresetStatus({...makePresetStatus, fetched: false, fetching: true});
if (context?.session) {
ApiRequestSender.setPresetAtkSkill(context.session.user.id.toString(), inputData)
.then((response) => {
const link = new URL(window.location.href);
link.searchParams.set(PRESET_QUERY_NAME, response.presetId);

setMakePresetStatus({fetched: true, fetching: false, data: link.href});
})
.catch(() => {
setMakePresetStatus({fetched: true, fetching: false, data: null});
});
} else {
onNotLoggedInInternal();
setMakePresetStatus({...makePresetStatus, fetched: true, fetching: false});
}
};

if (isNotFetched(getPresetStatus)) {
if (context?.session) {
Expand All @@ -79,15 +45,9 @@ export const useAtkSkillInput = (onNotLoggedIn?: () => void): UseAtkSkillInputRe
GoogleAnalytics.presetLoaded('atkSkill');
} else {
setGetPresetStatus({...getPresetStatus, fetched: true, fetching: false});
onNotLoggedInInternal();
onNotLoggedIn();
}
}

return {
inputData,
setInputData,
getPresetStatus: getPresetStatus,
makePresetLink: makePresetStatus.data,
makePreset,
};
return {inputData, setInputData, getPresetStatus};
};
14 changes: 10 additions & 4 deletions src/components/elements/gameData/skillAtk/in/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {ResourceLoader} from '../../../../../utils/services/resources/loader';
import {useFetchState} from '../../../common/fetch';
import {CommonModal, ModalState} from '../../../common/modal';
import {useAtkSkillInput} from '../hooks/preset';
import {DisplayItemPicker} from './display';
import {Filter} from './filter';
import {DisplayItemPicker} from './limit';
import {InputParameters} from './params';
import {InputData} from './types';
import {validateInputData} from './utils/inputData';
Expand All @@ -30,9 +30,13 @@ export const AttackingSkillInput = ({isAllFetched, onSearchRequested}: InputProp
title: '',
message: '',
});
const {inputData, setInputData, getPresetStatus} = useAtkSkillInput();
const isSearchAllowed = isAllFetched && getPresetStatus.fetched;

const {inputData, setInputData, getPresetStatus} = useAtkSkillInput(() => {
setModalState({
title: 'Error',
show: true,
message: t((t) => t.game.skillAtk.error.presetMustLogin),
});
});
const {fetchStatus: conditionEnums, fetchFunction: fetchConditionEnums} = useFetchState<CategorizedConditionEnums>(
{afflictions: [], elements: []},
ResourceLoader.getEnumCategorizedConditions,
Expand All @@ -44,6 +48,8 @@ export const AttackingSkillInput = ({isAllFetched, onSearchRequested}: InputProp
'Failed to fetch the element enums.',
);

const isSearchAllowed = isAllFetched && getPresetStatus.fetched;

fetchConditionEnums();
fetchElemEnums();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ElementBonusData} from '../../../../../../api-def/resources';
import {UseFetchEnumsReturn} from '../../hooks/enums';
import {CalculatedSkillEntry} from '../../out/types';
import {calculateEntries, filterSkillEntries} from '../../out/utils';
import {calculateEntries, filterSkillEntries} from '../../out/utils/entries';
import {InputData} from '../types';


Expand Down
69 changes: 67 additions & 2 deletions src/components/elements/gameData/skillAtk/main.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,75 @@ describe('ATK skill lookup', () => {
userEvent.click(searchButton);

await waitForEntryProcessed();
screen.debug(undefined, 100000);
// Actual damage from Wedding Aoi
expect(await screen.findByText('417,497')).toBeInTheDocument();
});

it.todo('reset preset status on input changed then re-search');
it('makes correct input preset', async () => {
const fnMakePreset = jest.spyOn(ApiRequestSender, 'setPresetAtkSkill').mockResolvedValue({
code: ApiResponseCode.SUCCESS,
success: true,
presetId: 'abc',
});

renderReact(
() => <AttackingSkillLookup/>,
{hasSession: true},
);

const displayActualDamageBtn = await screen.findByText(translationEN.game.skillAtk.display.options.actualDamage);
userEvent.click(displayActualDamageBtn);
await waitFor(() => expect(displayActualDamageBtn.parentNode).toHaveClass('active'));

const searchButton = await screen.findByText(
translationEN.misc.search,
{selector: 'button:enabled'},
{timeout: 2000},
);
userEvent.click(searchButton);

await waitForEntryProcessed();

const shareButton = screen.getByText('', {selector: 'i.bi-share-fill'});
userEvent.click(shareButton);

expect(fnMakePreset.mock.calls[0][1].display.actualDamage).toBe(true);
});

it('reset preset status on input changed then re-search', async () => {
jest.spyOn(ApiRequestSender, 'setPresetAtkSkill').mockResolvedValue({
code: ApiResponseCode.SUCCESS,
success: true,
presetId: 'abc',
});

renderReact(
() => <AttackingSkillLookup/>,
{hasSession: true},
);

const displayActualDamageBtn = await screen.findByText(translationEN.game.skillAtk.display.options.actualDamage);
userEvent.click(displayActualDamageBtn);
await waitFor(() => expect(displayActualDamageBtn.parentNode).toHaveClass('active'));

const searchButton = await screen.findByText(
translationEN.misc.search,
{selector: 'button:enabled'},
{timeout: 2000},
);
userEvent.click(searchButton);

await waitForEntryProcessed();

const shareButton = screen.getByText('', {selector: 'i.bi-share-fill'});
userEvent.click(shareButton);
expect(shareButton).not.toBeInTheDocument();

userEvent.click(displayActualDamageBtn);
await waitFor(() => expect(displayActualDamageBtn.parentNode).not.toHaveClass('active'));

userEvent.click(searchButton);

expect(screen.getByText('', {selector: 'i.bi-share-fill'})).toBeInTheDocument();
});
});
40 changes: 24 additions & 16 deletions src/components/elements/gameData/skillAtk/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Row from 'react-bootstrap/Row';

import {scrollRefToTop} from '../../../../utils/scroll';
import {GoogleAnalytics} from '../../../../utils/services/ga';
import {CommonModal, ModalState} from '../../common/modal';
import {useFetchEnums} from './hooks/enums';
import {AttackingSkillInput} from './in/main';
import {InputData} from './in/types';
Expand All @@ -18,16 +17,17 @@ import {AttackingSkillPreset} from './preset/main';
import {AttackingSkillSorter} from './sorter/main';


type State = {
inputData: InputData,
calculatedEntries?: Array<CalculatedSkillEntry>,
}

export const AttackingSkillLookup = () => {
// Having this reduces state updates when changing input.
// Frequent update in this component is not ideal because rendering output is expensive.
const [inputDataForward, setInputDataForward] = React.useState(generateInputData());
const [modalState, setModalState] = React.useState<ModalState>({
show: false,
title: '',
message: '',
const [inputDataForward, setInputDataForward] = React.useState<State>({
inputData: generateInputData(),
});
const [calculatedEntries, setCalculatedEntries] = React.useState<Array<CalculatedSkillEntry> | undefined>();

const entryCol = React.useRef<HTMLDivElement>(null);

Expand All @@ -42,43 +42,51 @@ export const AttackingSkillLookup = () => {
} = useFetchEnums();

React.useEffect(() => {
if (!calculatedEntries) {
if (!inputDataForward.calculatedEntries) {
return;
}
scrollRefToTop(entryCol);
}, [calculatedEntries]);
}, [inputDataForward.calculatedEntries]);

return (
<>
<CommonModal modalState={modalState} setModalState={setModalState}/>
<Row>
<Col lg={4} className="rounded bg-black-32 p-3 mb-3">
<AttackingSkillInput
isAllFetched={isAllFetched}
onSearchRequested={(inputData: InputData) => {
GoogleAnalytics.damageCalc('search', inputData);

setCalculatedEntries(getCalculatedEntries(inputData, attackingSkillEntries, elementBonuses));
setInputDataForward(inputData);
setInputDataForward({
inputData,
calculatedEntries: getCalculatedEntries(inputData, attackingSkillEntries, elementBonuses),
});
}}
/>
</Col>
<Col ref={entryCol} lg={8} className="px-0 px-lg-3">
<Form.Row className="text-right mb-1">
<Col>
<AttackingSkillPreset isEnabled={!!calculatedEntries?.length}/>
<AttackingSkillPreset
inputData={inputDataForward.inputData}
isEnabled={!!inputDataForward.calculatedEntries?.length}
/>
</Col>
<Col xs="auto">
<AttackingSkillSorter
inputData={inputDataForward.inputData}
onOrderPicked={(newInputData) => {
setCalculatedEntries(getCalculatedEntries(newInputData, attackingSkillEntries, elementBonuses));
setInputDataForward({
inputData: newInputData,
calculatedEntries: getCalculatedEntries(newInputData, attackingSkillEntries, elementBonuses),
});
}}
/>
</Col>
</Form.Row>
<AttackingSkillOutput
displayConfig={inputDataForward.display}
calculatedEntries={calculatedEntries || []}
displayConfig={inputDataForward.inputData.display}
calculatedEntries={inputDataForward.calculatedEntries || []}
conditionEnumMap={conditionEnumMap}
skillIdentifierInfo={skillIdentifierInfo}
skillEnums={skillEnums}
Expand Down
Loading

0 comments on commit 4cf75cb

Please sign in to comment.