Update achievements

This commit is contained in:
Bill 2022-03-23 03:05:44 -04:00
parent c8ca5d2b82
commit d1a7badeba
20 changed files with 182 additions and 189 deletions

View File

@ -19,7 +19,7 @@ $grid-active-border-color: $white;
$toolbar-height: 55px;
$achievement-width: 375px;
$achievement-height: 425px;
$achievement-height: 415px;
$avatar-editor-width: 620px;
$avatar-editor-height: 374px;

View File

@ -0,0 +1,13 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetLocalization } from '..';
export const GetAchievementBadgeCode = (achievement: AchievementData) =>
{
if(!achievement) return null;
let badgeId = achievement.badgeId;
if(!achievement.finalLevel) badgeId = GetLocalization().getPreviousLevelBadgeId(badgeId);
return badgeId;
}

View File

@ -0,0 +1,10 @@
import { AchievementData } from '@nitrots/nitro-renderer';
export const GetAchievementHasStarted = (achievement: AchievementData) =>
{
if(!achievement) return false;
if(achievement.finalLevel || ((achievement.level - 1) > 0)) return true;
return false;
}

View File

@ -0,0 +1,15 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetConfiguration } from '..';
export const GetAchievementIsIgnored = (achievement: AchievementData) =>
{
if(!achievement) return false;
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
const value = achievement.badgeId.replace(/[0-9]/g, '');
const index = ignored.indexOf(value);
if(index >= 0) return true;
return false;
}

View File

@ -0,0 +1,5 @@
export * from './AchievementCategory';
export * from './GetAchievementBadgeCode';
export * from './GetAchievementHasStarted';
export * from './GetAchievementIsIgnored';
export * from './GetAchievementLevel';

View File

@ -1,3 +1,4 @@
export * from './achievements';
export * from './common';
export * from './core';
export * from './friends';

View File

