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

250 lines
9.2 KiB
TypeScript
Raw Normal View History

2022-03-23 08:05:44 +01:00
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, ILinkEventTracker, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
2021-09-30 04:29:26 +02:00
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
2022-03-30 18:47:30 +02:00
import { AchievementCategory, AddEventLinkTracker, CloneObject, GetAchievementCategoryImageUrl, GetAchievementIsIgnored, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
2022-03-24 03:54:52 +01:00
import { Base, Column, LayoutImage, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
2022-03-23 08:05:44 +01:00
import { AchievementsUIUnseenCountEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { AchievementCategoryView } from './views/AchievementCategoryView';
2021-09-30 04:29:26 +02:00
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
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 onAchievementEvent = useCallback((event: AchievementEvent) =>
{
const parser = event.getParser();
const achievement = parser.achievement;
const categoryName = achievement.category;
2022-03-23 08:05:44 +01:00
setAchievementCategories(prevValue =>
2022-04-01 19:33:08 +02:00
{
const newValue = [ ...prevValue ];
const categoryIndex = newValue.findIndex(existing => (existing.code === categoryName));
if(categoryIndex === -1)
2021-09-30 04:29:26 +02:00
{
2022-04-01 19:33:08 +02:00
const category = new AchievementCategory(categoryName);
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
category.achievements.push(achievement);
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
newValue.push(category);
}
else
{
const category = CloneObject(newValue[categoryIndex]);
const newAchievements = [ ...category.achievements ];
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
let previousAchievement: AchievementData = null;
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
if(achievementIndex === -1)
{
newAchievements.push(achievement);
2022-03-23 08:05:44 +01:00
}
else
{
2022-04-01 19:33:08 +02:00
previousAchievement = newAchievements[achievementIndex];
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
newAchievements[achievementIndex] = achievement;
}
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
if(!GetAchievementIsIgnored(achievement))
{
achievement.unseen++;
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
if(previousAchievement) achievement.unseen += previousAchievement.unseen;
}
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
category.achievements = newAchievements;
2022-03-30 18:47:30 +02:00
2022-04-01 19:33:08 +02:00
newValue[categoryIndex] = category;
}
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
return newValue;
});
2022-03-23 08:05:44 +01:00
}, []);
2021-09-30 04:29:26 +02:00
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;
2022-03-23 08:05:44 +01:00
2021-09-30 04:29:26 +02:00
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-03-23 08:05:44 +01:00
const setAchievementSeen = useCallback((code: string, achievementId: number) =>
2022-01-04 07:14:36 +01:00
{
2022-03-23 08:05:44 +01:00
setAchievementCategories(prevValue =>
2022-04-01 19:33:08 +02:00
{
const newValue = [ ...prevValue ];
for(const category of newValue)
2022-03-23 08:05:44 +01:00
{
2022-04-01 19:33:08 +02:00
if(category.code !== code) continue;
2022-01-04 07:14:36 +01:00
2022-04-01 19:33:08 +02:00
for(const achievement of category.achievements)
2022-03-23 08:05:44 +01:00
{
2022-04-01 19:33:08 +02:00
if(achievement.achievementId !== achievementId) continue;
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
achievement.unseen = 0;
2022-03-23 08:05:44 +01:00
}
2022-04-01 19:33:08 +02:00
}
2022-03-23 08:05:44 +01:00
2022-04-01 19:33:08 +02:00
return newValue;
});
2022-03-23 08:05:44 +01:00
}, []);
const linkReceived = useCallback((url: string) =>
2021-09-30 04:29:26 +02:00
{
2022-03-23 08:05:44 +01:00
const parts = url.split('/');
if(parts.length < 2) return;
2021-09-30 04:29:26 +02:00
2022-03-23 08:05:44 +01:00
switch(parts[1])
2021-09-30 04:29:26 +02:00
{
2022-03-23 08:05:44 +01:00
case 'show':
setIsVisible(true);
return;
case 'hide':
setIsVisible(false);
return;
case 'toggle':
setIsVisible(prevValue => !prevValue);
return;
}
}, []);
2021-09-30 04:29:26 +02:00
2022-03-23 08:05:44 +01:00
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived,
eventUrlPrefix: 'achievements/'
};
2021-09-30 04:29:26 +02:00
2022-03-23 08:05:44 +01:00
AddEventLinkTracker(linkTracker);
2021-09-30 04:29:26 +02:00
2022-03-23 08:05:44 +01:00
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived ]);
2021-09-30 04:29:26 +02:00
useEffect(() =>
{
2022-03-18 01:31:40 +01:00
if(!isVisible || isInitalized) return;
2021-09-30 04:29:26 +02:00
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>
2022-03-26 01:07:33 +01:00
<LayoutImage imageUrl={ GetAchievementCategoryImageUrl(getSelectedCategory, null,true) } />
2021-09-30 04:29:26 +02:00
</NitroCardSubHeaderView> }
2022-03-23 08:05:44 +01:00
<NitroCardContentView gap={ 1 }>
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-03-24 03:54:52 +01:00
<Column grow justifyContent="end" gap={ 1 }>
<Text small center>{ LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) }</Text>
2022-03-23 08:05:44 +01:00
<LayoutProgressBar text={ LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) } progress={ getProgress } maxProgress={ getMaxProgress } />
2022-01-04 07:14:36 +01:00
</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
);
};