Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 139 additions & 13 deletions pages/account/cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import {
Text,
Heading,
Grid,
Stack
Stack,
Select,
SelectMultiple
} from 'grommet'
import { useEffect, useContext, useState } from 'react';
import { useEffect, useContext, useState, useMemo } from 'react';
import { AppContext } from '../../data/appContext';
import { NextSeo } from 'next-seo';
import ShadowBox from '../../components/base/ShadowBox';
Expand All @@ -14,6 +16,7 @@ import { Card } from '../../data/domain/cards';
import { CardSet } from '../../data/domain/cardSets';
import TipDisplay from '../../components/base/TipDisplay';
import { initCardSetRepo } from '../../data/domain/data/CardSetRepo';
import { uniqueFilter } from '../../data/utility';

const shouldHideCard = ({ card }: { card: Card }) => {
return false;
Expand Down Expand Up @@ -64,10 +67,13 @@ const CardBox = ({ card }: { card: Card }) => {
<IconImage data={Card.getStarImageForLevel(4)} />
<Text size="small"> : {card.getBonusText(4)} ({Math.floor(card.getCardsForStar(4))} cards)</Text>
</Box>
<Box direction='row' justify='start' align='center' gap='xxsmall'>
<IconImage data={Card.getStarImageForLevel(5)} />
<Text size="small"> : {card.getBonusText(5)} ({Math.floor(card.getCardsForStar(5))} cards)</Text>
</Box>
{
card.fivestar &&
<Box direction='row' justify='start' align='center' gap='xxsmall'>
<IconImage data={Card.getStarImageForLevel(5)} />
<Text size="small"> : {card.getBonusText(5)} ({Math.floor(card.getCardsForStar(5))} cards)</Text>
</Box>
}
</Box>
{(!isMaxed) &&
<Box>
Expand Down Expand Up @@ -148,7 +154,11 @@ const CardSetBox = ({ cardSet }: { cardSet: CardSet }) => {
}

function CardsDisplay() {
const [cards, setCardsData] = useState<Card[]>();
const [cards, setCardsData] = useState<Card[]>([]);
const [sort, setSort] = useState<string>('');
const [filter, setFilter] = useState<string[]>([]);
const [allFilterOptions, setAllFilterOptions] = useState<string[]>([]);
const [currentFilterOptions, setCurrentFilterOptions] = useState<string[]>([]);
const cardSets = CardSet.fromBase(initCardSetRepo(), cards) as CardSet[];
const appContext = useContext(AppContext);

Expand All @@ -157,8 +167,84 @@ function CardsDisplay() {
const theData = appContext.data.getData();
setCardsData(theData.get("cards"));
cardSets.forEach(cardSet => { cardSet.cards = (cards) ? cards.filter(card => card.data.category == cardSet.cardSetName) : [] });

const filterOptions = cards.filter(card => card.displayName != "New Monster?").map(card => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for taking so long to respond.

I think it's here. If you debug it, it will always keep breaking in this useEffect() even after the page has been rendered for a while. I think it's because you are depending on cardSets but also making changes to it on this line.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the cardSets from the useEffect dependancy array solves the constant re-render problem, and we don't need to depend on it so that's fine.

However, I am finally noticing what you guys mean by the page being "laggy" or "slow" and I still haven't found a way to improve it .. maybe there's little we can do with so much information being rendered .. not sure.

I tried moving a lot of the calculations to the "pre-calculation" stage but that made little difference.

return card.data.effect.replaceAll('+', '').replaceAll('%', '').replaceAll('{', '').replaceAll('(Passive)', '').trim();
}).filter(uniqueFilter).sort();

// We keep two set of state, all available filter options and currently available ones.
// The reason for the 2nd one is to allow the search to remove filters based on user typing.
setAllFilterOptions(filterOptions);
setCurrentFilterOptions(filterOptions);
}
}, [appContext, cardSets])

// our sort options are fixed, so just statically set them.
const sortOptions = ["Level", "Least Cards to Next Level"];

const cardsToShow = useMemo(() => {
// If we are still loading, do nothing.
if (!cards) {
return [];
}
}, [appContext, cardSets, cards])

let cardsToDisplay = cards.filter(card => card.displayName != "New Monster?");

// If we have any filters configured, filter them out of the base set
if (filter.length != 0) {
cardsToDisplay = cardsToDisplay.filter(card => filter.includes(card.data.effect.replaceAll('+', '').replaceAll('%', '').replaceAll('{', '').replaceAll('(Passive)', '').trim()));
}

// Now we sort
return cardsToDisplay?.sort((card1, card2) => {
// Base case scenario they are just by index.
const indexSort = card1.index > card2.index ? 1 : -1;

// Least cards to next level sort function
function sortByCardsToNextLevel(card1: Card, card2: Card) {
const currentCard1Level = card1.getStars();
// If card is max level, move it to the end
if (card1.fivestar ? currentCard1Level == 5 : currentCard1Level == 4) {
return 1;
}
const currentCard2Level = card2.getStars();
// If card is max level, move it to the end
if (card2.fivestar ? currentCard2Level == 5 : currentCard2Level == 4) {
return -1;
}
// Else sort by cards till next level
return (card1.count > 0 ? (card1.getCardsForStar(currentCard1Level + 1) - card1.count) : 1) > (card2.count > 0 ? (card2.getCardsForStar(currentCard2Level + 1) - card2.count) : 1) ? 1 : -1;
}

// Sort by level sort function
function sortByLevel(card1: Card, card2: Card) {
// Card will be level 0 if they either have no cards at all or if they are level 0 (so borderless)
if (card1.count == 0 || card2.count == 0) {
return card1.count > card2.count ? -1 : 1;
}

// If they both have at least one card, we can do traditionnal checks
const currentCard1Level = card1.getStars();
const currentCard2Level = card2.getStars();
if (currentCard1Level == currentCard2Level) {
// If level is still equal, sort by time until next level
return sortByCardsToNextLevel(card1, card2);
} else {
// if level isn't equal, just sort by level
return currentCard1Level > currentCard2Level ? -1 : 1;
}
}

switch (sort) {
case "Level":
return sortByLevel(card1, card2);
case "Least Cards to Next Level":
return sortByCardsToNextLevel(card1, card2);
default:
return indexSort;
}
})
}, [cards, sort, filter])