@ -1,13 +1,11 @@
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, ILinkEventTracker, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
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';
import { AchievementCategory } from './common/AchievementCategory';
import { AchievementUtilities } from './common/AchievementUtilities';
import { AchievementCategory, AddEventLinkTracker, GetAchievementIsIgnored, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { Base, Column, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
import { AchievementsUIUnseenCountEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { AchievementCategoryView } from './views/AchievementCategoryView';
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
import { AchievementCategoryView } from './views/category/AchievementCategoryView';
export const AchievementsView: FC<{}> = props =>
{
@ -17,33 +15,16 @@ export const AchievementsView: FC<{}> = props =>
const [ selectedCategoryCode, setSelectedCategoryCode ] = useState<string>(null);
const [ achievementScore, setAchievementScore ] = useState(0);
const onAchievementsUIEvent = useCallback((event: AchievementsUIEvent) =>
{
switch(event.type)
{
case AchievementsUIEvent.SHOW_ACHIEVEMENTS:
setIsVisible(true);
return;
case AchievementsUIEvent.HIDE_ACHIEVEMENTS:
setIsVisible(false);
return;
case AchievementsUIEvent.TOGGLE_ACHIEVEMENTS:
setIsVisible(value => !value);
return;
}
}, []);
UseUiEvent(AchievementsUIEvent.SHOW_ACHIEVEMENTS, onAchievementsUIEvent);
UseUiEvent(AchievementsUIEvent.HIDE_ACHIEVEMENTS, onAchievementsUIEvent);
UseUiEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS, onAchievementsUIEvent);
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));
setAchievementCategories(prevValue =>
{
const newValue = [ ...prevValue ];
const categoryIndex = newValue.findIndex(existing => (existing.code === categoryName));
if(categoryIndex === -1)
{
@ -51,11 +32,11 @@ export const AchievementsView: FC<{}> = props =>
category.achievements.push(achievement);
newCategories.push(category);
newValue.push(category);
}
else
{
const category = newCategories[categoryIndex];
const category = newValue[categoryIndex];
const newAchievements = [ ...category.achievements ];
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
let previousAchievement: AchievementData = null;
@ -71,7 +52,7 @@ export const AchievementsView: FC<{}> = props =>
newAchievements[achievementIndex] = achievement;
}
if(!AchievementUtilities.isIgnoredAchievement(achievement))
if(!GetAchievementIsIgnored(achievement))
{
achievement.unseen++;
@ -81,8 +62,9 @@ export const AchievementsView: FC<{}> = props =>
category.achievements = newAchievements;
}
setAchievementCategories(newCategories);
}, [ achievementCategories ]);
return newValue;
});
}, []);
UseMessageEventHook(AchievementEvent, onAchievementEvent);
@ -95,6 +77,7 @@ export const AchievementsView: FC<{}> = props =>
for(const achievement of parser.achievements)
{
const categoryName = achievement.category;
let existing = categories.find(category => (category.code === categoryName));
if(!existing)
@ -167,20 +150,13 @@ export const AchievementsView: FC<{}> = props =>
return achievementCategories.find(existing => (existing.code === selectedCategoryCode));
}, [ achievementCategories, selectedCategoryCode ]);
const getCategoryIcon = useMemo(() =>
{
if(!getSelectedCategory) return null;
const imageUrl = GetConfiguration<string>('achievements.images.url');
return imageUrl.replace('%image%', `achicon_${ getSelectedCategory.code }`);
}, [ getSelectedCategory ]);
const setAchievementSeen = useCallback((code: string, achievementId: number) =>
{
const newCategories = [ ...achievementCategories ];
setAchievementCategories(prevValue =>
{
const newValue = [ ...prevValue ];
for(const category of newCategories)
for(const category of newValue)
{
if(category.code !== code) continue;
@ -192,8 +168,41 @@ export const AchievementsView: FC<{}> = props =>
}
}
setAchievementCategories(newCategories);
}, [ achievementCategories ]);
return newValue;
});
}, []);
const linkReceived = useCallback((url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'show':
setIsVisible(true);
return;
case 'hide':
setIsVisible(false);
return;
case 'toggle':
setIsVisible(prevValue => !prevValue);
return;
}
}, []);
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived,
eventUrlPrefix: 'achievements/'
};
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived ]);
useEffect(() =>
{
@ -220,15 +229,12 @@ export const AchievementsView: FC<{}> = props =>
<Text>{ LocalizeText('achievements.details.categoryprogress', [ 'progress', 'limit' ], [ getSelectedCategory.getProgress().toString(), getSelectedCategory.getMaxProgress().toString() ]) }</Text>
</Column>
</NitroCardSubHeaderView> }
<NitroCardContentView>
<NitroCardContentView gap={ 1 }>
{ !getSelectedCategory &&
<>
<AchievementsCategoryListView categories={ achievementCategories } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } />
<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>
<LayoutProgressBar text={ LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) } progress={ getProgress } maxProgress={ getMaxProgress } />
<Text className="bg-muted rounded p-1" center>{ LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) }</Text>
</Column>
</> }

View File

@ -1,38 +0,0 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetConfiguration, GetLocalization } from '../../../api';
export class AchievementUtilities
{
public static hasStarted(achievement: AchievementData): boolean
{
if(!achievement) return false;
if(achievement.finalLevel || ((achievement.level - 1) > 0)) return true;
return false;
}
public static getBadgeCode(achievement: AchievementData): string
{
if(!achievement) return null;
let badgeId = achievement.badgeId;
if(!achievement.finalLevel) badgeId = GetLocalization().getPreviousLevelBadgeId(badgeId);
return badgeId;
}
public static isIgnoredAchievement(achievement: AchievementData): boolean
{
if(!achievement) return false;
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
const value = achievement.badgeId.replace(/[0-9]/g, '');
const index = ignored.indexOf(value);
if(index >= 0) return true;
return false;
}
}

View File

