Update achievements

This commit is contained in:
Bill 2022-10-24 02:26:46 -04:00
parent 1ef9190fab
commit 99e98048e0
11 changed files with 65 additions and 68 deletions

View File

@ -1,5 +1,5 @@
import { ILinkEventTracker } from '@nitrots/nitro-renderer'; import { ILinkEventTracker } from '@nitrots/nitro-renderer';
import { FC, useEffect, useMemo, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { AchievementUtilities, AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { AchievementUtilities, AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api';
import { Base, Column, LayoutImage, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common'; import { Base, Column, LayoutImage, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
import { useAchievements } from '../../hooks'; import { useAchievements } from '../../hooks';
@ -9,14 +9,7 @@ import { AchievementsCategoryListView } from './views/category-list/Achievements
export const AchievementsView: FC<{}> = props => export const AchievementsView: FC<{}> = props =>
{ {
const [ isVisible, setIsVisible ] = useState(false); const [ isVisible, setIsVisible ] = useState(false);
const { achievementCategories = [], selectedCategoryCode = null, setSelectedCategoryCode = null, selectedAchievementId = -1, setSelectedAchievementId = null, achievementScore = 0, getProgress = 0, getMaxProgress = 0, setAchievementSeen = null } = useAchievements(); const { achievementCategories = [], selectedCategoryCode = null, setSelectedCategoryCode = null, achievementScore = 0, getProgress = 0, getMaxProgress = 0, selectedCategory = null } = useAchievements();
const selectedCategory = useMemo(() =>
{
if(selectedCategoryCode === null) return null;
return achievementCategories.find(category => (category.code === selectedCategoryCode));
}, [ achievementCategories, selectedCategoryCode ]);
useEffect(() => useEffect(() =>
{ {
@ -72,7 +65,7 @@ export const AchievementsView: FC<{}> = props =>
</Column> </Column>
</> } </> }
{ selectedCategory && { selectedCategory &&
<AchievementCategoryView category={ selectedCategory } selectedAchievementId={ selectedAchievementId } setSelectedAchievementId={ setSelectedAchievementId } setAchievementSeen={ setAchievementSeen } /> } <AchievementCategoryView category={ selectedCategory } /> }
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );

View File

@ -1,48 +1,35 @@
import { Dispatch, FC, SetStateAction, useEffect, useMemo } from 'react'; import { FC, useEffect } from 'react';
import { AchievementCategory } from '../../../api'; import { AchievementCategory } from '../../../api';
import { Column } from '../../../common'; import { Column } from '../../../common';
import { AchievementListView } from './achievement-list/AchievementListView'; import { useAchievements } from '../../../hooks';
import { AchievementListView } from './achievement-list';
import { AchievementDetailsView } from './AchievementDetailsView'; import { AchievementDetailsView } from './AchievementDetailsView';
interface AchievementCategoryViewProps interface AchievementCategoryViewProps
{ {
category: AchievementCategory; category: AchievementCategory;
selectedAchievementId: number;
setSelectedAchievementId: Dispatch<SetStateAction<number>>;
setAchievementSeen: (code: string, achievementId: number) => void;
} }
export const AchievementCategoryView: FC<AchievementCategoryViewProps> = props => export const AchievementCategoryView: FC<AchievementCategoryViewProps> = props =>
{ {
const { category = null, selectedAchievementId = -1, setSelectedAchievementId = null, setAchievementSeen = null } = props; const { category = null } = props;
const { selectedAchievement = null, setSelectedAchievementId = null } = useAchievements();
const selectedAchievement = useMemo(() =>
{
if(selectedAchievementId === -1) return null;
return category.achievements.find(achievement => (achievement.achievementId === selectedAchievementId));
}, [ category, selectedAchievementId ]);
useEffect(() => useEffect(() =>
{ {
if(!category) return;
if(!selectedAchievement) if(!selectedAchievement)
{ {
if(category.achievements.length) setSelectedAchievementId(category.achievements[0].achievementId); setSelectedAchievementId(category?.achievements?.[0]?.achievementId);
} }
}, [ selectedAchievement, category, setSelectedAchievementId ]); }, [ category, selectedAchievement, setSelectedAchievementId ]);
useEffect(() =>
{
if(!selectedAchievement) return;
setAchievementSeen(category.code, selectedAchievement.achievementId);
}, [ selectedAchievement, category, setAchievementSeen ]);
if(!category) return null; if(!category) return null;
return ( return (
<Column fullHeight justifyContent="between"> <Column fullHeight justifyContent="between">
<AchievementListView achievements={ category.achievements } selectedAchievementId={ selectedAchievementId } setSelectedAchievementId={ setSelectedAchievementId } /> <AchievementListView achievements={ category.achievements } />
{ !!selectedAchievement && { !!selectedAchievement &&
<AchievementDetailsView achievement={ selectedAchievement } /> } <AchievementDetailsView achievement={ selectedAchievement } /> }
</Column> </Column>

View File

@ -1,5 +1,5 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { FC, PropsWithChildren } from 'react'; import { FC } from 'react';
import { AchievementUtilities, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../api'; import { AchievementUtilities, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../api';
import { Column, Flex, LayoutCurrencyIcon, LayoutProgressBar, Text } from '../../../common'; import { Column, Flex, LayoutCurrencyIcon, LayoutProgressBar, Text } from '../../../common';
import { AchievementBadgeView } from './AchievementBadgeView'; import { AchievementBadgeView } from './AchievementBadgeView';
@ -9,14 +9,14 @@ interface AchievementDetailsViewProps
achievement: AchievementData; achievement: AchievementData;
} }
export const AchievementDetailsView: FC<PropsWithChildren<AchievementDetailsViewProps>> = props => export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
{ {
const { achievement = null, children = null, ...rest } = props; const { achievement = null } = props;
if(!achievement) return null; if(!achievement) return null;
return ( return (
<Flex shrink className="bg-muted rounded p-2 text-black" gap={ 2 } overflow="hidden" { ...rest }> <Flex shrink className="bg-muted rounded p-2 text-black" gap={ 2 } overflow="hidden">
<Column center gap={ 1 }> <Column center gap={ 1 }>
<AchievementBadgeView className="nitro-achievements-badge-image" achievement={ achievement } scale={ 2 } /> <AchievementBadgeView className="nitro-achievements-badge-image" achievement={ achievement } scale={ 2 } />
<Text fontWeight="bold"> <Text fontWeight="bold">
@ -48,7 +48,6 @@ export const AchievementDetailsView: FC<PropsWithChildren<AchievementDetailsView
<LayoutProgressBar text={ LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) } progress={ (achievement.currentPoints + achievement.scoreAtStartOfLevel) } maxProgress={ (achievement.scoreLimit + achievement.scoreAtStartOfLevel) } /> } <LayoutProgressBar text={ LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) } progress={ (achievement.currentPoints + achievement.scoreAtStartOfLevel) } maxProgress={ (achievement.scoreLimit + achievement.scoreAtStartOfLevel) } /> }
</Column> } </Column> }
</Column> </Column>
{ children }
</Flex> </Flex>
) )
} }

View File

@ -1,25 +1,24 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { Dispatch, FC, PropsWithChildren, SetStateAction } from 'react'; import { FC } from 'react';
import { LayoutGridItem } from '../../../../common'; import { LayoutGridItem } from '../../../../common';
import { useAchievements } from '../../../../hooks';
import { AchievementBadgeView } from '../AchievementBadgeView'; import { AchievementBadgeView } from '../AchievementBadgeView';
interface AchievementListItemViewProps interface AchievementListItemViewProps
{ {
achievement: AchievementData; achievement: AchievementData;
selectedAchievementId: number;
setSelectedAchievementId: Dispatch<SetStateAction<number>>;
} }
export const AchievementListItemView: FC<PropsWithChildren<AchievementListItemViewProps>> = props => export const AchievementListItemView: FC<AchievementListItemViewProps> = props =>
{ {
const { achievement = null, selectedAchievementId = -1, setSelectedAchievementId = null, children = null, ...rest } = props; const { achievement = null } = props;
const { selectedAchievement = null, setSelectedAchievementId = null } = useAchievements();
if(!achievement) return null; if(!achievement) return null;
return ( return (
<LayoutGridItem itemActive={ (selectedAchievementId === achievement.achievementId) } itemUnseen={ (achievement.unseen > 0) } onClick={ event => setSelectedAchievementId(achievement.achievementId) } { ...rest }> <LayoutGridItem itemActive={ (selectedAchievement === achievement) } itemUnseen={ (achievement.unseen > 0) } onClick={ event => setSelectedAchievementId(achievement.achievementId) }>
<AchievementBadgeView achievement={ achievement } /> <AchievementBadgeView achievement={ achievement } />
{ children }
</LayoutGridItem> </LayoutGridItem>
); );
} }

View File

@ -1,23 +1,20 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { Dispatch, FC, PropsWithChildren, SetStateAction } from 'react'; import { FC } from 'react';
import { AutoGrid } from '../../../../common'; import { AutoGrid } from '../../../../common';
import { AchievementListItemView } from './AchievementListItemView'; import { AchievementListItemView } from './AchievementListItemView';
interface AchievementListViewProps interface AchievementListViewProps
{ {
achievements: AchievementData[]; achievements: AchievementData[];
selectedAchievementId: number;
setSelectedAchievementId: Dispatch<SetStateAction<number>>;
} }
export const AchievementListView: FC<PropsWithChildren<AchievementListViewProps>> = props => export const AchievementListView: FC<AchievementListViewProps> = props =>
{ {
const { achievements = null, selectedAchievementId = -1, setSelectedAchievementId = null, children = null, ...rest } = props; const { achievements = null } = props;
return ( return (
<AutoGrid columnCount={ 6 } columnMinWidth={ 50 } columnMinHeight={ 50 } { ...rest }> <AutoGrid columnCount={ 6 } columnMinWidth={ 50 } columnMinHeight={ 50 }>
{ achievements && (achievements.length > 0) && achievements.map((achievement, index) => <AchievementListItemView key={ index } achievement={ achievement } selectedAchievementId={ selectedAchievementId } setSelectedAchievementId={ setSelectedAchievementId } />) } { achievements && (achievements.length > 0) && achievements.map((achievement, index) => <AchievementListItemView key={ index } achievement={ achievement } />) }
{ children }
</AutoGrid> </AutoGrid>
); );
} }

View File

@ -0,0 +1,2 @@
export * from './AchievementListItemView';
export * from './AchievementListView';

View File

@ -1,4 +1,4 @@
import { Dispatch, FC, PropsWithChildren, SetStateAction } from 'react'; import { Dispatch, FC, SetStateAction } from 'react';
import { AchievementUtilities, IAchievementCategory, LocalizeText } from '../../../../api'; import { AchievementUtilities, IAchievementCategory, LocalizeText } from '../../../../api';
import { LayoutBackgroundImage, LayoutGridItem, Text } from '../../../../common'; import { LayoutBackgroundImage, LayoutGridItem, Text } from '../../../../common';
@ -9,9 +9,9 @@ interface AchievementCategoryListItemViewProps
setSelectedCategoryCode: Dispatch<SetStateAction<string>>; setSelectedCategoryCode: Dispatch<SetStateAction<string>>;
} }
export const AchievementsCategoryListItemView: FC<PropsWithChildren<AchievementCategoryListItemViewProps>> = props => export const AchievementsCategoryListItemView: FC<AchievementCategoryListItemViewProps> = props =>
{ {
const { category = null, selectedCategoryCode = null, setSelectedCategoryCode = null, children = null, ...rest } = props; const { category = null, selectedCategoryCode = null, setSelectedCategoryCode = null } = props;
if(!category) return null; if(!category) return null;
@ -21,12 +21,11 @@ export const AchievementsCategoryListItemView: FC<PropsWithChildren<AchievementC
const getTotalUnseen = AchievementUtilities.getAchievementCategoryTotalUnseen(category); const getTotalUnseen = AchievementUtilities.getAchievementCategoryTotalUnseen(category);
return ( return (
<LayoutGridItem itemActive={ (selectedCategoryCode === category.code) } itemCount={ getTotalUnseen } itemCountMinimum={ 0 } gap={ 1 } onClick={ event => setSelectedCategoryCode(category.code) } { ...rest }> <LayoutGridItem itemActive={ (selectedCategoryCode === category.code) } itemCount={ getTotalUnseen } itemCountMinimum={ 0 } gap={ 1 } onClick={ event => setSelectedCategoryCode(category.code) }>
<Text fullWidth center small className="pt-1">{ LocalizeText(`quests.${ category.code }.name`) }</Text> <Text fullWidth center small className="pt-1">{ LocalizeText(`quests.${ category.code }.name`) }</Text>
<LayoutBackgroundImage position="relative" imageUrl={ getCategoryImage }> <LayoutBackgroundImage position="relative" imageUrl={ getCategoryImage }>
<Text fullWidth center position="absolute" variant="white" style={ { fontSize: 12, bottom: 9 } }>{ progress } / { maxProgress }</Text> <Text fullWidth center position="absolute" variant="white" style={ { fontSize: 12, bottom: 9 } }>{ progress } / { maxProgress }</Text>
</LayoutBackgroundImage> </LayoutBackgroundImage>
{ children }
</LayoutGridItem> </LayoutGridItem>
); );
} }

View File

@ -1,4 +1,4 @@
import { Dispatch, FC, PropsWithChildren, SetStateAction } from 'react'; import { Dispatch, FC, SetStateAction } from 'react';
import { IAchievementCategory } from '../../../../api'; import { IAchievementCategory } from '../../../../api';
import { AutoGrid } from '../../../../common'; import { AutoGrid } from '../../../../common';
import { AchievementsCategoryListItemView } from './AchievementsCategoryListItemView'; import { AchievementsCategoryListItemView } from './AchievementsCategoryListItemView';
@ -10,14 +10,13 @@ interface AchievementsCategoryListViewProps
setSelectedCategoryCode: Dispatch<SetStateAction<string>>; setSelectedCategoryCode: Dispatch<SetStateAction<string>>;
} }
export const AchievementsCategoryListView: FC<PropsWithChildren<AchievementsCategoryListViewProps>> = props => export const AchievementsCategoryListView: FC<AchievementsCategoryListViewProps> = props =>
{ {
const { categories = null, selectedCategoryCode = null, setSelectedCategoryCode = null, children = null, ...rest } = props; const { categories = null, selectedCategoryCode = null, setSelectedCategoryCode = null } = props;
return ( return (
<AutoGrid columnCount={ 3 } columnMinWidth={ 90 } columnMinHeight={ 100 } { ...rest }> <AutoGrid columnCount={ 3 } columnMinWidth={ 90 } columnMinHeight={ 100 }>
{ categories && (categories.length > 0) && categories.map((category, index) => <AchievementsCategoryListItemView key={ index } category={ category } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } /> ) } { categories && (categories.length > 0) && categories.map((category, index) => <AchievementsCategoryListItemView key={ index } category={ category } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } /> ) }
{ children }
</AutoGrid> </AutoGrid>
); );
}; };

