Skip to content

Commit

Permalink
Use a toggle for titan gear
Browse files Browse the repository at this point in the history
  • Loading branch information
apache1123 committed Jan 14, 2024
1 parent 7cdabcf commit e3810bb
Show file tree
Hide file tree
Showing 19 changed files with 121 additions and 82 deletions.
Binary file added public/changelog/titan-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 21 additions & 11 deletions src/components/GearTypeSelector/GearTypeSelector.stories.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';

import { gearTypesLookup } from '../../constants/gear-types';
import type { GearType } from '../../models/gear-type';
import { GearTypeSelector } from './GearTypeSelector';

Expand All @@ -12,25 +13,34 @@ const meta: Meta<typeof GearTypeSelector> = {
export default meta;
type Story = StoryObj<typeof GearTypeSelector>;

const selectedValue = {
gearType: {
id: 'Helmet',
displayName: 'Helmet',
} as GearType,
const selectedGearType = {
id: 'Helmet',
displayName: 'Helmet',
} as GearType;

const customOptions = gearTypesLookup.allIds.map((id) => ({
gearType: gearTypesLookup.byId[id],
isTitan: true,
};
}));

export const NoGearTypeSelected: Story = {};

export const SelectedValue: Story = {
export const SelectedGearType: Story = {
args: {
selectedGearType: selectedGearType,
},
};

export const Disabled: Story = {
args: {
selectedValue,
selectedGearType: selectedGearType,
disabled: true,
},
};

export const DisableGearTypeChange: Story = {
export const CustomOptions: Story = {
args: {
selectedValue,
disableGearTypeChange: true,
selectedGearType: selectedGearType,
options: customOptions,
},
};
61 changes: 19 additions & 42 deletions src/components/GearTypeSelector/GearTypeSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,30 @@
import { Autocomplete, Stack, TextField, Typography } from '@mui/material';
import { useEffect, useState } from 'react';

import { gearTypesLookup } from '../../constants/gear-types';
import type { GearType } from '../../models/gear-type';
import { GearTypeIcon } from '../GearTypeIcon/GearTypeIcon';

type Value = { gearType: GearType; isTitan: boolean };
type Option = { gearType: GearType; isTitan?: boolean };

export interface GearTypeSelectorProps {
selectedValue: Value | undefined;
onChange?(value: Value): void;
/** Disable gear type change (e.g. from a Helmet to an Eyepiece) if a gear type is already selected, but still allow the change to a Titan/non-Titan variation of that gear type */
disableGearTypeChange?: boolean;
selectedGearType: GearType | undefined;
options?: Option[];
onChange?(value: GearType): void;
disabled?: boolean;
}

const defaultOptions: Option[] = gearTypesLookup.allIds.map((id) => ({
gearType: gearTypesLookup.byId[id],
isTitan: false,
}));

export const GearTypeSelector = ({
selectedValue,
selectedGearType,
options: optionsFromProps,
onChange,
disableGearTypeChange,
disabled,
}: GearTypeSelectorProps) => {
const [options, setOptions] = useState<Value[]>([]);

// When there is a selected gear type and it cannot be changed e.g. in loadouts where the gear type is fixed, only allow two options - the non-titan gear of that type and a titan gear of that type.
// Other cases, show all gear types and their titan variants
useEffect(() => {
setOptions(
selectedValue && disableGearTypeChange
? gearTypesLookup.allIds
.filter((id) => selectedValue.gearType.id === id)
.reduce((acc, id) => {
const gearType = gearTypesLookup.byId[id];
return acc.concat([
{ gearType, isTitan: false },
{ gearType, isTitan: true },
]);
}, [] as Value[])
: gearTypesLookup.allIds
.map((id) => ({
gearType: gearTypesLookup.byId[id],
isTitan: false,
}))
.concat(
gearTypesLookup.allIds.map((id) => ({
gearType: gearTypesLookup.byId[id],
isTitan: true,
}))
)
);
}, [selectedValue, disableGearTypeChange]);
const options = optionsFromProps || defaultOptions;

return (
<Autocomplete
Expand All @@ -61,15 +37,16 @@ export const GearTypeSelector = ({
renderInput={(params) => (
<TextField {...params} label="Select gear type" variant="standard" />
)}
value={selectedValue}
onChange={(_, { gearType, isTitan }) => {
value={options?.find(
(option) => option.gearType.id === selectedGearType?.id
)}
onChange={(_, { gearType }) => {
if (onChange) {
onChange({ gearType, isTitan });
onChange(gearType);
}
}}
isOptionEqualToValue={(option, value) =>
option.gearType.id === value.gearType.id &&
option.isTitan === value.isTitan
option.gearType.id === value.gearType.id
}
renderOption={(props, { gearType, isTitan }) => (
<Stack direction="row" spacing={1} component="li" {...props}>
Expand Down
14 changes: 14 additions & 0 deletions src/constants/changelog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,18 @@ export const changelog: Changelog = [
date: new Date(Date.UTC(2024, 0, 10)),
title: 'Add Brevey',
},
{
semver: '3.7.0',
date: new Date(Date.UTC(2024, 0, 14)),
title:
'To make a piece of gear into a titan gear (and vice versa) - use the toggle instead of using the gear type selector',
description: (
<Image
src="/changelog/titan-3.png"
alt="titan-example-3"
width={645}
height={190}
/>
),
},
];
5 changes: 1 addition & 4 deletions src/features/GearOCRModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,7 @@ export const GearOCRModal = ({
gearState={tempGearState}
gearTypeSelector={
<GearTypeSelector
selectedValue={{
gearType: tempGearSnap.type,
isTitan: tempGearSnap.isAugmented,
}}
selectedGearType={tempGearSnap.type}
disabled
/>
}
Expand Down
34 changes: 32 additions & 2 deletions src/features/GearPiece.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
AccordionDetails,
AccordionSummary,
Box,
FormControlLabel,
Paper,
Stack,
Switch,
Typography,
} from '@mui/material';
import Grid from '@mui/material/Unstable_Grid2';
Expand All @@ -31,6 +33,7 @@ export interface GearPieceProps {
gearTypeSelector?: ReactNode;
/** External actions such as `Import gear` & `Save gear` that make no sense to be orchestrated by a `Gear` instance, but can be slotted here (for layout purposes) */
actions?: ReactNode;
showTitanToggle?: boolean;
showStatSummary?: CoreElementalType;
additionalAccordions?: ReactNode;
['data-testid']?: string;
Expand All @@ -41,6 +44,7 @@ export const GearPiece = ({
gearState,
gearTypeSelector,
actions,
showTitanToggle,
showStatSummary,
additionalAccordions,
'data-testid': dataTestId,
Expand Down Expand Up @@ -83,6 +87,22 @@ export const GearPiece = ({
})}
</Stack>
}
titanToggle={
showTitanToggle && (
<FormControlLabel
control={
<Switch
checked={gearSnap.isAugmented}
onChange={(_, checked) => {
gearState.isAugmented = checked;
}}
color="titan"
/>
}
label="Titan"
/>
)
}
actions={actions}
summary={
<>
Expand Down Expand Up @@ -176,6 +196,7 @@ function Layout({
typeSelector,
starsSelector,
randomStats,
titanToggle,
actions,
summary,
'data-testid': dataTestId,
Expand All @@ -184,6 +205,7 @@ function Layout({
typeSelector: ReactNode;
starsSelector: ReactNode;
randomStats: ReactNode;
titanToggle: ReactNode;
actions: ReactNode;
summary: ReactNode;
['data-testid']?: string;
Expand All @@ -199,8 +221,16 @@ function Layout({
<Box mt={1}>{starsSelector}</Box>
</Grid>
</Grid>
<Stack direction="row-reverse" spacing={1} mb={2}>
{actions}
<Stack
direction="row"
justifyContent={titanToggle ? 'space-between' : 'flex-end'}
spacing={2}
mb={2}
>
{titanToggle}
<Stack direction="row-reverse" spacing={1}>
{actions}
</Stack>
</Stack>
<Box mb={3}>{randomStats}</Box>
<Box>{summary}</Box>
Expand Down
18 changes: 11 additions & 7 deletions src/features/gear-comparer/LoadoutGear.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useSnapshot } from 'valtio';

import { GearTypeSelector } from '../../components/GearTypeSelector/GearTypeSelector';
import { gearTypesLookup } from '../../constants/gear-types';
import type { GearComparerState } from '../../states/gear-comparer';
import { gearComparerState } from '../../states/states';
import { GearOCRModal } from '../GearOCRModal';
Expand All @@ -10,24 +11,26 @@ export function LoadoutGear() {
const {
selectedLoadoutGear: gearSnap,
loadoutsState: {
selectedLoadout: { elementalType },
selectedLoadout: { elementalType, gearSet },
},
} = useSnapshot(gearComparerState) as GearComparerState;
const gearState = gearComparerState.selectedLoadoutGear;

const gearTypeSelectorOptions = gearTypesLookup.allIds.map((id) => ({
gearType: gearTypesLookup.byId[id],
isTitan: gearSet.getGearByType(id).isAugmented,
}));

return (
<GearPiece
gearSnap={gearSnap}
gearState={gearState}
gearTypeSelector={
<GearTypeSelector
selectedValue={{
gearType: gearSnap.type,
isTitan: gearSnap.isAugmented,
}}
onChange={({ gearType, isTitan }) => {
selectedGearType={gearSnap.type}
options={gearTypeSelectorOptions}
onChange={(gearType) => {
gearComparerState.selectedGearTypeId = gearType.id;
gearComparerState.selectedLoadoutGear.isAugmented = isTitan;
}}
/>
}
Expand All @@ -41,6 +44,7 @@ export function LoadoutGear() {
}}
/>
}
showTitanToggle
showStatSummary={elementalType}
data-testid={'loadout-gear'}
/>
Expand Down
17 changes: 11 additions & 6 deletions src/features/gear-comparer/ReplacementGear.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useSnapshot } from 'valtio';

import { GearTypeSelector } from '../../components/GearTypeSelector/GearTypeSelector';
import { gearTypesLookup } from '../../constants/gear-types';
import type { GearComparerState } from '../../states/gear-comparer';
import { gearComparerState } from '../../states/states';
import { GearOCRModal } from '../GearOCRModal';
Expand All @@ -11,25 +12,28 @@ import { SaveGearModal } from './SaveGearModal';
export function ReplacementGear() {
const {
replacementGear: gearSnap,
replacementGearGearSet,
loadoutsState: {
selectedLoadout: { elementalType },
},
} = useSnapshot(gearComparerState) as GearComparerState;
const gearState = gearComparerState.replacementGear;

const gearTypeSelectorOptions = gearTypesLookup.allIds.map((id) => ({
gearType: gearTypesLookup.byId[id],
isTitan: replacementGearGearSet.getGearByType(id).isAugmented,
}));

return (
<GearPiece
gearSnap={gearSnap}
gearState={gearState}
gearTypeSelector={
<GearTypeSelector
selectedValue={{
gearType: gearSnap.type,
isTitan: gearSnap.isAugmented,
}}
onChange={({ gearType, isTitan }) => {
selectedGearType={gearSnap.type}
options={gearTypeSelectorOptions}
onChange={(gearType) => {
gearComparerState.selectedGearTypeId = gearType.id;
gearComparerState.replacementGear.isAugmented = isTitan;
}}
/>
}
Expand All @@ -47,6 +51,7 @@ export function ReplacementGear() {
/>
</>
}
showTitanToggle
showStatSummary={elementalType}
additionalAccordions={<GearRollSimulator />}
data-testid={'replacement-gear'}
Expand Down
16 changes: 6 additions & 10 deletions src/features/loadouts/LoadoutGear.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,11 @@ export function LoadoutGear({ gearSnap, gearState }: LoadoutGearProps) {
gearState={gearState}
gearTypeSelector={
<GearTypeSelector
selectedValue={{
gearType: gearSnap.type,
isTitan: gearSnap.isAugmented,
}}
onChange={({ gearType, isTitan }) => {
if (gearType.id === gearState.type.id) {
gearState.isAugmented = isTitan;
}
}}
disableGearTypeChange
selectedGearType={gearSnap.type}
options={[
{ gearType: gearSnap.type, isTitan: gearSnap.isAugmented },
]}
disabled
/>
}
actions={
Expand All @@ -61,6 +56,7 @@ export function LoadoutGear({ gearSnap, gearState }: LoadoutGearProps) {
enforceGearType={gearSnap.type.id}
/>
}
showTitanToggle
showStatSummary={loadoutSnap.elementalType}
data-testid={gearTypeId}
/>
Expand Down
Loading

0 comments on commit e3810bb

Please sign in to comment.