Skip to content

Commit a957ccd

Browse files
authored
Helper component for card properties (#820)
* Helper component for card properties * Improve * Add dedicated ErrorBoundary for CardDetail
1 parent 780b2c1 commit a957ccd

File tree

2 files changed

+31
-60
lines changed

2 files changed

+31
-60
lines changed

frontend/src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ function App() {
105105
<RouterProvider router={router} />
106106
<InstallPrompt />
107107
<DonationPopup />
108-
<CardDetail />
108+
<ErrorBoundary fallback={null} onError={() => toast({ variant: 'destructive', description: 'Failed opening card details.' })}>
109+
<CardDetail />
110+
</ErrorBoundary>
109111
{/* Add React Query DevTools (only in development) */}
110112
{process.env.NODE_ENV === 'development' && <ReactQueryDevtools initialIsOpen={false} />}
111113
</DialogContext.Provider>

frontend/src/pages/collection/CardDetail.tsx

Lines changed: 28 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import i18n from 'i18next'
22
import { CircleHelp } from 'lucide-react'
3-
import { useEffect, useState } from 'react'
3+
import { type ReactNode, useEffect, useState } from 'react'
44
import { useTranslation } from 'react-i18next'
55
import { Tooltip } from 'react-tooltip'
66
import { Card as CardComponent } from '@/components/Card'
@@ -15,7 +15,16 @@ import { getCardNameByLang } from '@/lib/utils'
1515
import { useCollection, useDeleteCard, useSelectedCard } from '@/services/collection/useCollection'
1616
import type { Card, CollectionRow } from '@/types'
1717

18-
function CardDetail() {
18+
function CardProperty({ name, children }: { name: string; children: ReactNode }) {
19+
return (
20+
<p className="flex">
21+
<strong className="block min-w-[175px]">{name}</strong>
22+
{children}
23+
</p>
24+
)
25+
}
26+
27+
export default function CardDetail() {
1928
const { t } = useTranslation(['pages/card-detail', 'common/types', 'common/packs', 'common/sets'])
2029
const { selectedCardId: id, setSelectedCardId: setId } = useSelectedCard()
2130

@@ -128,61 +137,23 @@ function CardDetail() {
128137
)}
129138
</div>
130139

131-
<p className="mt-8 flex">
132-
<strong className="block min-w-[175px]">{t('text.expansion')}</strong> {card?.expansion}
133-
</p>
134-
<p className="mt-1 flex">
135-
<strong className="block min-w-[175px]">{t('text.pack')}</strong> {card && t(`${card.pack}`, { ns: 'common/packs' })}
136-
</p>
137-
138-
<p className="mt-1 flex">
139-
<strong className="block min-w-[175px]">Energy</strong> {card?.energy}
140-
</p>
141-
<p className="mt-1 flex">
142-
<strong className="block min-w-[175px]">{t('text.weakness')}</strong> {(card && t(`${card.weakness}`, { ns: 'common/types' })) || 'N/A'}
143-
</p>
144-
{card?.hp && (
145-
<p className="mt-1 flex">
146-
<strong className="block min-w-[175px]">{t('text.hp')}</strong> {card?.hp}
147-
</p>
148-
)}
149-
{card?.retreat && (
150-
<p className="mt-1 flex">
151-
<strong className="block min-w-[175px]">{t('text.retreat')}</strong> {card.retreat}
152-
</p>
153-
)}
154-
155-
<p className="mt-1 flex">
156-
<strong className="block min-w-[175px]">{t('text.ability')}</strong> {card?.ability?.name ?? <i>None</i>}
157-
</p>
158-
{card?.ability && (
159-
<p className="mt-1 flex">
160-
<strong className="block min-w-[175px]">{t('text.abilityEffect')}</strong> {card?.ability.effect}
161-
</p>
162-
)}
163-
164-
<p className="mt-1 flex">
165-
<strong className="block min-w-[175px]">{t('text.cardType')}</strong> {card && t(`cardType.${card.card_type}`)}
166-
</p>
167-
<p className="mt-1 flex">
168-
<strong className="block min-w-[175px]">{t('text.evolutionType')}</strong> {card && t(`evolutionType.${card.evolution_type}`)}
169-
</p>
170-
171-
{expansion && packName && (
172-
<p className="mt-1 flex">
173-
<strong className="block min-w-[175px]">{t('text.chanceToPull', { ns: 'pages/card-detail' })}</strong>
174-
{card && pullRateForSpecificCard(expansion, packName, card).toFixed(2)}%
175-
</p>
176-
)}
177-
{card && craftingCost[card.rarity] && (
178-
<p className="mt-1 flex">
179-
<strong className="block min-w-[175px]">{t('text.craftingCost')}</strong> {craftingCost[card.rarity]}
180-
</p>
181-
)}
182-
183-
<p className="mt-1 flex">
184-
<strong className="block min-w-[175px]">{t('text.artist')}</strong> {card?.artist}
185-
</p>
140+
<div className="mt-8">
141+
<CardProperty name={t('text.expansion')}>{card?.expansion}</CardProperty>
142+
<CardProperty name={t('text.pack')}>{card && t(card.pack, { ns: 'common/packs' })}</CardProperty>
143+
<CardProperty name="Energy">{card?.energy}</CardProperty>
144+
<CardProperty name={t('text.weakness')}>{(card && t(card.weakness, { ns: 'common/types' })) || 'N/A'}</CardProperty>
145+
{card?.hp && <CardProperty name={t('text.hp')}>{card?.hp}</CardProperty>}
146+
{card?.retreat && <CardProperty name={t('text.retreat')}>{card.retreat}</CardProperty>}
147+
<CardProperty name={t('text.ability')}>{card?.ability?.name ?? <i>None</i>}</CardProperty>
148+
{card?.ability && <CardProperty name={t('text.abilityEffect')}>{card?.ability.effect}</CardProperty>}
149+
<CardProperty name={t('text.cardType')}>{card && t(`cardType.${card.card_type}`)}</CardProperty>
150+
<CardProperty name={t('text.evolutionType')}>{card && t(`evolutionType.${card.evolution_type}`)}</CardProperty>
151+
{expansion && packName && card && card.rarity !== 'P' && (
152+
<CardProperty name={t('text.chanceToPull')}>{card && pullRateForSpecificCard(expansion, packName, card).toFixed(2)}%</CardProperty>
153+
)}
154+
{card && craftingCost[card.rarity] && <CardProperty name={t('text.craftingCost')}>{craftingCost[card.rarity]}</CardProperty>}
155+
<CardProperty name={t('text.artist')}>{card?.artist}</CardProperty>
156+
</div>
186157

187158
{!!row?.collection?.length && (
188159
<>
@@ -217,5 +188,3 @@ function CardDetail() {
217188
</Sheet>
218189
)
219190
}
220-
221-
export default CardDetail

0 commit comments

Comments
 (0)