View File

@ -0,0 +1,2 @@
export * from './AchievementsCategoryListItemView';
export * from './AchievementsCategoryListView';

View File

@ -0,0 +1,5 @@
export * from './achievement-list';
export * from './AchievementBadgeView';
export * from './AchievementCategoryView';
export * from './AchievementDetailsView';
export * from './category-list';

View File

@ -1,5 +1,6 @@
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer'; import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
import { useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { useBetween } from 'use-between';
import { AchievementCategory, AchievementUtilities, CloneObject, SendMessageComposer } from '../../api'; import { AchievementCategory, AchievementUtilities, CloneObject, SendMessageComposer } from '../../api';
import { useMessageEvent } from '../events'; import { useMessageEvent } from '../events';
@ -43,7 +44,21 @@ const useAchievementsState = () =>
return ~~((((getProgress - 0) * (100 - 0)) / (getMaxProgress - 0)) + 0); return ~~((((getProgress - 0) * (100 - 0)) / (getMaxProgress - 0)) + 0);
}, [ getProgress, getMaxProgress ]); }, [ getProgress, getMaxProgress ]);
const setAchievementSeen = (categoryCode: string, achievementId: number) => const selectedCategory = useMemo(() =>
{
if(selectedCategoryCode === null) return null;
return achievementCategories.find(category => (category.code === selectedCategoryCode));
}, [ achievementCategories, selectedCategoryCode ]);
const selectedAchievement = useMemo(() =>
{
if((selectedAchievementId === -1) || !selectedCategory) return null;
return selectedCategory.achievements.find(achievement => (achievement.achievementId === selectedAchievementId));
}, [ selectedCategory, selectedAchievementId ]);
const setAchievementSeen = useCallback((categoryCode: string, achievementId: number) =>
{ {
setAchievementCategories(prevValue => setAchievementCategories(prevValue =>
{ {
@ -63,7 +78,7 @@ const useAchievementsState = () =>
return newValue; return newValue;
}); });
} }, []);
useMessageEvent<AchievementEvent>(AchievementEvent, event => useMessageEvent<AchievementEvent>(AchievementEvent, event =>
{ {
@ -157,7 +172,7 @@ const useAchievementsState = () =>
setNeedsUpdate(false); setNeedsUpdate(false);
}, [ needsUpdate ]); }, [ needsUpdate ]);
return { achievementCategories, selectedCategoryCode, setSelectedCategoryCode, selectedAchievementId, setSelectedAchievementId, achievementScore, getTotalUnseen, getProgress, getMaxProgress, scaledProgressPercent, setAchievementSeen }; return { achievementCategories, selectedCategoryCode, setSelectedCategoryCode, selectedAchievementId, setSelectedAchievementId, achievementScore, getTotalUnseen, getProgress, getMaxProgress, scaledProgressPercent, selectedCategory, selectedAchievement, setAchievementSeen };
} }
export const useAchievements = useAchievementsState; export const useAchievements = () => useBetween(useAchievementsState);