Skip to content

Commit

Permalink
Merge pull request #47 from dragoni7/exotic-class-item
Browse files Browse the repository at this point in the history
Exotic class item
  • Loading branch information
dragoni7 authored Sep 1, 2024
2 parents 7be3aa7 + a78a587 commit 36d2bce
Show file tree
Hide file tree
Showing 19 changed files with 319 additions and 119 deletions.
28 changes: 17 additions & 11 deletions src/app/routes/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useEffect, useState, useMemo } from 'react';
import { styled } from '@mui/system';
import { useDispatch, useSelector } from 'react-redux';
import { AppDispatch, RootState } from '../../store';
import { updateSelectedExoticItemHash, updateSelectedValues } from '../../store/DashboardReducer';
import { generatePermutations } from '../../features/armor-optimization/generate-permutations';
import { filterPermutations } from '../../features/armor-optimization/filter-permutations';
import SingleDiamondButton from '../../components/SingleDiamondButton';
Expand All @@ -11,10 +10,10 @@ import { getDestinyMembershipId } from '../../features/membership/bungie-account
import { updateMembership } from '../../store/MembershipReducer';
import { getProfileData } from '../../features/profile/destiny-profile';
import { updateProfileData } from '../../store/ProfileReducer';
import { DestinyArmor, Character, FilteredPermutation } from '../../types/d2l-types';
import { Character } from '../../types/d2l-types';
import StatsTable from '../../features/armor-optimization/StatsTable';
import HeaderComponent from '../../components/HeaderComponent';
import ExoticSearch from '../../components/ExoticSearch';
import ExoticSelector from '../../features/armor-optimization/ExoticSelector';
import greyBackground from '../../assets/grey.png';
import { db } from '../../store/db';
import { resetLoadout, updateLoadoutCharacter, updateSubclass } from '../../store/LoadoutReducer';
Expand Down Expand Up @@ -106,11 +105,11 @@ export const Dashboard: React.FC = () => {
const dispatch = useDispatch<AppDispatch>();
const membership = useSelector((state: RootState) => state.destinyMembership.membership);
const characters = useSelector((state: RootState) => state.profile.profileData.characters);
const { selectedValues, selectedExoticItemHash } = useSelector(
const { selectedValues, selectedExotic, selectedExoticClassCombo } = useSelector(
(state: RootState) => state.dashboard
);

const [selectedCharacter, setSelectedCharacter] = useState<Character | null>(null);
const [selectedCharacter, setSelectedCharacter] = useState<Character | undefined>(undefined);
const [isLoading, setIsLoading] = useState(false);
const [subclasses, setSubclasses] = useState<ManifestSubclass[]>([]);
const [selectedSubclass, setSelectedSubclass] = useState<ManifestSubclass | null>(null);
Expand All @@ -135,7 +134,7 @@ export const Dashboard: React.FC = () => {
};

updateProfile().catch(console.error);
}, [dispatch]);
}, []);

useEffect(() => {
if (selectedCharacter) {
Expand All @@ -155,11 +154,18 @@ export const Dashboard: React.FC = () => {
}, [selectedCharacter, dispatch]);

const permutations = useMemo(() => {
if (selectedCharacter && selectedExoticItemHash !== undefined) {
return generatePermutations(selectedCharacter.armor, selectedExoticItemHash);
if (selectedCharacter && selectedExotic !== undefined) {
if (selectedExoticClassCombo)
return generatePermutations(
selectedCharacter.armor,
selectedExotic,
selectedExoticClassCombo
);

return generatePermutations(selectedCharacter.armor, selectedExotic);
}
return null;
}, [selectedCharacter, selectedExoticItemHash]);
}, [selectedCharacter, selectedExotic, selectedExoticClassCombo]);

const filteredPermutations = useMemo(() => {
if (permutations && selectedValues) {
Expand Down Expand Up @@ -248,9 +254,9 @@ export const Dashboard: React.FC = () => {
)}
<Container>
<NewComponentWrapper>
<ExoticSearch
<ExoticSelector
selectedCharacter={selectedCharacter}
selectedExoticItemHash={selectedExoticItemHash}
selectedExoticItemHash={selectedExotic.itemHash}
/>
</NewComponentWrapper>
<BottomPane>
Expand Down
2 changes: 1 addition & 1 deletion src/components/LoadoutCustomization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import './LoadoutCustomization.css';
import { Button, Box, Container, Grid } from '@mui/material';
import { styled } from '@mui/material/styles';
import ModCustomization from '../features/armor/components/ModCustomization';
import ModCustomization from '../features/armor-mods/components/ModCustomization';
import EquipLoadout from '../features/loadouts/components/EquipLoadout';
import AbilitiesModification from '../features/subclass/AbilitiesModification';
import { ManifestSubclass } from '../types/manifest-types';
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import React, { useEffect, useState } from 'react';
import { styled } from '@mui/material/styles';
import { Autocomplete, TextField, Popper } from '@mui/material';
import { db } from '../store/db';
import { Character } from '../types/d2l-types';
import { updateSelectedExoticItemHash } from '../store/DashboardReducer';
import { db } from '../../store/db';
import { armor, Character, ExoticClassCombo } from '../../types/d2l-types';
import {
updateSelectedExoticClassCombo,
updateSelectedExoticItemHash,
} from '../../store/DashboardReducer';
import { useDispatch } from 'react-redux';
import { ManifestExoticArmor } from '../../types/manifest-types';
import { ARMOR } from '../../lib/bungie_api/constants';

const NewComponentContainer = styled('div')({
backgroundColor: 'transparent',
Expand All @@ -19,8 +24,8 @@ const NewComponentContainer = styled('div')({

const ExoticIcon = styled('img')<{ isOwned: boolean; isSelected: boolean }>(
({ isOwned, isSelected }) => ({
width: isSelected ? '100px' : '50px',
height: isSelected ? '100px' : '50px',
width: isSelected ? '91px' : '50px',
height: isSelected ? '91px' : '50px',
marginRight: '10px',
filter: isOwned ? 'none' : 'grayscale(100%)',
border: isSelected ? '5px solid transparent' : 'none',
Expand Down Expand Up @@ -89,41 +94,30 @@ const StyledPopper = styled(Popper)({
},
});

type ExoticViewModel = {
itemHash: string;
name: string;
icon: string;
isOwned: boolean;
};

interface ExoticSearchProps {
selectedCharacter: Character | null;
selectedExoticItemHash: string | null;
interface ExoticSelectorProps {
selectedCharacter: Character | undefined;
selectedExoticItemHash: number | null;
}

const ExoticSearch: React.FC<ExoticSearchProps> = ({
const ExoticSelector: React.FC<ExoticSelectorProps> = ({
selectedCharacter,
selectedExoticItemHash,
}) => {
const dispatch = useDispatch();
const [exotics, setExotics] = useState<ExoticViewModel[]>([]);
const [selectedExotic, setSelectedExotic] = useState<ExoticViewModel | null>(null);
const [exotics, setExotics] = useState<ManifestExoticArmor[]>([]);
const [comboInput, setComboInput] = useState('');
const [selectedExotic, setSelectedExotic] = useState<ManifestExoticArmor | null>(null);
const [selectedCombo, setSelectedCombo] = useState<ExoticClassCombo | null>(null);
const [inputValue, setInputValue] = React.useState('');
const exoticClassCombos = selectedCharacter?.exoticClassCombos;

const fetchExoticData = async () => {
if (selectedCharacter) {
const data = await db.manifestExoticArmorCollection
.where('class')
.equalsIgnoreCase(selectedCharacter.class)
.toArray();
setExotics(
data.map((item) => ({
itemHash: item.itemHash.toString(),
name: item.name,
icon: item.icon,
isOwned: item.isOwned,
}))
);
setExotics(data);
}
};

Expand All @@ -145,14 +139,26 @@ const ExoticSearch: React.FC<ExoticSearchProps> = ({
setInputValue('');
}, [selectedCharacter]);

const handleExoticSelect = (newValue: ExoticViewModel | null) => {
const handleExoticSelect = (newValue: ManifestExoticArmor | null) => {
setSelectedExotic(newValue);
dispatch(updateSelectedExoticItemHash(newValue ? newValue.itemHash : null));

dispatch(
updateSelectedExoticItemHash({
itemHash: newValue ? newValue.itemHash : null,
slot: newValue?.slot as armor,
})
);
};

function handleExoticClassComboSelect(newValue: ExoticClassCombo | null) {
setSelectedCombo(newValue);
dispatch(updateSelectedExoticClassCombo(newValue));
}

const handleClearSelection = () => {
setSelectedExotic(null);
dispatch(updateSelectedExoticItemHash(null));
setSelectedCombo(null);
dispatch(updateSelectedExoticItemHash({ itemHash: null, slot: null }));
};

return (
Expand All @@ -163,14 +169,16 @@ const ExoticSearch: React.FC<ExoticSearchProps> = ({
<Autocomplete
disablePortal
value={selectedExotic}
onChange={(event, newValue) => handleExoticSelect(newValue as ExoticViewModel | null)}
onChange={(event, newValue) =>
handleExoticSelect(newValue as ManifestExoticArmor | null)
}
inputValue={inputValue}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
id="exotics"
options={exotics}
getOptionLabel={(option: ExoticViewModel) => option.name}
getOptionLabel={(option: ManifestExoticArmor) => option.name}
sx={{ width: 300 }}
PopperComponent={StyledPopper}
renderOption={(props, option) => {
Expand Down Expand Up @@ -231,6 +239,69 @@ const ExoticSearch: React.FC<ExoticSearchProps> = ({
isOwned={selectedExotic.isOwned}
isSelected={true}
/>
{selectedExotic.slot === ARMOR.CLASS_ARMOR && (
<Autocomplete
id="exotic_combos"
disablePortal
value={selectedCombo}
onChange={(event, newValue) =>
handleExoticClassComboSelect(newValue as ExoticClassCombo | null)
}
inputValue={comboInput}
onInputChange={(event, newInputValue) => {
setComboInput(newInputValue);
}}
options={exoticClassCombos ? exoticClassCombos : []}
getOptionLabel={(option: ExoticClassCombo) =>
String(option.firstIntrinsicHash) + ' & ' + String(option.secondIntrinsicHash)
}
sx={{ width: 250 }}
PopperComponent={StyledPopper}
renderOption={(props, option) => {
const { key, ...otherProps } = props;
return (
<li
{...otherProps}
key={option.firstIntrinsicHash + option.secondIntrinsicHash}
>
<div>
{option.firstIntrinsicHash}
{' & '}
{option.secondIntrinsicHash}
</div>
</li>
);
}}
renderInput={(params) => (
<TextField
{...params}
label="Exotic Class Options"
variant="outlined"
sx={{
'& .MuiOutlinedInput-root': {
color: 'white',
borderRadius: '0',
'& fieldset': {
borderColor: 'white',
},
'&:hover fieldset': {
borderColor: 'white',
},
'&.Mui-focused fieldset': {
borderColor: 'white',
},
},
'& .MuiInputLabel-root': {
color: 'white',
},
'& .MuiInputLabel-root.Mui-focused': {
color: 'white',
},
}}
/>
)}
/>
)}
<ArrowButton isSelected={true} onClick={handleClearSelection}>
<ArrowIcon isSelected={true} />
</ArrowButton>
Expand All @@ -242,4 +313,4 @@ const ExoticSearch: React.FC<ExoticSearchProps> = ({
);
};

export default ExoticSearch;
export default ExoticSelector;
Loading

0 comments on commit 36d2bce

Please sign in to comment.