Skip to content
This repository was archived by the owner on Dec 22, 2025. It is now read-only.

Commit 46d5c38

Browse files
committed
Add feature to add sweeping results to inventory
1 parent d7d8668 commit 46d5c38

File tree

11 files changed

+226
-10
lines changed

11 files changed

+226
-10
lines changed

components/Home.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,15 @@ const Home: NextPage = observer((props) => {
120120
equipmentsById={equipmentsById}
121121
equipmentsRequirementStore={store.equipmentsRequirementStore}
122122
normalMissionItemDropRatio={store.gameInfoStore.normalMissionItemDropRatio}
123-
onCloseInEfficacyDialog={handleCloseInEfficacyDialog}/>
123+
onCloseInEfficacyDialog={handleCloseInEfficacyDialog}
124+
piecesState={piecesState} />
124125
<IgnoredCampaigns
125126
solution={solution}
126127
allCampaigns={campaigns}
127128
allRequiredPieceIds={store.equipmentsRequirementStore.getAllRequiredPieceIds()}
128129
equipmentsById={equipmentsById}
129130
gameServer={store.gameInfoStore.gameServer}
130-
/>
131+
piecesState={piecesState} />
131132
</React.Fragment>;
132133
};
133134

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@use 'components/calculationInput/common/common-calculation-input-layout';
2+
3+
.container {
4+
display: grid;
5+
justify-content: center;
6+
grid-template-columns: repeat(auto-fill, 350px);
7+
grid-gap: 10px;
8+
}
9+
10+
.xs {
11+
grid-template-columns: repeat(auto-fill, 300px);
12+
}
13+
14+
.equipmentInputContainer {
15+
display: flex;
16+
margin: 10px;
17+
align-items: center;
18+
}
19+
20+
.equipmentCard {
21+
@include common-calculation-input-layout.items-list;
22+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import styles from './AddToInventoryDialog.module.scss';
2+
import {Button, Dialog, DialogActions, DialogContent, DialogTitle, useMediaQuery, useTheme} from '@mui/material';
3+
import React, {useEffect, useMemo} from 'react';
4+
import {useTranslation} from 'next-i18next';
5+
import {useForm} from 'react-hook-form';
6+
import {DropPieceIdWithProbAndCount, EquipmentsById} from 'components/calculationInput/PiecesCalculationCommonTypes';
7+
import {InventoryForm} from './InventoryUpdateDialog';
8+
import ObtainedPieceBox from './ObtainedPieceBox';
9+
import {EquipmentsByTierAndCategory} from '../EquipmentsInput';
10+
import {useStore} from 'stores/WizStore';
11+
import {PieceState} from './PiecesInventory';
12+
13+
const AddToInventoryDialog = ({
14+
open,
15+
drops,
16+
equipById,
17+
piecesState,
18+
onCancel,
19+
onUpdate,
20+
}: {
21+
open: boolean,
22+
drops: DropPieceIdWithProbAndCount[],
23+
equipById: EquipmentsById,
24+
piecesState: Map<string, PieceState>,
25+
onCancel: () => void,
26+
onUpdate: (formValues: InventoryForm) => void,
27+
}) => {
28+
const store = useStore();
29+
const {t} = useTranslation('home');
30+
const theme = useTheme();
31+
32+
const pieceIds = useMemo(() => drops.map((drop) => drop.id), [drops]);
33+
const pieces = useMemo(() => {
34+
return Array.from(piecesState.values())
35+
.filter((state) => pieceIds.includes(state.pieceId) && state.needCount > 0);
36+
}, [piecesState, pieceIds]);
37+
const defaultValues = useMemo(() => {
38+
return pieces.reduce<InventoryForm>((acc, piece) => {
39+
acc[piece.pieceId] = '';
40+
return acc;
41+
}, {});
42+
}, [pieces]);
43+
44+
const {
45+
control,
46+
formState: {isValid: isCountValid, errors: allErrors},
47+
getValues,
48+
reset,
49+
} = useForm<InventoryForm>({
50+
mode: 'onChange',
51+
defaultValues,
52+
});
53+
54+
useEffect(() => {
55+
open && reset();
56+
}, [open, reset]);
57+
58+
const handleCancelDialog = () => {
59+
onCancel();
60+
};
61+
62+
const handleUpdateInventory = () => {
63+
onUpdate(getValues());
64+
const inventory = Object.entries(getValues()).reduce<InventoryForm>((acc, [id, value]) => {
65+
const count = parseInt(value);
66+
const stock = piecesState.get(id)?.inStockCount;
67+
count && stock && (acc[id] = `${count + stock}`);
68+
return acc;
69+
}, {});
70+
store.equipmentsRequirementStore.updateInventory(inventory);
71+
};
72+
73+
const isFullScreen = useMediaQuery(theme.breakpoints.down('md'));
74+
const isXsOrSmallerScreen = useMediaQuery(theme.breakpoints.down('sm'));
75+
const hasManyPieces = () => pieces.length > 3;
76+
77+
return <Dialog open={open} keepMounted fullWidth
78+
fullScreen={hasManyPieces() && isFullScreen}
79+
maxWidth={hasManyPieces() && 'xl'}>
80+
<DialogTitle>獲得した設計図</DialogTitle>
81+
82+
<DialogContent className={styles.dialogContentContainer}>
83+
<div className={styles.filler}></div>
84+
<div className={`${styles.container} ${isXsOrSmallerScreen && styles.xs}`}>
85+
{pieces.map((piece) => {
86+
return <ObtainedPieceBox key={piece.pieceId} allErrors={allErrors}
87+
control={control}
88+
equipmentsById={equipById}
89+
piece={piece}/>;
90+
})}
91+
</div>
92+
<div className={styles.filler}></div>
93+
</DialogContent>
94+
95+
<DialogActions>
96+
<Button onClick={handleCancelDialog}>{t('cancelButton')}</Button>
97+
<Button onClick={handleUpdateInventory} disabled={!isCountValid}>
98+
追加
99+
</Button>
100+
</DialogActions>
101+
</Dialog>;
102+
};
103+
104+
export default AddToInventoryDialog;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@use 'components/calculationInput/common/common-calculation-input-layout';
2+
3+
.equipmentInputContainer{
4+
display: flex;
5+
margin: 10px;
6+
align-items: center;
7+
}
8+
9+
.equipmentCard{
10+
@include common-calculation-input-layout.items-list;
11+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import styles from './PieceUpdateBox.module.scss';
2+
import {Card, CardActionArea} from '@mui/material';
3+
import EquipmentCard from 'components/bui/card/EquipmentCard';
4+
import BuiBanner from 'components/bui/BuiBanner';
5+
import Box from '@mui/material/Box';
6+
import PositiveIntegerOnlyInput from 'components/calculationInput/common/PositiveIntegerOnlyInput';
7+
import React from 'react';
8+
import {EquipmentsById} from 'components/calculationInput/PiecesCalculationCommonTypes';
9+
import {PieceState} from 'components/calculationInput/equipments/inventory/PiecesInventory';
10+
import {Control} from 'react-hook-form/dist/types/form';
11+
import {InventoryForm} from 'components/calculationInput/equipments/inventory/InventoryUpdateDialog';
12+
import {useTranslation} from 'next-i18next';
13+
14+
const ObtainedPieceBox = function({
15+
equipmentsById,
16+
piece,
17+
control,
18+
allErrors,
19+
}: {
20+
equipmentsById: EquipmentsById,
21+
piece: PieceState,
22+
control: Control<InventoryForm>,
23+
allErrors: any,
24+
}) {
25+
const {t} = useTranslation('home');
26+
27+
const pieceIcon = equipmentsById.get(piece.pieceId)?.icon;
28+
if (!pieceIcon) return null;
29+
30+
return <div className={styles.equipmentInputContainer}>
31+
<Card elevation={1}>
32+
<CardActionArea disabled>
33+
<div className={styles.equipmentCard}>
34+
<EquipmentCard imageName={pieceIcon} bottomRightText={`x${piece.inStockCount}`} />
35+
<BuiBanner label={`${piece.needCount}`} width={'120%'} />
36+
</div>
37+
</CardActionArea>
38+
</Card>
39+
<Box sx={{mr: 2}}/>
40+
<PositiveIntegerOnlyInput name={piece.pieceId}
41+
min={0}
42+
control={control} showError={!!allErrors[piece.pieceId]}
43+
helperText={allErrors[piece.pieceId]?.message ?? ''}
44+
inputLabel={t('addPieceDialog.obtainedCount')} />
45+
</div>;
46+
};
47+
48+
export default ObtainedPieceBox;

components/calculationInput/listStagesResult/AllPotentialStages.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ const AllPotentialStages = ({
3636
campaignInfo={campaign} stageExplanationLabel={t('resultPiecesCountOnStage', {count: campaign?.targetRewardIds?.size})}
3737
allDrops={allDrops} equipmentsById={equipmentsById}
3838
shouldHighLightPiece={(id) => campaign.targetRewardIds.has(id)}
39-
hidePieceDropCount/>
39+
hidePieceDropCount
40+
piecesState={piecesState} />
4041
</Box>;
4142
})
4243
}

components/calculationResult/CampaignDropItemsList.module.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
color: #2d4665;
1515
}
1616

17-
.campaignNameAndTimes{
17+
.campaignHeader {
1818
align-items: center;
19+
margin-bottom: 1rem;
1920
}
2021

2122
.noSelection{

components/calculationResult/CampaignDropItemsList.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import styles from './CampaignDropItemsList.module.scss';
22
import {Card, CardContent, Typography} from '@mui/material';
3-
import React, {FunctionComponent} from 'react';
3+
import React, {FunctionComponent, useState} from 'react';
44
import {Campaign} from 'model/Campaign';
55
import {DropPieceIdWithProbAndCount, EquipmentsById} from 'components/calculationInput/PiecesCalculationCommonTypes';
66
import Grid from '@mui/material/Unstable_Grid2';
77
import BuiBanner from '../bui/BuiBanner';
88
import {useTranslation} from 'next-i18next';
99
import EquipmentCard from 'components/bui/card/EquipmentCard';
10+
import BuiButton from 'components/bui/BuiButton';
11+
import AddToInventoryDialog from '../calculationInput/equipments/inventory/AddToInventoryDialog';
12+
import {PieceState} from 'components/calculationInput/equipments/inventory/PiecesInventory';
1013

1114
type CampaignDropItemsListProps = {
1215
campaignInfo: Campaign,
@@ -16,6 +19,7 @@ type CampaignDropItemsListProps = {
1619
hidePieceDropCount?: boolean,
1720
containerCardVariation?: 'elevation' | 'outlined',
1821
shouldHighLightPiece?: (pieceId: string) => boolean,
22+
piecesState: Map<string, PieceState>,
1923
}
2024

2125
const CampaignDropItemsList :
@@ -27,14 +31,22 @@ const CampaignDropItemsList :
2731
shouldHighLightPiece,
2832
hidePieceDropCount= false,
2933
containerCardVariation = 'elevation',
34+
piecesState,
3035
}
3136
) => {
3237
const {t} = useTranslation('home');
38+
const [open, setOpen] = useState(false);
3339
return <Card variant={containerCardVariation} className={styles.cardWrapper}
3440
elevation={containerCardVariation == 'elevation' ? 2 : undefined}>
41+
<AddToInventoryDialog open={open}
42+
onUpdate={() => setOpen(false)}
43+
onCancel={() => setOpen(false)}
44+
equipById={equipmentsById}
45+
piecesState={piecesState}
46+
drops={allDrops} />
3547
<CardContent>
3648
<Grid container>
37-
<Grid xs={12} container className={styles.campaignNameAndTimes}>
49+
<Grid xs={12} container className={styles.campaignHeader}>
3850
<Typography variant={'h4'}>
3951
{`${campaignInfo.area}-${campaignInfo.stage}`}
4052
</Typography>
@@ -43,6 +55,12 @@ const CampaignDropItemsList :
4355
sx={{marginLeft: '0.8em'}}
4456
backgroundColor={'secondary'}
4557
width={'unset'}/>
58+
59+
<div style={{flexGrow: 1}}/>
60+
61+
<BuiButton color={'baButtonSecondary'} onClick={() => setOpen(true)}>
62+
{'結果を記入'}
63+
</BuiButton>
4664
</Grid>
4765

4866
<Grid xs={12} className={styles.noSelection}>

components/calculationResult/IgnoredCampaigns.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Box from '@mui/material/Box';
1414
import {useTranslation} from 'next-i18next';
1515
import {getRewardsByRegion} from 'common/gameDataHandlerUtil';
1616
import {GameServer} from 'model/Equipment';
17+
import {PieceState} from 'components/calculationInput/equipments/inventory/PiecesInventory';
1718

1819
type CampaignByRequiredPieceCount = {
1920
[key: number]: Campaign[],
@@ -79,7 +80,11 @@ const IgnoredCampaigns = ({
7980
allRequiredPieceIds,
8081
equipmentsById,
8182
gameServer,
82-
}: IgnoredCampaignsProps & {equipmentsById: EquipmentsById}) => {
83+
piecesState,
84+
}: IgnoredCampaignsProps & {
85+
equipmentsById: EquipmentsById,
86+
piecesState: Map<string, PieceState>,
87+
}) => {
8388
const {t} = useTranslation('home');
8489

8590
const skippedValidCampaigns = useMemo(
@@ -123,7 +128,8 @@ const IgnoredCampaigns = ({
123128
campaignInfo={campaign} stageExplanationLabel={t('stageIsSkipped')}
124129
allDrops={allDrops} equipmentsById={equipmentsById}
125130
containerCardVariation={'outlined'}
126-
hidePieceDropCount/>
131+
hidePieceDropCount
132+
piecesState={piecesState}/>
127133
</div>;
128134
})
129135
}

components/calculationResult/RecommendedCampaigns.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import InefficientRequirementWarning, {
1919
OnCloseInefficacyDialog,
2020
} from 'components/calculationInput/common/InefficientRequirementWarning';
2121
import {getRewardsByRegion} from 'common/gameDataHandlerUtil';
22+
import {PieceState} from 'components/calculationInput/equipments/inventory/PiecesInventory';
2223

2324

2425
const RecommendedCampaigns = ({
@@ -28,13 +29,15 @@ const RecommendedCampaigns = ({
2829
equipmentsRequirementStore,
2930
normalMissionItemDropRatio,
3031
onCloseInEfficacyDialog,
32+
piecesState,
3133
}: {
3234
solution: Solution<string>,
3335
campaignsById: CampaignsById,
3436
equipmentsById: EquipmentsById,
3537
equipmentsRequirementStore: IEquipmentsRequirementStore,
3638
normalMissionItemDropRatio: number,
3739
onCloseInEfficacyDialog: OnCloseInefficacyDialog,
40+
piecesState: Map<string, PieceState>,
3841
}) => {
3942
const {t} = useTranslation('home');
4043
const store = useStore();
@@ -94,7 +97,7 @@ const RecommendedCampaigns = ({
9497
return <div key={key} className={styles.selectedPiecesCard}>
9598
<CampaignDropItemsList
9699
campaignInfo={campaignInfo} stageExplanationLabel={t('stageSweepingTimes', {sweepingTimes})}
97-
allDrops={allDrops} equipmentsById={equipmentsById} />
100+
allDrops={allDrops} equipmentsById={equipmentsById} piecesState={piecesState} />
98101
</div>;
99102
})
100103
}

0 commit comments

Comments
 (0)