if (!cards || !cardSets) {
return null;
Expand All @@ -168,11 +254,51 @@ function CardsDisplay() {
<Box gap='medium'>
<NextSeo title="Cards" />
<Heading level='2' size='medium' style={{ fontWeight: 'normal' }}>Cards</Heading>
<Grid columns={{ size: 'auto', count: 1 }} gap='medium'>
{
cardSets?.map((cardSet, index) => <CardSetBox key={index} cardSet={cardSet} />)
}
</Grid>
<Box direction="row" gap="medium">
<Select size="small"
placeholder="Sort by"
clear
value={sort}
options={sortOptions}
onChange={({ value: nextValue }) => { setSort(nextValue); }}
/>
<SelectMultiple
size="small"
placeholder="Filter by"
searchPlaceholder="Search bonuses"
value={filter}
options={currentFilterOptions}
onChange={({ value: nextValue }) => { setFilter(nextValue); }}
onSearch={text => {
// The line below escapes regular expression special characters:
// [ \ ^ $ . | ? * + ( )
const escapedText = text.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');

// Create the regular expression with modified value which
// handles escaping special characters. Without escaping special
// characters, errors will appear in the console
const exp = new RegExp(escapedText, 'i');
setCurrentFilterOptions(allFilterOptions.filter(o => exp.test(o)));
}}
onClose={() => setCurrentFilterOptions(allFilterOptions)}
/>
</Box>
{
sort == '' && filter.length == 0 &&
<Grid columns={{ size: 'auto', count: 1 }} gap='medium'>
{
cardSets?.map((cardSet, index) => <CardSetBox key={index} cardSet={cardSet} />)
}
</Grid>
}
{
(sort != '' || filter.length > 0) &&
<Grid width='100%' columns='small' gap='small'>
{
cardsToShow?.map((card, index) => <CardBox key={index} card={card} />)
}
</Grid>
}
</Box>
)
}
Expand Down