@ -1,8 +0,0 @@
import { AchievementData } from '@nitrots/nitro-renderer';
export const GetScaledProgressPercent = (achievement: AchievementData) =>
{
if(!achievement) return 0;
return ~~(((((achievement.currentPoints + achievement.scoreAtStartOfLevel) - 0) * (100 - 0)) / ((achievement.scoreLimit + achievement.scoreAtStartOfLevel) - 0)) + 0);
}

View File

@ -0,0 +1,19 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { GetAchievementBadgeCode, GetAchievementHasStarted } from '../../../api';
import { BaseProps, LayoutBadgeImageView } from '../../../common';
interface AchievementBadgeViewProps extends BaseProps<HTMLDivElement>
{
achievement: AchievementData;
scale?: number;
}
export const AchievementBadgeView: FC<AchievementBadgeViewProps> = props =>
{
const { achievement = null, scale = 1, ...rest } = props;
if(!achievement) return null;
return <LayoutBadgeImageView badgeCode={ GetAchievementBadgeCode(achievement) } isGrayscale={ !GetAchievementHasStarted(achievement) } scale={ scale } { ...rest } />;
}

View File

@ -1,10 +1,10 @@
import { FC, useEffect, useMemo, useState } from 'react';
import { Column } from '../../../../common/Column';
import { AchievementCategory } from '../../common/AchievementCategory';
import { AchievementDetailsView } from '../achievement-details/AchievementDetailsView';
import { AchievementListView } from '../achievement-list/AchievementListView';
import { AchievementCategory } from '../../../api';
import { Column } from '../../../common';
import { AchievementListView } from './achievement-list/AchievementListView';
import { AchievementDetailsView } from './AchievementDetailsView';
export class AchievementCategoryViewProps
interface AchievementCategoryViewProps
{
category: AchievementCategory;
setAchievementSeen: (code: string, achievementId: number) => void;

View File

@ -1,13 +1,11 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../../api';
import { Base, Column, Flex, LayoutCurrencyIcon, Text } from '../../../../common';
import { AchievementUtilities } from '../../common/AchievementUtilities';
import { GetAchievementLevel } from '../../common/GetAchievementLevel';
import { GetScaledProgressPercent } from '../../common/GetScaledProgressPercent';
import { AchievementBadgeView } from '../achievement-badge/AchievementBadgeView';
import { GetAchievementBadgeCode, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../api';
import { GetAchievementLevel } from '../../../api/achievements/GetAchievementLevel';
import { Column, Flex, LayoutCurrencyIcon, LayoutProgressBar, Text } from '../../../common';
import { AchievementBadgeView } from './AchievementBadgeView';
export interface AchievementDetailsViewProps
interface AchievementDetailsViewProps
{
achievement: AchievementData;
}
@ -19,7 +17,6 @@ export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
if(!achievement) return null;
const achievementLevel = GetAchievementLevel(achievement);
const scaledProgressPercent = GetScaledProgressPercent(achievement);
return (
<Flex shrink className="bg-muted rounded p-2 text-black" gap={ 2 } overflow="hidden">
@ -32,10 +29,10 @@ export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
<Column fullWidth justifyContent="center" overflow="hidden">
<Column gap={ 1 }>
<Text fontWeight="bold" truncate>
{ LocalizeBadgeName(AchievementUtilities.getBadgeCode(achievement)) }
{ LocalizeBadgeName(GetAchievementBadgeCode(achievement)) }
</Text>
<Text truncate>
{ LocalizeBadgeDescription(AchievementUtilities.getBadgeCode(achievement)) }
<Text textBreak>
{ LocalizeBadgeDescription(GetAchievementBadgeCode(achievement)) }
</Text>
</Column>
{ ((achievement.levelRewardPoints > 0) || (achievement.scoreLimit > 0)) &&
@ -51,10 +48,7 @@ export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
</Flex>
</Flex> }
{ (achievement.scoreLimit > 0) &&
<Base className="progress" position="relative">
<Flex fit center position="absolute" className="text-black"> { LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) }</Flex>
<Base className="progress-bar" style={ { width: (scaledProgressPercent + '%') }} />
</Base> }
<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>
</Flex>

View File

@ -1,21 +0,0 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { BaseProps, LayoutBadgeImageView } from '../../../../common';
import { AchievementUtilities } from '../../common/AchievementUtilities';
export interface AchievementBadgeViewProps extends BaseProps<HTMLDivElement>
{
achievement: AchievementData;
scale?: number;
}
export const AchievementBadgeView: FC<AchievementBadgeViewProps> = props =>
{
const { achievement = null, scale = 1, ...rest } = props;
if(!achievement) return null;
return (
<LayoutBadgeImageView badgeCode={ AchievementUtilities.getBadgeCode(achievement) } isGrayscale={ !AchievementUtilities.hasStarted(achievement) } scale={ scale } { ...rest } />
);
}

View File

@ -1,9 +1,9 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { LayoutGridItem, LayoutGridItemProps } from '../../../../common/layout/LayoutGridItem';
import { AchievementBadgeView } from '../achievement-badge/AchievementBadgeView';
import { LayoutGridItem, LayoutGridItemProps } from '../../../../common';
import { AchievementBadgeView } from '../AchievementBadgeView';
export interface AchievementListItemViewProps extends LayoutGridItemProps
interface AchievementListItemViewProps extends LayoutGridItemProps
{
achievement: AchievementData;
}

View File

@ -1,6 +1,6 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { Dispatch, FC, SetStateAction } from 'react';
import { AutoGrid } from '../../../../common/AutoGrid';
import { AutoGrid } from '../../../../common';
import { AchievementListItemView } from './AchievementListItemView';
export interface AchievementListViewProps

View File

@ -1,9 +1,6 @@
import { FC, useCallback, useMemo } from 'react';
import { GetConfiguration, LocalizeText } from '../../../../api';
import { LayoutGridItem, LayoutGridItemProps } from '../../../../common/layout/LayoutGridItem';
import { LayoutImage } from '../../../../common/layout/LayoutImage';
import { Text } from '../../../../common/Text';
import { AchievementCategory } from '../../common/AchievementCategory';
import { AchievementCategory, GetConfiguration, LocalizeText } from '../../../../api';
import { LayoutGridItem, LayoutGridItemProps, LayoutImage, Text } from '../../../../common';
export interface AchievementCategoryListItemViewProps extends LayoutGridItemProps
{

View File

@ -1,6 +1,6 @@
import { Dispatch, FC, SetStateAction } from 'react';
import { AutoGrid } from '../../../../common/AutoGrid';
import { AchievementCategory } from '../../common/AchievementCategory';
import { AchievementCategory } from '../../../../api';
import { AutoGrid } from '../../../../common';
import { AchievementsCategoryListItemView } from './AchievementsCategoryListItemView';
export interface AchievementsCategoryListViewProps

View File

@ -2,7 +2,7 @@ import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, Nitro
import { FC, useCallback, useState } from 'react';
import { CreateLinkEvent, GetSessionDataManager, GetUserProfile, OpenMessengerChat, VisitDesktop } from '../../api';
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, GuideToolEvent, InventoryEvent, ModToolsEvent, UnseenItemTrackerUpdateEvent, UserSettingsUIEvent } from '../../events';
import { AchievementsUIUnseenCountEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, GuideToolEvent, InventoryEvent, ModToolsEvent, UnseenItemTrackerUpdateEvent, UserSettingsUIEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
import { ToolbarViewItems } from './common/ToolbarViewItems';
import { ToolbarMeView } from './ToolbarMeView';
@ -157,7 +157,7 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
DispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS));
return;
case ToolbarViewItems.ACHIEVEMENTS_ITEM:
DispatchUiEvent(new AchievementsUIEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS));
CreateLinkEvent('achievements/toggle');
setMeExpanded(false);
return;
case ToolbarViewItems.PROFILE_ITEM: