Skip to content

Use a toggle for titan gear #102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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