utils#formatNumberWithCommas TypeScript Examples
The following examples show how to use
utils#formatNumberWithCommas.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From exevo-pan with The Unlicense | 6 votes |
AuctionBid = ({ hasBeenBidded, currentBid, past }: AuctionBidProps) => {
const {
translations: { common },
} = useTranslations()
const bidLabelText = useMemo(() => {
if (past) {
return hasBeenBidded
? common.CharacterCard.bidLabelText.auctionSuccessful
: common.CharacterCard.bidLabelText.auctionFailed
}
return hasBeenBidded
? common.CharacterCard.bidLabelText.currentBid
: common.CharacterCard.bidLabelText.minimumBid
}, [past, hasBeenBidded, common])
return (
<LabeledTextBox labelText={bidLabelText}>
<Icons.TibiaCoin />
{formatNumberWithCommas(currentBid)}
</LabeledTextBox>
)
}
Example #2
Source File: Achievements.tsx From exevo-pan with The Unlicense | 6 votes |
CharacterAchievements = ({ achievementPoints, ...props }: CharacterAchievementsProps) => ( <S.TitleWrapper {...props}> <S.Icons.Achievements /> Achievement points: {formatNumberWithCommas(achievementPoints)} </S.TitleWrapper> )
Example #3
Source File: Charms.tsx From exevo-pan with The Unlicense | 6 votes |
CharacterCharms = ({
charmInfo,
items,
placement,
...props
}: CharacterCharmsProps) => {
const {
translations: { common },
} = useTranslations()
return (
<Tooltip
aria-label={common.CharacterCard.Tooltips.labels.charms}
content={
<Lister maxLines={MAX_LINES} partialList={items} fullList={tokens} />
}
placement={placement}
>
<S.TitleWrapper {...props}>
<S.Icons.Charm />
Charms: {items.length}/{tokens.length}
{charmInfo && (
<>
{' '}
(
<strong style={{ marginRight: 3 }}>
{formatNumberWithCommas(charmInfo.total)}
</strong>{' '}
total points,
<strong style={{ margin: '0 3px' }}>
{formatNumberWithCommas(charmInfo.unspent)}
</strong>{' '}
unspent)
</>
)}
</S.TitleWrapper>
</Tooltip>
)
}
Example #4
Source File: utils.ts From exevo-pan with The Unlicense | 6 votes |
formatDiffValue = (value: number): string =>
`${getNumberSign(value)}${formatNumberWithCommas(Math.abs(value))}`
Example #5
Source File: TibiaCoin.tsx From exevo-pan with The Unlicense | 6 votes |
TibiaCoin = ({ value, ...props }: TibiaCoinProps) => {
const formattedValue = formatNumberWithCommas(value)
return (
<S.Flex title={`${formattedValue} Tibia Coins`} {...props}>
<Image
src={tibiaCoinSrc}
alt="Tibia Coin"
unoptimized
width={12}
height={12}
/>
{formattedValue}
</S.Flex>
)
}
Example #6
Source File: index.tsx From exevo-pan with The Unlicense | 6 votes |
Scoreboard = ({ guildA, guildB, className, ...props }: ScoreboardProps) => ( <section className={clsx('card p-5 text-center transition-colors', className)} {...props} > <div className="flex flex-col items-center justify-center gap-6 md:flex-row md:gap-[132px] lg:flex-col lg:gap-12"> <GuildSummary guildName={guildA.name} href={guildA.href} displayValue={formatNumberWithCommas(guildA.kills)} diffText={formatDiffValue(guildA.diff)} winning={guildA.kills >= guildB.kills} label="Kills" /> <GuildSummary guildName={guildB.name} href={guildB.href} displayValue={formatNumberWithCommas(guildB.kills)} diffText={formatDiffValue(guildB.diff)} winning={guildB.kills >= guildA.kills} label="Kills" /> </div> </section> )
Example #7
Source File: utils.ts From exevo-pan with The Unlicense | 6 votes |
formatDisplayValue = (value: number): string =>
`${getNumberSign(value)}${formatNumberWithCommas(Math.abs(value))}`
Example #8
Source File: index.tsx From exevo-pan with The Unlicense | 5 votes |
describe('<List />', () => {
test('should render all head content', () => {
const { container } = renderWithProviders(
<List title="Level" charactersList={mockData} displayedDataKey="level" />,
)
expect(screen.getByRole('heading', { name: 'Level' })).toBeInTheDocument()
const [rankingPosition, nickname, value] =
container.querySelectorAll('table thead tr th')
expect(rankingPosition).toHaveAttribute('aria-label', 'Ranking position')
expect(rankingPosition).toHaveTextContent('#')
expect(nickname).toHaveTextContent('Nickname')
expect(value).toHaveTextContent('Level')
})
test('should render every list item', () => {
const { container } = renderWithProviders(
<List title="Level" charactersList={mockData} displayedDataKey="level" />,
)
container.querySelectorAll('table tbody tr').forEach((row, index) => {
const [rankingPosition, nicknameLink, value] = row.querySelectorAll('td')
const currentCharacter = mockData[index]
expect(rankingPosition).toHaveTextContent((index + 1).toString())
expect(nicknameLink).toHaveTextContent(currentCharacter.nickname)
expect(value).toHaveTextContent(
currentCharacter.level as unknown as string,
)
})
})
test('should render every list item with formatted values', () => {
const { container } = renderWithProviders(
<List
title="Level"
charactersList={mockData}
displayedDataKey="level"
format={formatNumberWithCommas}
/>,
)
container.querySelectorAll('table tbody tr').forEach((row, index) => {
const [rankingPosition, nicknameLink, value] = row.querySelectorAll('td')
const currentCharacter = mockData[index]
expect(rankingPosition).toHaveTextContent((index + 1).toString())
expect(nicknameLink).toHaveTextContent(currentCharacter.nickname)
expect(value).toHaveTextContent(
formatNumberWithCommas(currentCharacter.level as unknown as number),
)
})
})
})
Example #9
Source File: index.tsx From exevo-pan with The Unlicense | 5 votes |
HighscoresGrid = ({
statisticsData,
className,
style,
...props
}: HighscoresGridProps) => {
const {
translations: { statistics },
} = useTranslations()
return (
<div
className={clsx('inner-container grid gap-6 py-4', className)}
style={{
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
...style,
}}
{...props}
>
<h2 className="hidden">{statistics.HighscoresGrid.title}</h2>
<List
title={statistics.HighscoresGrid.top10BidTitle}
charactersList={statisticsData.top10Bid}
displayedDataKey="currentBid"
format={useCallback(
(value: number) => `${formatNumberWithCommas(value)} TC`,
[],
)}
/>
<List
title="Level"
charactersList={statisticsData.top10Level}
displayedDataKey="level"
format={formatNumberWithCommas}
/>
<List
title="Magic"
charactersList={statisticsData.top10Magic}
displayedDataKey="magic"
/>
<List
title="Distance"
charactersList={statisticsData.top10Distance}
displayedDataKey="distance"
/>
<List
title="Sword"
charactersList={statisticsData.top10Sword}
displayedDataKey="sword"
/>
<List
title="Axe"
charactersList={statisticsData.top10Axe}
displayedDataKey="axe"
/>
<List
title="Club"
charactersList={statisticsData.top10Club}
displayedDataKey="club"
/>
<List
title="Fist"
charactersList={statisticsData.top10Fist}
displayedDataKey="fist"
/>
<List
title="Shielding"
charactersList={statisticsData.top10Shielding}
displayedDataKey="shielding"
/>
<List
title="Fishing"
charactersList={statisticsData.top10Fishing}
displayedDataKey="fishing"
/>
</div>
)
}
Example #10
Source File: index.tsx From exevo-pan with The Unlicense | 5 votes |
GuildXPGrid = ({ warData }: GuildXPGridProps) => {
const {
translations: { war },
} = useTranslations()
const {
xpStats: { todayDiff, dailyXPDiff, currentXP },
} = warData
return (
<article className="inner-container custom-scrollbar bg-background relative grid max-h-[calc(100%-44px)] gap-4 overflow-auto py-4 transition-colors">
<h2 className="hidden">{war.PageTitle}</h2>
<div className="child:w-full flex flex-wrap gap-4">
<ScoreboardXP
guildA={{
name: 'Libertabra Pune',
todayDiff: todayDiff.guildA,
href: 'https://www.tibia.com/community/?subtopic=guilds&page=view&order=level_desc&GuildName=Libertabra%20Pune&onlyshowonline=0',
}}
guildB={{
name: 'Bones Alliance',
todayDiff: todayDiff.guildB,
href: 'https://www.tibia.com/community/?subtopic=guilds&page=view&order=level_desc&GuildName=Bones%20Alliance&onlyshowonline=0',
}}
/>
<ComparisonChart
title={war.GuildXPGrid.comparisonChartTitle}
guildA={{
name: 'Libertabra Pune',
summaryValue: `${formatNumberWithCommas(
Math.trunc(currentXP.guildA / 1000000),
)}M ${war.GuildXPGrid.guildSummaryValueSuffix}`,
dataArray: xpToDataSnapshot(dailyXPDiff.guildA),
}}
guildB={{
name: 'Bones Alliance',
summaryValue: `${formatNumberWithCommas(
Math.trunc(currentXP.guildB / 1000000),
)}M ${war.GuildXPGrid.guildSummaryValueSuffix}`,
dataArray: xpToDataSnapshot(dailyXPDiff.guildB),
}}
tooltipSuffix={war.GuildXPGrid.comparisonChartSuffix}
dateLabelType="Date"
/>
</div>
</article>
)
}
Example #11
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
CharacterCard = ({
characterData,
highlighted = false,
lazyRender = false,
expandable = false,
past = false,
...props
}: CharacterCardProps) => {
const {
translations: { common },
} = useTranslations()
const {
id,
nickname,
outfitId,
level,
vocationId,
serverData,
transfer,
auctionEnd,
hasBeenBidded,
currentBid,
items,
skills,
imbuements,
charms,
quests,
charmInfo,
preySlot,
} = characterData
const tcInvested = useMemo(
() => formatNumberWithCommas(calculateTotalInvestment(characterData)),
[characterData],
)
const ref = useRef<HTMLDivElement>()
const [isExpanded, setExpanded] = useState(false)
const expandCard = useCallback(() => setExpanded(true), [])
const handleKeyPress = useCallback(
(event: React.KeyboardEvent) => {
if (checkKeyboardTrigger(event.code)) expandCard()
},
[expandCard],
)
return (
<>
<S.Wrapper
ref={ref as React.RefObject<HTMLDivElement>}
highlighted={highlighted}
role={expandable ? 'button' : undefined}
tabIndex={expandable ? 1 : undefined}
aria-label={expandable ? common.CharacterCard.expand : undefined}
onClick={expandable ? expandCard : undefined}
onKeyPress={expandable ? handleKeyPress : undefined}
{...props}
>
<Head
id={id}
outfitId={outfitId}
nickname={nickname}
level={level}
vocationId={vocationId}
serverName={serverData.serverName}
highlighted={highlighted}
>
{highlighted && <TagButton />}
</Head>
<S.Body lazy={lazyRender}>
<S.InfoGrid>
<Textbox.Server
serverData={serverData}
nickname={nickname}
transfer={transfer}
/>
<Textbox.Pvp serverData={serverData} />
<Textbox.AuctionEnd auctionEnd={auctionEnd} past={past} />
<Textbox.AuctionBid
hasBeenBidded={hasBeenBidded}
currentBid={currentBid}
past={past}
/>
</S.InfoGrid>
<CharacterItems items={items} />
<CharacterSkills skills={skills} />
<S.FlexFooter>
<S.FlexColumn>
<ImbuementsTooltip items={imbuements} />
<CharmsTooltip items={charms} />
<QuestsTooltip items={quests} />
</S.FlexColumn>
<S.FlexColumn storeColumn>
<S.Checkbox
label="Charm Expansion"
checked={charmInfo.expansion}
/>
<S.Checkbox label="Prey Slot" checked={preySlot} />
{tcInvested !== '0' && (
<div
className="flex items-center justify-between gap-1.5"
title={`${common.CharacterCard.tcInvested.prefix} ${tcInvested} ${common.CharacterCard.tcInvested.suffix}`}
>
<S.CheckboxContainer>
<S.Icons.TibiaCoin />
</S.CheckboxContainer>
<S.Strong>
{tcInvested} {common.CharacterCard.tcInvested.invested}
</S.Strong>
</div>
)}
</S.FlexColumn>
</S.FlexFooter>
</S.Body>
<SpecialTags character={characterData} />
</S.Wrapper>
{isExpanded && (
<CharacterModal
characterData={characterData}
onClose={() => setExpanded(false)}
past={past}
/>
)}
</>
)
}
Example #12
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
Chart = ({
totalLabel,
yesterdayLabel,
tooltipLabel,
chartData,
className,
...props
}: ChartProps) => {
const {
translations: { statistics, common },
} = useTranslations()
const { colors } = useTheme()
const [dataSize, setDataSize] = useState(DAYS_IN_A_WEEK)
const { current, lastMonth: originalLastMonth } = chartData
const lastMonth = useMemo(
() => fillArrayUntil(originalLastMonth, DAYS_IN_A_MONTH),
[originalLastMonth],
)
const todayValue = lastMonth[lastMonth.length - 1]
const yesterdayValue = lastMonth[lastMonth.length - 2]
const dailyDifference = todayValue - yesterdayValue
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
animation: {
duration: 400,
easing: 'easeOutCubic',
},
elements: {
line: {
tension: 0,
},
},
legend: {
display: false,
},
scales: {
xAxes: [
{
ticks: {
fontColor: colors.onSurface,
},
gridLines: {
display: false,
},
},
],
yAxes: [
{
ticks: {
callback: (value: number) => formatNumberWithCommas(value),
fontColor: colors.onSurface,
},
gridLines: {
color: `${colors.separator}60`,
},
},
],
},
tooltips: {
callbacks: {
title: (tooltipItem: Record<string, string>[]) =>
`Day ${tooltipItem[0].xLabel}`,
label: (tooltipItem: Record<string, number>) =>
`${tooltipLabel}: ${formatNumberWithCommas(tooltipItem.yLabel)} TC`,
},
displayColors: false,
},
}),
[colors, tooltipLabel],
)
const chartDataObject = useMemo(
() => ({
labels: lastMonth
.slice(lastMonth.length - dataSize)
.map((_, index) => {
const date = new Date()
date.setDate(date.getDate() - index)
return `${date.getDate()}/${date.getMonth() + 1}, ${
common.Weekdays[date.getDay()]
}`
})
.reverse(),
datasets: [
{
label: tooltipLabel,
data: lastMonth.slice(lastMonth.length - dataSize),
fill: false,
backgroundColor: colors.primary,
borderColor: colors.primary,
},
],
}),
[colors, tooltipLabel, dataSize, lastMonth],
)
return (
<section
className={clsx(
styles.wrapper,
'card w-full py-5 pr-4 pl-[26px] transition-colors',
className,
)}
{...props}
>
<div className="mb-5 flex items-center gap-12">
<Summary
title={totalLabel}
value={current}
percentage={(todayValue / (current - todayValue)) * 100}
/>
<Summary
title={yesterdayLabel}
value={todayValue}
percentage={(Math.abs(dailyDifference) / yesterdayValue) * 100}
positive={dailyDifference > 0}
/>
</div>
<div className="h-[260px] w-full">
<Line data={chartDataObject} options={options} />
</div>
<div className="mt-[22px] flex gap-2">
<Chip
overrideStatus={dataSize === DAYS_IN_A_MONTH}
onClick={() => setDataSize(DAYS_IN_A_MONTH)}
>
{DAYS_IN_A_MONTH} {statistics.Days}
</Chip>
<Chip
overrideStatus={dataSize === DAYS_IN_A_WEEK}
onClick={() => setDataSize(DAYS_IN_A_WEEK)}
>
{DAYS_IN_A_WEEK} {statistics.Days}
</Chip>
</div>
</section>
)
}
Example #13
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
ComparisonChart = ({
guildA,
guildB,
tooltipSuffix,
dateLabelType,
className,
...props
}: ComparisonChartProps) => {
const {
translations: { common },
} = useTranslations()
const { colors } = useTheme()
const formatDateLabel = useCallback(
(timestamp: number, formatType: 'Time' | 'Date'): string => {
const currentDate = new Date(timestamp)
switch (formatType) {
case 'Time': {
const hours = currentDate.getHours().toString().padStart(2, '0')
const minutes = currentDate.getMinutes().toString().padStart(2, '0')
return `${hours}:${minutes}h`
}
case 'Date': {
const day = currentDate.getDate().toString()
const month = currentDate.getMonth() + 1
const weekday = currentDate.getDay()
return `${day}/${month}, ${common.Weekdays[weekday]}`
}
default:
return currentDate.toLocaleString()
}
},
[common],
)
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
animation: {
duration: 400,
easing: 'easeOutCubic',
},
elements: {
line: {
tension: 0,
},
},
legend: {
display: false,
},
scales: {
xAxes: [
{
ticks: {
fontColor: colors.onSurface,
},
gridLines: {
display: false,
},
},
],
yAxes: [
{
ticks: {
fontColor: colors.onSurface,
callback: (value: number) => compactNumberFormatter(value),
},
gridLines: {
color: `${colors.separator}60`,
},
},
],
displayColors: false,
},
tooltips: {
callbacks: {
label: (tooltipItem: Record<string, number>) =>
`${formatNumberWithCommas(tooltipItem.value)} ${tooltipSuffix}`,
},
displayColors: false,
},
}),
[colors],
)
const chartDataObject = useMemo(
() => ({
labels: guildA.dataArray.map((snapshot) =>
formatDateLabel(snapshot.timeStamp, dateLabelType),
),
datasets: [
{
label: guildA.name,
data: guildA.dataArray.map((snapshot) => snapshot.value),
fill: false,
backgroundColor: colorA,
borderColor: colorA,
},
{
label: guildB.name,
data: guildB.dataArray.map((snapshot) => snapshot.value),
fill: false,
backgroundColor: colorB,
borderColor: colorB,
},
],
}),
[colors, guildA],
)
return (
<section
className={clsx(
styles.wrapper,
'card h-[500px] pt-5 pr-4 pb-[86px] pl-[26px] transition-colors',
className,
)}
{...props}
>
<div className="child:text-onSurface mb-5 flex gap-6 md:gap-9">
<div style={{ color: colorA }}>
<GuildName>{guildA.name}</GuildName>
<OnlineCount>{guildA.summaryValue}</OnlineCount>
</div>
<div style={{ color: colorB }}>
<GuildName>{guildB.name}</GuildName>
<OnlineCount>{guildB.summaryValue}</OnlineCount>
</div>
</div>
<Line data={chartDataObject} options={options} />
</section>
)
}
Example #14
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
describe('<CharacterCard />', () => {
test.each(characterList)('should write every info correctly', (character) => {
renderWithProviders(<CharacterCard characterData={character} />)
expect(screen.getByText(character.nickname)).toBeInTheDocument()
expect(
screen.getByText(
`Level ${character.level} - ${vocation.getFullName(
character.vocationId,
character.level,
)}`,
),
).toBeInTheDocument()
expect(
screen.getByAltText(character.serverData.serverLocation.string),
).toBeInTheDocument()
expect(
screen.getByText(character.serverData.serverName),
).toBeInTheDocument()
expect(
screen.getByLabelText(
character.transfer
? 'Regular World Transfer available'
: 'Regular World Transfer NOT available',
),
).toBeInTheDocument()
expect(
screen.getByText(character.serverData.pvpType.string),
).toBeInTheDocument()
expect(
screen.getByText(character.hasBeenBidded ? 'Current Bid' : 'Minimum Bid'),
).toBeInTheDocument()
expect(
screen.getByText(formatNumberWithCommas(character.currentBid)),
).toBeInTheDocument()
expect(screen.queryAllByAltText('Featured item')).toHaveLength(
character.items.length,
)
character.items.forEach((itemId) => {
const [, tier] = itemId.toString().split('.')
if (tier) {
const [first] = screen.queryAllByTitle(`tier ${tier}`)
expect(first).toBeInTheDocument()
}
})
expect(
screen.getByText(
`Imbuements: ${character.imbuements.length}/${imbuement.tokens.length}`,
),
).toBeInTheDocument()
expect(
screen.getByText(
`Charms: ${character.charms.length}/${charm.tokens.length}`,
),
).toBeInTheDocument()
expect(
screen.getByText(
`Quests: ${character.quests.length}/${quest.tokens.length}`,
),
).toBeInTheDocument()
const charmCheckbox = screen.getByRole('checkbox', {
name: 'Charm Expansion',
})
if (character.charmInfo.expansion) {
expect(charmCheckbox).toBeChecked()
} else {
expect(charmCheckbox).not.toBeChecked()
}
const preyCheckbox = screen.getByRole('checkbox', {
name: 'Prey Slot',
})
if (character.preySlot) {
expect(preyCheckbox).toBeChecked()
} else {
expect(preyCheckbox).not.toBeChecked()
}
const totalInvestment = formatNumberWithCommas(
calculateTotalInvestment(character),
)
if (totalInvestment === '0') {
expect(screen.queryByText(totalInvestment)).not.toBeInTheDocument()
} else {
expect(
screen.getByText(totalInvestment, { exact: false }),
).toBeInTheDocument()
}
})
test.each(characterList)(
`should render a different bid label for ${routes.BAZAAR_HISTORY} route`,
(character) => {
renderWithProviders(<CharacterCard characterData={character} past />)
expect(
screen.getByText(
character.hasBeenBidded ? 'Auction Successful' : 'Auction Failed',
),
).toBeInTheDocument()
},
)
test.each(characterList)(
`should render highlighted card correctly`,
(character) => {
renderWithProviders(
<CharacterCard characterData={character} highlighted />,
)
expect(screen.getByText('Highlight your auction!')).toBeInTheDocument()
},
)
test('the character card should be able to be expanded', () => {
const [character] = characterList
renderWithProviders(<CharacterCard characterData={character} expandable />)
const expandButton = screen.getByRole('button', {
name: 'Expand for full auction details',
})
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
userEvent.click(expandButton)
expect(screen.getByRole('dialog')).toBeInTheDocument()
userEvent.click(screen.getByRole('button', { name: 'Close dialog' }))
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
})
Example #15
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
CharacterModal = ({
characterData,
onClose,
past = false,
}: CharacterModalProps) => {
const {
id,
sex,
outfitId,
nickname,
level,
vocationId,
serverData,
transfer,
auctionEnd,
hasBeenBidded,
currentBid,
items,
skills,
hirelings,
charmInfo,
preySlot,
huntingSlot,
storeItems,
imbuements,
charms,
quests,
outfits,
mounts,
storeOutfits,
storeMounts,
achievementPoints,
} = characterData
const {
translations: { common },
} = useTranslations()
const checkboxRecords = useMemo(() => checkStore(storeItems), [])
const tcInvested = useMemo(
() => formatNumberWithCommas(calculateTotalInvestment(characterData)),
[characterData],
)
const tabRef = useRef<HTMLDivElement>(null)
const isDesktop = useIsDesktop()
const handleTabChange = useCallback(() => {
if (!isDesktop) {
tabRef.current?.scrollIntoView({
block: 'start',
})
}
}, [isDesktop])
return (
<Dialog
isOpen
onClose={onClose}
className={clsx(
styles.wrapper,
'w-full max-w-[var(--cardMaxMobileWidth)] p-[var(--lateralMargin)] outline-none md:w-fit md:max-w-[calc(100%-80px)]',
)}
>
<Head
id={id}
outfitId={outfitId}
nickname={nickname}
level={level}
vocationId={vocationId}
serverName={serverData.serverName}
/>
<div className="custom-scrollbar -mx-[var(--lateralMargin)] h-[var(--gridMobileHeight)] overflow-y-auto px-[var(--lateralMargin)] md:h-[var(--cardFixedHeight)]">
<S.Spacer className="w-full md:flex md:gap-6">
<S.Spacer className="md:z-4 h-fit pt-1.5 md:sticky md:top-0 md:min-w-[280px] md:max-w-fit md:shrink-0">
<InfoGrid>
<Textbox.Server
serverData={serverData}
nickname={nickname}
transfer={transfer}
placement="bottom"
/>
<Textbox.Pvp serverData={serverData} />
<Textbox.AuctionEnd auctionEnd={auctionEnd} past={past} />
<Textbox.AuctionBid
hasBeenBidded={hasBeenBidded}
currentBid={currentBid}
past={past}
/>
</InfoGrid>
<CharacterItems items={items} />
<S.Section border>
<CharacterSkills skills={skills} />
</S.Section>
<S.TooltipSection>
<ImbuementsTooltip placement="top-start" items={imbuements} />
<CharmsTooltip
placement="top-start"
items={charms}
charmInfo={charmInfo}
/>
<QuestsTooltip placement="top-start" items={quests} />
<Hirelings hirelingsInfo={hirelings} />
<Achievements achievementPoints={achievementPoints} />
</S.TooltipSection>
</S.Spacer>
<S.Spacer className="h-fit w-full">
<S.Section border className="z-3">
<div
title={`${common.CharacterCard.tcInvested.prefix} ${tcInvested} ${common.CharacterCard.tcInvested.suffix}`}
className="text-tsm flex items-center gap-[5px]"
>
<Icons.TibiaCoin />{' '}
{common.CharacterCard.CharacterModal.totalInvested}:{' '}
<strong
className={clsx(
tcInvested === '0'
? 'font-normal'
: 'text-primaryHighlight',
)}
>
{tcInvested} Tibia Coins
</strong>
</div>
<div className="grid grid-flow-col grid-rows-3 gap-2 md:max-w-[400px]">
<Checkbox
label="Training Dummy"
checked={checkboxRecords.dummy}
/>
<Checkbox
label="Gold pouch"
checked={checkboxRecords.goldPouch}
/>
<Checkbox label="Hirelings" checked={hirelings.count > 0} />
<Checkbox
label="Charm expansion"
checked={charmInfo.expansion}
/>
<Checkbox label="Prey Slot" checked={preySlot} />
<Checkbox label="Hunting Task Slot" checked={huntingSlot} />
<Checkbox
label="Imbuement Shrine"
checked={checkboxRecords.imbuementShrine}
/>
<Checkbox
label="Reward Shrine"
checked={checkboxRecords.rewardShrine}
/>
<Checkbox label="Mailbox" checked={checkboxRecords.mailbox} />
</div>
</S.Section>
<Tabs.Group
className="min-h-[var(--gridMobileHeight)] md:min-h-[unset]"
style={{ display: 'block', overflow: 'unset' }}
onChange={handleTabChange}
ref={tabRef}
>
<Tabs.Panel
label={
<>
<OutfitIcon />
Outfits {tabCounter(outfits.length, storeOutfits.length)}
</>
}
>
<S.SpriteSection>
{outfits.map(({ name, type }) => (
<SpriteBox
key={name}
offset
auctionId={id}
name={name}
sex={sex}
src={resolvers.outfit(name, sex, type)}
type={type}
checkRareOutfit
/>
))}
</S.SpriteSection>
{storeOutfits.length > 0 && (
<>
<S.SpriteSectionDivisor>
Store outfits ({storeOutfits.length})
</S.SpriteSectionDivisor>
<S.SpriteSection>
{storeOutfits.map(({ name, type }) => (
<SpriteBox
key={name}
offset
auctionId={id}
name={name}
sex={sex}
src={resolvers.storeOutfit(name, sex, type)}
/>
))}
</S.SpriteSection>
</>
)}
</Tabs.Panel>
{mounts.length + storeMounts.length > 0 && (
<Tabs.Panel
label={
<>
<MountIcon />
Mounts {tabCounter(mounts.length, storeMounts.length)}
</>
}
>
<S.SpriteSection>
{mounts.map((name) => (
<SpriteBox
key={name}
offset
auctionId={id}
name={name}
sex={sex}
src={resolvers.mount(name)}
checkRareMount
/>
))}
</S.SpriteSection>
{storeMounts.length > 0 && (
<>
<S.SpriteSectionDivisor>
Store mounts ({storeMounts.length})
</S.SpriteSectionDivisor>
<S.SpriteSection>
{storeMounts.map((name) => (
<SpriteBox
key={name}
offset
auctionId={id}
name={name}
sex={sex}
src={resolvers.storeMount(name)}
/>
))}
</S.SpriteSection>
</>
)}
</Tabs.Panel>
)}
{storeItems.length > 0 && (
<Tabs.Panel
label={
<>
<StoreIcon />
Store Items ({storeItems.length})
</>
}
>
<S.SpriteSection>
{storeItems.map(({ name, amount }, childIndex) => (
<SpriteBox
// eslint-disable-next-line react/no-array-index-key
key={`${childIndex}-${name}`}
auctionId={id}
name={name}
amount={amount}
sex={sex}
src={resolvers.storeItem(name)}
/>
))}
</S.SpriteSection>
</Tabs.Panel>
)}
</Tabs.Group>
</S.Spacer>
</S.Spacer>
</div>
</Dialog>
)
}
Example #16
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
describe('<CharacterModal />', () => {
beforeEach(() => {
mockedFetch.mockClear()
scrollIntoViewMock.mockClear()
mockOnClose.mockClear()
setup.setTimeout()
})
test.each(characterList)(
'should render every element correctly',
(character) => {
const {
outfits,
storeOutfits,
mounts,
storeMounts,
storeItems,
charms,
charmInfo,
hirelings,
achievementPoints,
} = character
renderWithProviders(
<CharacterModal characterData={character} onClose={mockOnClose} />,
)
const totalInvestment = formatNumberWithCommas(
calculateTotalInvestment(character),
)
if (totalInvestment === '0') {
expect(screen.queryByText(totalInvestment)).not.toBeInTheDocument()
} else {
expect(
screen.getByText(`${totalInvestment} Tibia Coins`, { exact: false }),
).toBeInTheDocument()
}
expect(
screen.getByText(
`Outfits ${tabCounter(outfits.length, storeOutfits.length)}`,
{ exact: false },
),
).toBeInTheDocument()
expect(
screen.getByText(
`Mounts ${tabCounter(mounts.length, storeMounts.length)}`,
{ exact: false },
),
).toBeInTheDocument()
if (storeItems.length > 0) {
expect(
screen.getByText(`Store Items (${storeItems.length})`, {
exact: false,
}),
).toBeInTheDocument()
} else {
expect(
screen.queryByText(`Store Items (${storeItems.length})`, {
exact: false,
}),
).not.toBeInTheDocument()
}
expect(screen.getByText('Charms:', { exact: false }).textContent).toEqual(
`Charms: ${charms.length}/19 (${formatNumberWithCommas(
charmInfo.total,
)} total points,${formatNumberWithCommas(charmInfo.unspent)} unspent)`,
)
expect(
screen.getByText('Hirelings:', { exact: false }).textContent,
).toEqual(
`Hirelings: ${hirelings.count} (${hirelings.jobs}/4 jobs, ${hirelings.outfits} outfits)`,
)
expect(
screen.getByText(
`Achievement points: ${formatNumberWithCommas(achievementPoints)}`,
{
exact: false,
},
),
).toBeInTheDocument()
},
)
test('if a sprite is not found, it should call `NotifyErrorClient`', async () => {
const [character] = characterList
const { rerender } = renderWithProviders(
<CharacterModal
characterData={{ ...character, storeMounts: [] }}
onClose={mockOnClose}
/>,
)
expect(mockedFetch).toHaveBeenCalledTimes(0)
rerender(
<CharacterModal
characterData={{
...character,
storeMounts: ['weird mount'],
}}
onClose={mockOnClose}
/>,
)
await waitFor(() => expect(mockedFetch).toHaveBeenCalledTimes(1))
})
test('should call `onClose` handler', () => {
const [character] = characterList
renderWithProviders(
<CharacterModal characterData={character} onClose={mockOnClose} />,
)
expect(mockOnClose).toHaveBeenCalledTimes(0)
userEvent.click(screen.getByRole('button', { name: 'Close dialog' }))
expect(mockOnClose).toHaveBeenCalledTimes(1)
})
test('should be tabbable', () => {
const [character] = characterList
renderWithProviders(
<CharacterModal characterData={character} onClose={mockOnClose} />,
)
const [tab1, tab2] = screen.getAllByRole('tab')
expect(scrollIntoViewMock).toHaveBeenCalledTimes(0)
expect(tab1).toHaveAttribute('aria-selected', 'true')
expect(tab2).toHaveAttribute('aria-selected', 'false')
userEvent.click(tab2)
expect(tab1).toHaveAttribute('aria-selected', 'false')
expect(tab2).toHaveAttribute('aria-selected', 'true')
expect(scrollIntoViewMock).toHaveBeenCalledTimes(1)
})
})
Example #17
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
SpriteBox = ({
auctionId,
offset = false,
name,
sex,
src,
type,
amount = 0,
checkRareMount = false,
checkRareOutfit = false,
}: SpriteBoxProps) => {
const {
translations: { common },
} = useTranslations()
const isRareMount = checkRareMount ? rareMountSet.has(name) : false
const isRareOutfit =
checkRareOutfit && type ? testRareOutfit({ name, type, sex }) : false
const isRare = isRareMount || isRareOutfit
const showAddon = type !== undefined
const notifyError = useCallback(
() => NotifyErrorClient.setMessage({ auctionId, name, src }),
[auctionId, name, src],
)
return (
<div
title={amount > 1 ? `${formatNumberWithCommas(amount)}x ${name}` : name}
className={clsx(
'relative rounded-md',
showAddon && 'pb-2 shadow',
isRare ? 'bg-primary' : 'bg-primaryVariant',
isRare && styles.highlighted,
)}
>
<SpritePortrait
offset={offset}
alt={name}
src={src}
width={offset ? 64 : 32}
height={offset ? 64 : 32}
onError={notifyError}
className="pointer-events-none"
style={showAddon ? { boxShadow: 'unset' } : undefined}
/>
{showAddon && (
<div className="flex justify-evenly">
<Checkbox
aria-label={
common.CharacterCard.CharacterModal.SpriteBox.firstAddon
}
checked={addonCheck.first(type ?? 0)}
greenVariant={isRare}
/>
<Checkbox
aria-label={
common.CharacterCard.CharacterModal.SpriteBox.secondAddon
}
checked={addonCheck.second(type ?? 0)}
greenVariant={isRare}
/>
</div>
)}
{amount > 1 && (
<ActiveCount
className="z-1 absolute -top-1.5 -right-1.5 py-0.5 px-1 font-bold after:ml-[1px] after:font-normal after:content-['x']"
style={{
width: 'unset',
height: 'unset',
borderRadius: '4px',
}}
>
{amount}
</ActiveCount>
)}
</div>
)
}