nitro-react/src/components/achievements/AchievementsView.tsx

241 lines
9.5 KiB
TypeScript
Raw Normal View History

2021-09-30 04:29:26 +02:00
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
2022-03-03 10:11:31 +01:00
import { GetConfiguration, LocalizeText, SendMessageComposer } from '../../api';
import { Base, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook, UseUiEvent } from '../../hooks';
2021-09-30 04:29:26 +02:00
import { AchievementCategory } from './common/AchievementCategory';
import { AchievementUtilities } from './common/AchievementUtilities';
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
2021-06-28 19:13:33 +02:00
import { AchievementCategoryView } from './views/category/AchievementCategoryView';
2021-06-28 05:47:55 +02:00
2022-01-04 07:14:36 +01:00
export const AchievementsView: FC<{}> = props =>
2021-06-28 05:47:55 +02:00
{
const [ isVisible, setIsVisible ] = useState(false);
2021-09-30 04:29:26 +02:00
const [ isInitalized, setIsInitalized ] = useState(false);
const [ achievementCategories, setAchievementCategories ] = useState<AchievementCategory[]>([]);
const [ selectedCategoryCode, setSelectedCategoryCode ] = useState<string>(null);
const [ achievementScore, setAchievementScore ] = useState(0);
2021-06-28 05:47:55 +02:00
2021-09-30 04:29:26 +02:00
const onAchievementsUIEvent = useCallback((event: AchievementsUIEvent) =>
2021-06-28 05:47:55 +02:00
{
switch(event.type)
{
case AchievementsUIEvent.SHOW_ACHIEVEMENTS:
2021-06-28 05:47:55 +02:00
setIsVisible(true);
return;
case AchievementsUIEvent.HIDE_ACHIEVEMENTS:
2021-06-28 05:47:55 +02:00
setIsVisible(false);
return;
case AchievementsUIEvent.TOGGLE_ACHIEVEMENTS:
2021-06-28 05:47:55 +02:00
setIsVisible(value => !value);
return;
}
}, []);
2022-03-03 10:11:31 +01:00
UseUiEvent(AchievementsUIEvent.SHOW_ACHIEVEMENTS, onAchievementsUIEvent);
UseUiEvent(AchievementsUIEvent.HIDE_ACHIEVEMENTS, onAchievementsUIEvent);
UseUiEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS, onAchievementsUIEvent);
2021-09-30 04:29:26 +02:00
const onAchievementEvent = useCallback((event: AchievementEvent) =>
{
const parser = event.getParser();
const achievement = parser.achievement;
const newCategories = [ ...achievementCategories ];
const categoryName = achievement.category;
const categoryIndex = newCategories.findIndex(existing => (existing.code === categoryName));
if(categoryIndex === -1)
{
const category = new AchievementCategory(categoryName);
category.achievements.push(achievement);
newCategories.push(category);
}
else
{
const category = newCategories[categoryIndex];
const newAchievements = [ ...category.achievements ];
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
let previousAchievement: AchievementData = null;
if(achievementIndex === -1)
{
newAchievements.push(achievement);
}
else
{
previousAchievement = newAchievements[achievementIndex];
newAchievements[achievementIndex] = achievement;
}
if(!AchievementUtilities.isIgnoredAchievement(achievement))
{
achievement.unseen++;
if(previousAchievement) achievement.unseen += previousAchievement.unseen;
}
category.achievements = newAchievements;
}
setAchievementCategories(newCategories);
}, [ achievementCategories ]);
2022-03-03 10:11:31 +01:00
UseMessageEventHook(AchievementEvent, onAchievementEvent);
2021-09-30 04:29:26 +02:00
const onAchievementsEvent = useCallback((event: AchievementsEvent) =>
{
const parser = event.getParser();
const categories: AchievementCategory[] = [];
for(const achievement of parser.achievements)
{
const categoryName = achievement.category;
let existing = categories.find(category => (category.code === categoryName));
if(!existing)
{
existing = new AchievementCategory(categoryName);
categories.push(existing);
}
existing.achievements.push(achievement);
}
BatchUpdates(() =>
{
setAchievementCategories(categories);
setIsInitalized(true);
});
}, []);
2022-03-03 10:11:31 +01:00
UseMessageEventHook(AchievementsEvent, onAchievementsEvent);
2021-09-30 04:29:26 +02:00
const onAchievementsScoreEvent = useCallback((event: AchievementsScoreEvent) =>
{
const parser = event.getParser();
setAchievementScore(parser.score);
}, []);
2022-03-03 10:11:31 +01:00
UseMessageEventHook(AchievementsScoreEvent, onAchievementsScoreEvent);
2021-09-30 04:29:26 +02:00
const getTotalUnseen = useMemo(() =>
{
let unseen = 0;
for(const category of achievementCategories)
{
for(const achievement of category.achievements) unseen += achievement.unseen;
}
return unseen;
}, [ achievementCategories ]);
const getProgress = useMemo(() =>
{
let progress = 0;
for(const category of achievementCategories) progress += category.getProgress();
return progress;
}, [ achievementCategories ]);
const getMaxProgress = useMemo(() =>
{
let progress = 0;
for(const category of achievementCategories) progress += category.getMaxProgress();
return progress;
}, [ achievementCategories ]);
2021-10-05 21:52:52 +02:00
const scaledProgressPercent = useMemo(() =>
{
return ~~((((getProgress - 0) * (100 - 0)) / (getMaxProgress - 0)) + 0);
}, [ getProgress, getMaxProgress ]);
2021-09-30 04:29:26 +02:00
const getSelectedCategory = useMemo(() =>
{
if(!achievementCategories || !achievementCategories.length) return null;
return achievementCategories.find(existing => (existing.code === selectedCategoryCode));
}, [ achievementCategories, selectedCategoryCode ]);
2022-01-04 07:14:36 +01:00
const getCategoryIcon = useMemo(() =>
{
if(!getSelectedCategory) return null;
const imageUrl = GetConfiguration<string>('achievements.images.url');
return imageUrl.replace('%image%', `achicon_${ getSelectedCategory.code }`);
}, [ getSelectedCategory ]);
2021-09-30 04:29:26 +02:00
const setAchievementSeen = useCallback((code: string, achievementId: number) =>
{
const newCategories = [ ...achievementCategories ];
for(const category of newCategories)
{
if(category.code !== code) continue;
for(const achievement of category.achievements)
{
if(achievement.achievementId !== achievementId) continue;
achievement.unseen = 0;
}
}
setAchievementCategories(newCategories);
}, [ achievementCategories ]);
useEffect(() =>
{
if(!isVisible || !isInitalized) return;
2022-03-03 10:11:31 +01:00
SendMessageComposer(new RequestAchievementsMessageComposer());
2021-09-30 04:29:26 +02:00
}, [ isVisible, isInitalized ]);
useEffect(() =>
{
2022-03-03 10:11:31 +01:00
DispatchUiEvent(new AchievementsUIUnseenCountEvent(getTotalUnseen));
2021-09-30 04:29:26 +02:00
}, [ getTotalUnseen ]);
if(!isVisible || !isInitalized) return null;
2021-06-28 05:47:55 +02:00
return (
2022-03-04 07:29:14 +01:00
<NitroCardView uniqueKey="achievements" className="nitro-achievements" theme="primary-slim">
2021-09-30 04:29:26 +02:00
<NitroCardHeaderView headerText={ LocalizeText('inventory.achievements') } onCloseClick={ event => setIsVisible(false) } />
{ getSelectedCategory &&
2022-01-04 07:14:36 +01:00
<NitroCardSubHeaderView position="relative" className="justify-content-center align-items-center cursor-pointer" gap={ 3 }>
2022-03-03 08:23:01 +01:00
<Base onClick={ event => setSelectedCategoryCode(null) } className="nitro-achievements-back-arrow" />
2022-01-04 07:14:36 +01:00
<Column grow gap={ 0 }>
<Text fontSize={ 4 } fontWeight="bold" className="text-small">{ LocalizeText(`quests.${ getSelectedCategory.code }.name`) }</Text>
<Text>{ LocalizeText('achievements.details.categoryprogress', [ 'progress', 'limit' ], [ getSelectedCategory.getProgress().toString(), getSelectedCategory.getMaxProgress().toString() ]) }</Text>
</Column>
2021-09-30 04:29:26 +02:00
</NitroCardSubHeaderView> }
<NitroCardContentView>
2022-01-04 07:14:36 +01:00
{ !getSelectedCategory &&
<>
2022-02-16 07:40:54 +01:00
<AchievementsCategoryListView categories={ achievementCategories } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } />
2022-01-04 07:14:36 +01:00
<Column grow justifyContent="end">
<Base className="progress" position="relative">
<Flex fit center position="absolute" className="text-black">{ LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) }</Flex>
<Base className="progress-bar bg-success" style={ { width: (scaledProgressPercent + '%') }} />
</Base>
<Text className="bg-muted rounded p-1" center>{ LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) }</Text>
</Column>
</> }
{ getSelectedCategory &&
<AchievementCategoryView category={ getSelectedCategory } setAchievementSeen={ setAchievementSeen } /> }
2021-09-30 04:29:26 +02:00
</NitroCardContentView>
</NitroCardView>
2021-06-28 05:47:55 +02:00
);
};