Skip to content
Merged
Show file tree
Hide file tree
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
11 changes: 9 additions & 2 deletions frontend/public/locales/de-DE/filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"sortBy": "Sortiere nach",
"default": "Kartennummer",
"recent": "Zuletzt hinzugefügt",
"expansion-newest": "Neueste Erweiterung"
"expansion-newest": "Neueste Erweiterung",
"rarity": "Rarity",
"type": "Type"
},
"f-number": {
"numberCards": "Anzahl der gesuchten Karten",
Expand All @@ -22,5 +24,10 @@
"extra": "For trade"
},
"carddex": "Card Dex",
"trading": "Trading"
"trading": "Trading",
"f-owned": {
"all": "All",
"owned": "Owned",
"missing": "Missing"
}
}
4 changes: 3 additions & 1 deletion frontend/public/locales/de-DE/pages/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"missionDetail": {
"eligibleCards-singular": "Liste der berechtigten Karten: {{options}} option",
"eligibleCards-plural": "Liste der berechtigten Karten: {{options}} optionen",
"chanceFrom": "Wahrscheinlichkeit aus {{pack}}: {{chance}}%"
"chanceFrom": "Wahrscheinlichkeit aus {{pack}}: {{chance}}%",
"manuallyMarkedComplete": "Manually marked as completed",
"manuallyMarkComplete": "Manually mark as complete"
},
"filters": {
"allFilters": "Alle Filter",
Expand Down
7 changes: 4 additions & 3 deletions frontend/public/locales/en-US/filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
},
"f-sortBy": {
"sortBy": "Sort By",
"default": "Card ID",
"recent": "Recently updated",
"expansion-newest": "Expansion newest first"
"expansion-newest": "Expansion newest first",
"rarity": "Rarity",
"type": "Type",
"recent": "Recently updated"
},
"f-number": {
"numberCards": "Number of cards wanted",
Expand Down
11 changes: 9 additions & 2 deletions frontend/public/locales/es-ES/filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"sortBy": "Ordenar Por",
"default": "ID de tarjeta",
"recent": "Última actualización",
"expansion-newest": "Expansion newest first"
"expansion-newest": "Expansion newest first",
"rarity": "Rarity",
"type": "Type"
},
"f-number": {
"numberCards": "Número de cartas deseadas",
Expand All @@ -22,5 +24,10 @@
"registered": "Registered"
},
"carddex": "Card Dex",
"trading": "Trading"
"trading": "Trading",
"f-owned": {
"all": "All",
"owned": "Owned",
"missing": "Missing"
}
}
4 changes: 3 additions & 1 deletion frontend/public/locales/es-ES/pages/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"missionDetail": {
"eligibleCards-singular": "List of eligible cards: {{options}} option",
"eligibleCards-plural": "List of eligible cards: {{options}} options",
"chanceFrom": "Chance from {{pack}}: {{chance}}%"
"chanceFrom": "Chance from {{pack}}: {{chance}}%",
"manuallyMarkedComplete": "Manually marked as completed",
"manuallyMarkComplete": "Manually mark as complete"
},
"filters": {
"allFilters": "All filters",
Expand Down
11 changes: 9 additions & 2 deletions frontend/public/locales/fr-FR/filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"sortBy": "Trier par",
"default": "ID de carte",
"recent": "Mise à jour récemment",
"expansion-newest": "Plus récent en premier"
"expansion-newest": "Plus récent en premier",
"rarity": "Rarity",
"type": "Type"
},
"f-number": {
"numberCards": "Nombre d'exemplaire voulu",
Expand All @@ -22,5 +24,10 @@
"registered": "Obtenues"
},
"carddex": "Card Dex",
"trading": "Échanges"
"trading": "Échanges",
"f-owned": {
"all": "All",
"owned": "Owned",
"missing": "Missing"
}
}
4 changes: 3 additions & 1 deletion frontend/public/locales/fr-FR/pages/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"missionDetail": {
"eligibleCards-singular": "Liste des cartes éligibles : {{options}} option",
"eligibleCards-plural": "Liste des cartes éligibles : {{options}} options",
"chanceFrom": "Chance dans {{pack}} : {{chance}}%"
"chanceFrom": "Chance dans {{pack}} : {{chance}}%",
"manuallyMarkedComplete": "Manually marked as completed",
"manuallyMarkComplete": "Manually mark as complete"
},
"filters": {
"allFilters": "Tous les filtres",
Expand Down
11 changes: 9 additions & 2 deletions frontend/public/locales/it-IT/filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"sortBy": "Sort By",
"default": "Card ID",
"recent": "Recently updated",
"expansion-newest": "Expansion newest first"
"expansion-newest": "Expansion newest first",
"rarity": "Rarity",
"type": "Type"
},
"f-trading": {
"all": "All",
Expand All @@ -22,5 +24,10 @@
"registered": "Registered"
},
"carddex": "Card Dex",
"trading": "Trading"
"trading": "Trading",
"f-owned": {
"all": "All",
"owned": "Owned",
"missing": "Missing"
}
}
4 changes: 3 additions & 1 deletion frontend/public/locales/it-IT/pages/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"missionDetail": {
"eligibleCards-singular": "Elenco delle carte idonee: {{options}} opzione",
"eligibleCards-plural": "Elenco delle carte idonee: {{options}} opzioni",
"chanceFrom": "Probabilità da {{pack}}: {{chance}}%"
"chanceFrom": "Probabilità da {{pack}}: {{chance}}%",
"manuallyMarkedComplete": "Manually marked as completed",
"manuallyMarkComplete": "Manually mark as complete"
},
"filters": {
"allFilters": "Tutti i filtri",
Expand Down
11 changes: 9 additions & 2 deletions frontend/public/locales/pt-BR/filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"sortBy": "Sort By",
"default": "Card ID",
"recent": "Recently updated",
"expansion-newest": "Expansion newest first"
"expansion-newest": "Expansion newest first",
"rarity": "Rarity",
"type": "Type"
},
"f-trading": {
"all": "All",
Expand All @@ -22,5 +24,10 @@
"registered": "Registered"
},
"carddex": "Card Dex",
"trading": "Trading"
"trading": "Trading",
"f-owned": {
"all": "All",
"owned": "Owned",
"missing": "Missing"
}
}
4 changes: 3 additions & 1 deletion frontend/public/locales/pt-BR/pages/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"missionDetail": {
"eligibleCards-singular": "List of eligible cards: {{options}} option",
"eligibleCards-plural": "List of eligible cards: {{options}} options",
"chanceFrom": "Chance from {{pack}}: {{chance}}%"
"chanceFrom": "Chance from {{pack}}: {{chance}}%",
"manuallyMarkedComplete": "Manually marked as completed",
"manuallyMarkComplete": "Manually mark as complete"
},
"filters": {
"allFilters": "All filters",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function Card({ card, onImageClick, className, editable = true }: CardPro
</button>
<p
className="w-full min-w-0 text-[12px] pt-2 text-center font-semibold leading-tight"
title={card.updated_at ? `Last update ${new Date(card.updated_at).toLocaleString()}` : undefined}
title={card.updated_at ? `Last update ${card.updated_at.toLocaleString()}` : undefined}
>
<span className="block md:inline">{card.card_id}</span>
<span className="hidden md:inline"> – </span>
Expand Down
28 changes: 21 additions & 7 deletions frontend/src/components/FiltersPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Slot } from '@radix-ui/react-slot'
import { ArrowDownAZ, ArrowUpAZ } from 'lucide-react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import RarityFilter from '@/components/filters/RarityFilter.tsx'
Expand Down Expand Up @@ -91,13 +93,25 @@ const FilterPanel: FC<Props> = ({ className, filters, setFilters, clearFilters }
/>
)}
{filters.sortBy !== undefined && (
<DropdownFilter
label={t('f-sortBy.sortBy', { ns: 'filters' })}
options={sortByOptions}
value={filters.sortBy}
onChange={changeFilter('sortBy')}
show={(x) => t(`f-sortBy.${x}`, { ns: 'filters' })}
/>
<div className="flex gap-2">
<DropdownFilter
className="flex-1"
label={t('f-sortBy.sortBy', { ns: 'filters' })}
options={sortByOptions}
value={filters.sortBy}
onChange={changeFilter('sortBy')}
show={(x) => t(`f-sortBy.${x}`, { ns: 'filters' })}
/>
{filters.sortDesc !== undefined && (
<button
type="button"
onClick={() => setFilters({ sortDesc: !filters.sortDesc })}
className="group h-auto aspect-square bg-neutral-800 hover:bg-neutral-600 rounded-md border border-neutral-700 flex items-center justify-center"
>
<Slot className="stroke-neutral-400 group-hover:stroke-neutral-300">{filters.sortDesc ? <ArrowUpAZ /> : <ArrowDownAZ />}</Slot>
</button>
)}
</div>
)}
{filters.minNumber !== undefined && (
<DropdownFilter
Expand Down
47 changes: 27 additions & 20 deletions frontend/src/lib/filters.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import i18n from '@/i18n'
import { type CollectionRow, cardTypes, expansionIds, type Rarity, type RaritySettingsRow } from '@/types'
import { type Card, type CollectionRow, cardTypes, expansionIds, type Rarity, type RaritySettingsRow } from '@/types'
import { allCards, getCardByInternalId } from './CardsDB'
import { levenshtein } from './levenshtein'
import { getCardNameByLang, getExtraCards, getNeededCards } from './utils'

export const expansionOptions = ['all', ...expansionIds] as const
export const sortByOptions = ['expansion-newest', 'recent'] as const
export const sortByOptions = ['expansion-newest', 'rarity', 'type', 'recent'] as const
export const cardTypeOptions = cardTypes
export const ownershipOptions = ['all', 'missing', 'registered'] as const
export const tradingOptions = ['all', 'wanted', 'extra'] as const
Expand All @@ -24,13 +24,34 @@ export interface FiltersAll {
ownership: OwnershipOptions
trading: TradingOption
sortBy: SortByOption
sortDesc: boolean
minNumber: number
maxNumber: number | '∞'
deckbuildingMode: boolean
allTextSearch: boolean
}
export type Filters = Partial<FiltersAll>

const sortComparators: Record<SortByOption, (a: Card, b: Card) => number> = {
'expansion-newest': (a, b) => {
if (a.expansion !== b.expansion) {
return expansionIds.indexOf(a.expansion) - expansionIds.indexOf(b.expansion)
}
return a.card_id.localeCompare(b.card_id, i18n.language || 'en', { numeric: true })
},
rarity: (a, b) => (a.internal_id & 63) - (b.internal_id & 63),
type: (a, b) => cardTypeOptions.indexOf(a.energy) - cardTypeOptions.indexOf(b.energy),
recent: (a, b) => {
if (a.updated_at && b.updated_at) {
return b.updated_at.getTime() - a.updated_at.getTime()
} else if (a.updated_at && !b.updated_at) {
return -1
} else {
return 1
}
},
}

export function getFilteredCards(filters: Filters, cards: Map<number, CollectionRow>, tradingSettings?: RaritySettingsRow[]) {
let filteredCards = allCards

Expand Down Expand Up @@ -114,24 +135,10 @@ export function getFilteredCards(filters: Filters, cards: Map<number, Collection
}

if (filters.sortBy !== undefined) {
if (filters.sortBy === 'recent') {
filteredCards.sort((a, b) => {
if (a.updated_at && b.updated_at) {
return new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
} else if (a.updated_at && !b.updated_at) {
return -1
} else {
return 1
}
})
} else if (filters.sortBy === 'expansion-newest') {
filteredCards.sort((a, b) => {
if (a.expansion !== b.expansion) {
return expansionIds.indexOf(a.expansion) - expansionIds.indexOf(b.expansion)
}
return a.card_id.localeCompare(b.card_id, i18n.language || 'en', { numeric: true })
})
}
filteredCards.sort(sortComparators[filters.sortBy])
}
if (filters.sortDesc) {
filteredCards.reverse()
}

return filteredCards
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/collection/CardDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ export default function CardDetail() {
// if we draw from 'everypack' we need to take one of the packs to base calculations on
const packName = card?.pack === 'everypack' ? expansion?.packs[0].name : card?.pack

const formatTimestamp = (timestamp: string) => {
const formatTimestamp = (date: Date) => {
return new Intl.DateTimeFormat(undefined, {
dateStyle: 'long',
timeStyle: 'long',
}).format(new Date(timestamp))
}).format(date)
}

const handleUncollect = (cardId: string) => {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/pages/collection/CollectionCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const filterParsers: { [K in keyof FiltersAll]: (s: string) => Filters[K] | unde
ownership: (s) => ((ownershipOptions as readonly string[]).includes(s) ? (s as Filters['ownership']) : undefined),
trading: (s) => ((tradingOptions as readonly string[]).includes(s) ? (s as Filters['trading']) : undefined),
sortBy: (s) => ((sortByOptions as readonly string[]).includes(s) ? (s as Filters['sortBy']) : undefined),
sortDesc: boolParser,
minNumber: numberParser,
maxNumber: numberParser,
deckbuildingMode: boolParser,
Expand All @@ -65,6 +66,7 @@ const defaultFilters: Filters = {
ownership: 'all',
trading: 'all',
sortBy: 'expansion-newest',
sortDesc: false,
minNumber: 0,
maxNumber: '∞',
deckbuildingMode: false,
Expand Down Expand Up @@ -274,7 +276,7 @@ export default function CollectionCards({ children, cards, isPublic, share }: Pr
{children}
<CardsTable
cards={filteredCards}
groupExpansions={filters().sortBy !== 'recent'}
groupExpansions={filters().sortBy === 'expansion-newest'}
render={(c) => <Card card={c} editable={!filters().deckbuildingMode && !isPublic} />}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/pages/decks/DeckBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const defaultFilters: Filters = {
cardType: [],
rarity: [],
sortBy: 'expansion-newest',
sortDesc: false,
allTextSearch: false,
}

Expand Down
Loading