Feat: Add creating decks
This commit is contained in:
parent
7145906862
commit
aaa0bee853
26 changed files with 1279 additions and 180 deletions
265
app/app/account/profile/decks/page.tsx
Normal file
265
app/app/account/profile/decks/page.tsx
Normal file
|
@ -0,0 +1,265 @@
|
|||
'use client'
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { getCookie } from "@/lib/utils"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
|
||||
import type { deck, bset } from "@prisma/client";
|
||||
|
||||
interface bsetJson extends bset {
|
||||
set_codes: string[],
|
||||
icons: string[]
|
||||
}
|
||||
|
||||
interface cardEntryAPIProps {
|
||||
amount: number,
|
||||
sanitized_name: string,
|
||||
set: string
|
||||
}
|
||||
|
||||
interface deckAPIProps {
|
||||
name: string,
|
||||
selected_bset: string,
|
||||
commander_name: string,
|
||||
cards: cardEntryAPIProps[]
|
||||
}
|
||||
|
||||
export default function Signin() {
|
||||
const [deckName, setDeckName] = useState("")
|
||||
const [deckCommanderName, setDeckCommanderName] = useState("")
|
||||
const [deckImporter, setDeckImporter] = useState("")
|
||||
const [selectedBset, setSelectedBset] = useState("")
|
||||
const [decks, setDecks] = useState<deck[]>([])
|
||||
const [bsets, setBsets] = useState<bsetJson[]>([])
|
||||
const [openSelectBset, setOpenSelectBset] = useState(false)
|
||||
const router = useRouter()
|
||||
const token = getCookie('JWT')
|
||||
|
||||
useEffect(() => {
|
||||
if(getCookie('JWT') == "") {
|
||||
router.refresh()
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
fetch('http://localhost:3000/api/account/decks/', {
|
||||
method: "GET",
|
||||
headers: {Authorization: 'Bearer ' + token},
|
||||
}).then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((apiData) => {
|
||||
setDecks(apiData.data)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
fetch('http://localhost:8072/misc/bsets.json').then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((data) => {
|
||||
setBsets(data)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
},[])
|
||||
|
||||
function getDataFromLine(line: string){
|
||||
if(line != "") {
|
||||
const values = line.split(" ")
|
||||
if (values.length >= 4) {
|
||||
const amount: number = parseInt(values.at(0)!.toString())
|
||||
|
||||
let set_index = 0
|
||||
for(let i = 1; i < values.length; i++){
|
||||
if(values.at(-i)!.toString().match(/\([A-Z]{3}\)/gm)){
|
||||
set_index = -i
|
||||
}
|
||||
}
|
||||
|
||||
const set = values.at(set_index)!.toString().replace(/[()]/gm,"").toLowerCase()
|
||||
const card_name = values.slice(1,set_index).join(" ").replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase()
|
||||
const card_data : cardEntryAPIProps = {amount, sanitized_name: card_name, set}
|
||||
return card_data
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function deleteDeck(id:string){
|
||||
fetch('http://localhost:3000/api/account/decks/delete', {
|
||||
method: "DELETE",
|
||||
headers: {Authorization: 'Bearer ' + token},
|
||||
body: JSON.stringify({ id })
|
||||
}).then((res) => {
|
||||
if(res.status == 200) {
|
||||
setDecks(old => old.filter((deck: deck) => deck.id != id))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateDeckInput(txt:string){
|
||||
setDeckImporter(txt)
|
||||
const lines = txt.split("\n")
|
||||
setDeckCommanderName(lines[0])
|
||||
}
|
||||
|
||||
function importDeck(){
|
||||
const deckText = deckImporter
|
||||
const lines = deckText.split("\n")
|
||||
const dataToSend : deckAPIProps = { name: deckName, selected_bset: selectedBset.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase() ,commander_name: getDataFromLine(deckCommanderName)!.sanitized_name, cards: [] }
|
||||
lines.slice(1).forEach((line: string) => {
|
||||
const data = getDataFromLine(line)
|
||||
if(data != null) {
|
||||
dataToSend.cards.push(data)
|
||||
}
|
||||
});
|
||||
console.log(dataToSend)
|
||||
|
||||
|
||||
fetch('http://localhost:3000/api/account/decks/create', {
|
||||
method: "POST",
|
||||
headers: {Authorization: 'Bearer ' + token},
|
||||
body: JSON.stringify(dataToSend)
|
||||
}).then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((apiData) => {
|
||||
const new_deck: deck = apiData.data
|
||||
setDecks(oldDecks => [...oldDecks, new_deck])
|
||||
setDeckName("")
|
||||
setDeckImporter("")
|
||||
setSelectedBset("")
|
||||
setDeckCommanderName("")
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center mt-24" >
|
||||
<Card className="max-w-xl w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Importer un deck</CardTitle>
|
||||
<CardDescription>Depuis moxfield</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="font-bold">Nom du deck</Label>
|
||||
<Input value={deckName} onChange={(e) => setDeckName(e.target.value)} placeholder="Nom du deck" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="font-bold">BSet selectionné</Label>
|
||||
<Popover open={openSelectBset} onOpenChange={setOpenSelectBset}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={openSelectBset}
|
||||
className="w-full justify-between"
|
||||
>
|
||||
{selectedBset
|
||||
? bsets.find((bset: bset) => bset.sanitized_name === selectedBset)?.name
|
||||
: "Selectionnez un Bset..."}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command className="w-full">
|
||||
<CommandInput placeholder="Search framework..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>Pas de BSet trouvé.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{bsets.map((bset) => (
|
||||
<CommandItem
|
||||
key={bset.sanitized_name}
|
||||
value={bset.sanitized_name}
|
||||
onSelect={(currentValue) => {
|
||||
setSelectedBset(currentValue === selectedBset ? "" : currentValue)
|
||||
setOpenSelectBset(false)
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row gap-2">
|
||||
{bset.icons.map((icon) => (
|
||||
<img key={icon} src={icon} className="h-3" loading="lazy" />
|
||||
))}
|
||||
</div>
|
||||
{bset.name}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="font-bold">Commandant</Label>
|
||||
<Label className="text-xs">Correspond à la première ligne de l'import Moxfield</Label>
|
||||
<Input value={deckCommanderName} placeholder="Commandant du Deck" disabled />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="font-bold">Liste des cartes</Label>
|
||||
<Textarea value={deckImporter} onChange={(e) => updateDeckInput(e.target.value)} placeholder="Collez votre deck ici." className="h-60" />
|
||||
</div>
|
||||
<div className="flex flex-row w-full">
|
||||
<Button onClick={importDeck}>Importer</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="max-w-3xl w-full mt-12">
|
||||
<Table className="w-full">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{ decks.map((deck) => (
|
||||
<TableRow key={deck.id}>
|
||||
<TableCell>{deck.name}</TableCell>
|
||||
<TableCell className="flex flex-row gap-4 items-center"><a href={"/deck/" + deck.id}>Voir la page</a><Button disabled>Editer</Button><Button onClick={() => {deleteDeck(deck.id)}} variant="destructive">Supprimer</Button></TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -113,7 +113,6 @@ export default function Home() {
|
|||
setBsetList(old => old.filter((bset) => bset.id != id))
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
141
app/app/api/account/decks/create/route.ts
Normal file
141
app/app/api/account/decks/create/route.ts
Normal file
|
@ -0,0 +1,141 @@
|
|||
import { NextResponse, NextRequest } from 'next/server'
|
||||
import { validateToken, decryptToken } from '@/lib/jwt'
|
||||
import { db } from "@/lib/db"
|
||||
|
||||
interface orCardFilterProps {
|
||||
sanitized_name: string
|
||||
OR: orSetFilterProps[]
|
||||
}
|
||||
|
||||
interface orSetFilterProps {
|
||||
set_code: string
|
||||
}
|
||||
|
||||
interface cardEntryAPIProps {
|
||||
amount: number,
|
||||
sanitized_name: string,
|
||||
set: string
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const token = req?.headers.get("authorization")?.split(" ")[1]
|
||||
const { name, cards, selected_bset, commander_name } = await req.json()
|
||||
|
||||
if(token == undefined) {
|
||||
return NextResponse.json({"message": "You did not provide a token."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
if(!validateToken(token)) {
|
||||
return NextResponse.json({"message": "Your token is not valid."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const tokenData = decryptToken(token)
|
||||
|
||||
if(name == undefined || cards == undefined || selected_bset == undefined || commander_name == undefined) {
|
||||
return NextResponse.json({"message": "Wrong data in the request."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const bset = await db.bset.findFirst({
|
||||
where: {
|
||||
sanitized_name: selected_bset
|
||||
},
|
||||
relationLoadStrategy: "join",
|
||||
include: {
|
||||
sets: true
|
||||
}
|
||||
})
|
||||
|
||||
const set_codes: orSetFilterProps[] = []
|
||||
bset?.sets.forEach((set) => {
|
||||
set_codes.push({set_code: set.code})
|
||||
})
|
||||
|
||||
const cardsFilter: orCardFilterProps[] = [{sanitized_name: commander_name, OR: set_codes}]
|
||||
cards.forEach((card:cardEntryAPIProps) => {
|
||||
cardsFilter.push({sanitized_name: card.sanitized_name, OR: set_codes})
|
||||
})
|
||||
|
||||
const cardsData = await db.carte.findMany({
|
||||
where: {
|
||||
OR: cardsFilter
|
||||
}
|
||||
})
|
||||
|
||||
let allCardFound = true
|
||||
if(cardsData.findIndex(cardData => cardData.sanitized_name == commander_name) == -1){
|
||||
allCardFound = false
|
||||
}
|
||||
cards.forEach((card: cardEntryAPIProps) => {
|
||||
if(cardsData.findIndex(cardData => cardData.sanitized_name == card.sanitized_name) == -1){
|
||||
console.log(card)
|
||||
allCardFound = false
|
||||
}
|
||||
})
|
||||
|
||||
if(!allCardFound) {
|
||||
return NextResponse.json({"message": "Some cards were not found..."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const deck = await db.deck.create({
|
||||
data: {
|
||||
name,
|
||||
utilisateurice: {
|
||||
connect: {
|
||||
id: tokenData.id
|
||||
}
|
||||
},
|
||||
commander: {
|
||||
connect: {
|
||||
id: cardsData[cardsData.findIndex(cardData => cardData.sanitized_name == commander_name)].id
|
||||
}
|
||||
},
|
||||
bset: {
|
||||
connect: {
|
||||
id: bset?.id
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
cards.forEach(async (card: cardEntryAPIProps) => {
|
||||
const cardData_id = cardsData[cardsData.findIndex(cardData => cardData.sanitized_name == card.sanitized_name)].id
|
||||
console.log(card.sanitized_name)
|
||||
await db.cartes_dans_deck.create({
|
||||
data: {
|
||||
amount: card.amount,
|
||||
carte: {
|
||||
connect: {
|
||||
id: cardData_id
|
||||
}
|
||||
},
|
||||
deck: {
|
||||
connect: {
|
||||
id: deck.id
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return NextResponse.json({"data": deck, "message": "Deck created !"},{
|
||||
status: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return NextResponse.json(
|
||||
{ error: "Failed, check console" },
|
||||
{
|
||||
status: 500,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
55
app/app/api/account/decks/delete/route.ts
Normal file
55
app/app/api/account/decks/delete/route.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { NextResponse, NextRequest } from 'next/server'
|
||||
import { validateToken } from '@/lib/jwt'
|
||||
import { db } from "@/lib/db"
|
||||
|
||||
|
||||
// TODO: Check if the user is the owner of the deck or an admin.
|
||||
export async function DELETE(req: NextRequest) {
|
||||
try {
|
||||
const token = req?.headers.get("authorization")?.split(" ")[1]
|
||||
|
||||
const { id } = await req.json()
|
||||
|
||||
if(token == undefined) {
|
||||
return NextResponse.json({"message": "You did not provide a token."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
if(!validateToken(token)) {
|
||||
return NextResponse.json({"message": "Your token is not valid."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
if(id == undefined) {
|
||||
return NextResponse.json({"message": "You did not provide an ID."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
await db.cartes_dans_deck.deleteMany({
|
||||
where: {
|
||||
deck_id: id
|
||||
}
|
||||
})
|
||||
|
||||
await db.deck.delete({
|
||||
where: {
|
||||
id
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({"message": "Deck successfully deleted."},{
|
||||
status: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return NextResponse.json(
|
||||
{ error: "Failed, check console" },
|
||||
{
|
||||
status: 500,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
41
app/app/api/account/decks/route.ts
Normal file
41
app/app/api/account/decks/route.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { NextResponse, NextRequest } from 'next/server'
|
||||
import { validateToken, decryptToken } from '@/lib/jwt'
|
||||
import { db } from "@/lib/db"
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const token = req?.headers.get("authorization")?.split(" ")[1]
|
||||
|
||||
if(token == undefined) {
|
||||
return NextResponse.json({"message": "You did not provide a token."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
if(!validateToken(token)) {
|
||||
return NextResponse.json({"message": "Your token is not valid."},{
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const tokenData = decryptToken(token)
|
||||
|
||||
const decks = await db.deck.findMany({
|
||||
where: {
|
||||
utilisateurice_id: tokenData.id
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({"data": decks, "message": "Deck created !"},{
|
||||
status: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return NextResponse.json(
|
||||
{ error: "Failed, check console" },
|
||||
{
|
||||
status: 500,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ export async function POST(req: NextRequest) {
|
|||
|
||||
if (user !== undefined){
|
||||
if(createHmac('sha256',secret).update(password).digest('hex') == user!.password) {
|
||||
const token = createToken({data: {username: user!.username, admin: user!.admin}, maxAge: 60*60*24*7})
|
||||
const token = createToken({data: {username: user!.username, admin: user!.admin, id: user!.id}, maxAge: 60*60*24*7})
|
||||
return NextResponse.json({"JWT": token},{
|
||||
status: 200,
|
||||
});
|
||||
|
|
36
app/app/api/deck/[:id]/route.ts
Normal file
36
app/app/api/deck/[:id]/route.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { NextResponse, NextRequest } from 'next/server'
|
||||
import { db } from "@/lib/db"
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const deckId = req.nextUrl.pathname.slice(10).replace(/[^a-zA-Z0-9\-]/gim,"")
|
||||
console.log(deckId)
|
||||
|
||||
const deck = await db.deck.findFirst({
|
||||
where: {
|
||||
id: deckId
|
||||
},
|
||||
relationLoadStrategy: "join",
|
||||
include: {
|
||||
cartes: {
|
||||
include: {
|
||||
carte: true
|
||||
}
|
||||
},
|
||||
commander: true
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({"deck": deck, "message": "Deck created !"},{
|
||||
status: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return NextResponse.json(
|
||||
{ error: "Failed, check console" },
|
||||
{
|
||||
status: 500,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
49
app/app/deck/[:id]/page.tsx
Normal file
49
app/app/deck/[:id]/page.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
'use client'
|
||||
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { useEffect, useState } from "react"
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { deck, cartes_dans_deck, carte } from '@prisma/client'
|
||||
|
||||
interface deckFromApi extends deck {
|
||||
commander: carte,
|
||||
cartes: cartes_dans_deckFromApi[]
|
||||
}
|
||||
|
||||
interface cartes_dans_deckFromApi extends cartes_dans_deck {
|
||||
carte: carte
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
const deckId = usePathname().slice(6).split("/")[0]
|
||||
const [deck, setDeck] = useState<deckFromApi>()
|
||||
|
||||
useEffect(() => {
|
||||
fetch('http://localhost:3000/api/deck/'+deckId, {
|
||||
method: "GET",
|
||||
}).then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((apiData) => {
|
||||
setDeck(apiData.deck)
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center mt-32">
|
||||
{ deck != undefined && (
|
||||
<>
|
||||
<h1 className="text-5xl">{deck?.name}</h1>
|
||||
<MTGCard cardname={deck.commander?.name} imageURI={deck.commander?.normal_image} url={"/card/" + deck.commander?.sanitized_name} />
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{deck.cartes?.map((card) => (
|
||||
<MTGCard key={card.carte.id} cardname={card.amount + "x " + card.carte.name} imageURI={card.carte.normal_image} url={"/card/" + card.carte.sanitized_name}/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -15,7 +25,7 @@ export default function Home() {
|
|||
const [landCardList, setLandCardList] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
fetch('http://localhost:8072/top/colorless.json').then((res) => {
|
||||
fetch('http://localhost:8072/top/mono-colorless.json').then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((data) => {
|
||||
const limit = 20
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -15,7 +25,7 @@ export default function Home() {
|
|||
const [landCardList, setLandCardList] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
fetch('http://localhost:8072/top/multicolor.json').then((res) => {
|
||||
fetch('http://localhost:8072/top/mono-multicolor.json').then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((data) => {
|
||||
const limit = 20
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MTGCard } from '@/components/ui/mtg-card'
|
||||
|
||||
import type { carte } from "@prisma/client";
|
||||
interface carte_from_stats {
|
||||
id: string,
|
||||
name: string,
|
||||
normal_image: string,
|
||||
sanitized_name: string,
|
||||
nbr_decks: number,
|
||||
total_decks: number,
|
||||
percent_decks: number,
|
||||
price: string,
|
||||
cardmarket_uri: string
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [creatureCardList, setCreatureCardList] = useState([])
|
||||
|
@ -35,44 +45,44 @@ export default function Home() {
|
|||
<div className="flex flex-col items-center mt-32">
|
||||
<h1>Creature</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{creatureCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{creatureCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Instants</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{instantCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{instantCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Sorceries</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{sorceryCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{sorceryCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Enchantment</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{enchantmentCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{enchantmentCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Planeswalker</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{planeswalkerCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{planeswalkerCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Artifact</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{artifactCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{artifactCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
<h1>Lands</h1>
|
||||
<div className="flex flex-row flex-wrap gap-4 p-8">
|
||||
{landCardList.map((card: carte) => (
|
||||
<MTGCard key={card.id} cardname={card.name_fr} imageURI={card.normal_image} url={"/card/" + card.sanitized_name}/>
|
||||
{landCardList.map((card: carte_from_stats) => (
|
||||
<MTGCard key={card.id} cardname={card.name} imageURI={card.normal_image} url={"/card/" + card.sanitized_name} nbrDecks={card.nbr_decks} totalDecks={card.total_decks} percentDecks={card.percent_decks} price={card.price} cardmarketURI={card.cardmarket_uri}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
26
app/components/ui/label.tsx
Normal file
26
app/components/ui/label.tsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
|
||||
export { Label }
|
|
@ -6,10 +6,15 @@ interface MTGCardProps {
|
|||
className?: string,
|
||||
imageURI: string,
|
||||
cardname: string,
|
||||
url: string
|
||||
url: string,
|
||||
nbrDecks?: number,
|
||||
totalDecks?: number,
|
||||
percentDecks?: number,
|
||||
price?: string,
|
||||
cardmarketURI?: string
|
||||
}
|
||||
|
||||
const MTGCard = ({ className, imageURI, cardname, url }: MTGCardProps) => {
|
||||
const MTGCard = ({ className, imageURI, cardname, url, nbrDecks, totalDecks, percentDecks, price, cardmarketURI }: MTGCardProps) => {
|
||||
const [loaded, setLoaded] = React.useState(false)
|
||||
|
||||
return (
|
||||
|
@ -24,7 +29,17 @@ const MTGCard = ({ className, imageURI, cardname, url }: MTGCardProps) => {
|
|||
<span className="h-64 shadow">Loading...</span>
|
||||
}
|
||||
<img src={imageURI} className="rounded" height={loaded ? 'auto' : '0'} onLoad={() => {setLoaded(true)}} loading="lazy" />
|
||||
<span className="text-center">{cardname}</span>
|
||||
<div className="flex flex-col items-center gap-0">
|
||||
{ price != undefined && (
|
||||
<a href={cardmarketURI != undefined ? cardmarketURI : "#"} target={cardmarketURI != undefined ? "_blank" : "_self"}>{price}€</a>
|
||||
)}
|
||||
<span className="text-center">{cardname}</span>
|
||||
{ nbrDecks != undefined && (
|
||||
<>
|
||||
<span className="text-xs">{nbrDecks} de {totalDecks} Decks ({percentDecks}%)</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
)}
|
||||
MTGCard.displayName = "MTGCard"
|
||||
|
|
|
@ -66,7 +66,7 @@ export function NavigationBar ({ isLoggedIn, username}: NavigationProps) {
|
|||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<a className="flex flex-row gap-2" href="/top/blue">
|
||||
<a className="flex flex-row gap-2" href="/top/black">
|
||||
<Black className="h-4 w-4"/>
|
||||
<span>Noir</span>
|
||||
</a>
|
||||
|
@ -394,10 +394,13 @@ export function NavigationBar ({ isLoggedIn, username}: NavigationProps) {
|
|||
}
|
||||
{
|
||||
isLoggedIn &&
|
||||
<a href="/account/profile" className="flex flex-row items-center gap-2">
|
||||
<IconUserFilled color="gray" />
|
||||
<span className="text-gray-400">{username}</span>
|
||||
</a>
|
||||
<>
|
||||
<a href="/account/profile/decks" className="flex flex-row items-center gap-2"><span className="text-gray-400">Decks</span></a>
|
||||
<a href="/account/profile" className="flex flex-row items-center gap-2">
|
||||
<IconUserFilled color="gray" />
|
||||
<span className="text-gray-400">{username}</span>
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
33
app/components/ui/popover.tsx
Normal file
33
app/components/ui/popover.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverAnchor = PopoverPrimitive.Anchor
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
22
app/components/ui/textarea.tsx
Normal file
22
app/components/ui/textarea.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Textarea = React.forwardRef<
|
||||
HTMLTextAreaElement,
|
||||
React.ComponentProps<"textarea">
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Textarea.displayName = "Textarea"
|
||||
|
||||
export { Textarea }
|
279
app/package-lock.json
generated
279
app/package-lock.json
generated
|
@ -14,7 +14,9 @@
|
|||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.1",
|
||||
"@radix-ui/react-popover": "^1.1.3",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@tabler/icons": "^3.22.0",
|
||||
"@tabler/icons-react": "^3.22.0",
|
||||
|
@ -1339,6 +1341,29 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-label": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz",
|
||||
"integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-menu": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz",
|
||||
|
@ -1415,6 +1440,260 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.3.tgz",
|
||||
"integrity": "sha512-MBDKFwRe6fi0LT8m/Jl4V8J3WbS/UfXJtsgg8Ym5w5AyPG3XfHH4zhBp1P8HmZK83T8J7UzVm6/JpDE3WMl1Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.2",
|
||||
"@radix-ui/react-focus-guards": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-popper": "1.2.1",
|
||||
"@radix-ui/react-portal": "1.1.3",
|
||||
"@radix-ui/react-presence": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-slot": "1.1.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"aria-hidden": "^1.1.1",
|
||||
"react-remove-scroll": "2.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz",
|
||||
"integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.2.tgz",
|
||||
"integrity": "sha512-kEHnlhv7wUggvhuJPkyw4qspXLJOdYoAP4dO2c8ngGuXTq1w/HZp1YeVB+NQ2KbH1iEG+pvOCGYSqh9HZOz6hg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz",
|
||||
"integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
|
||||
"integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||
"@radix-ui/react-use-rect": "1.1.0",
|
||||
"@radix-ui/react-use-size": "1.1.0",
|
||||
"@radix-ui/rect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz",
|
||||
"integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
||||
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.1",
|
||||
"@radix-ui/react-popover": "^1.1.3",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@tabler/icons": "^3.22.0",
|
||||
"@tabler/icons-react": "^3.22.0",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["relationJoins"]
|
||||
}
|
||||
|
||||
|
@ -9,54 +9,76 @@ datasource db {
|
|||
}
|
||||
|
||||
model utilisateurice {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
username String
|
||||
password String
|
||||
email String
|
||||
admin Boolean @default(false)
|
||||
deck deck[]
|
||||
}
|
||||
|
||||
model carte {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name_en String
|
||||
name_fr String
|
||||
sanitized_name String
|
||||
released_at String
|
||||
small_image String
|
||||
normal_image String
|
||||
mana_cost String
|
||||
cmc Int
|
||||
type_line_en String?
|
||||
type_line_fr String?
|
||||
oracle_text_en String?
|
||||
oracle_text_fr String?
|
||||
power String?
|
||||
toughness String?
|
||||
colors String[]
|
||||
keywords String[]
|
||||
set set @relation(fields: [set_id], references: [id])
|
||||
set_id String @db.Uuid
|
||||
rarity String
|
||||
type String?
|
||||
cardmarket_uri String?
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
sanitized_name String
|
||||
released_at String
|
||||
layout String
|
||||
small_image String
|
||||
small_image_back String?
|
||||
normal_image String
|
||||
normal_image_back String?
|
||||
type_line String?
|
||||
colors String[]
|
||||
set set @relation(fields: [set_id], references: [id])
|
||||
set_id String @db.Uuid
|
||||
set_code String
|
||||
rarity String
|
||||
type String?
|
||||
price String?
|
||||
cardmarket_uri String?
|
||||
decks cartes_dans_deck[]
|
||||
decks_as_commander deck[]
|
||||
}
|
||||
|
||||
model deck {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
utilisateurice_id String @db.Uuid
|
||||
utilisateurice utilisateurice @relation(fields: [utilisateurice_id], references: [id])
|
||||
cartes cartes_dans_deck[]
|
||||
commander carte @relation(fields: [commander_id], references: [id])
|
||||
commander_id String @db.Uuid
|
||||
bset bset @relation(fields: [bset_id], references: [id])
|
||||
bset_id String @db.Uuid
|
||||
}
|
||||
|
||||
model cartes_dans_deck {
|
||||
carte carte @relation(fields: [carte_id], references: [id])
|
||||
carte_id String @db.Uuid
|
||||
deck deck @relation(fields: [deck_id], references: [id])
|
||||
deck_id String @db.Uuid
|
||||
amount Int
|
||||
|
||||
@@id([carte_id, deck_id])
|
||||
}
|
||||
|
||||
model set {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name_en String
|
||||
sanitized_name String
|
||||
code String
|
||||
set_type String
|
||||
released_at String?
|
||||
icon_svg_uri String
|
||||
cards carte[]
|
||||
bset bset? @relation(fields: [bset_id], references: [id])
|
||||
bset_id String? @db.Uuid
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name_en String
|
||||
sanitized_name String
|
||||
code String
|
||||
set_type String
|
||||
released_at String?
|
||||
icon_svg_uri String
|
||||
cards carte[]
|
||||
bset bset? @relation(fields: [bset_id], references: [id])
|
||||
bset_id String? @db.Uuid
|
||||
}
|
||||
|
||||
model bset {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
sanitized_name String
|
||||
sets set[]
|
||||
decks deck[]
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ const Bsets = [
|
|||
{"name": "War of the Spark", sets: ["war"]},
|
||||
{"name": "Dominaria", sets: ["dom"]},
|
||||
{"name": "March of the machine", sets: ["mom","mat"]},
|
||||
{"name": "Innistrad Midnight Hunt", sets: ["wow","mid"]},
|
||||
{"name": "Innistrad Midnight Hunt", sets: ["vow","mid"]},
|
||||
{"name": "Guilds of Ravnica", sets: ["rna","grn"]},
|
||||
{"name": "Ixalan", sets: ["rix","xln"]},
|
||||
{"name": "Amonkhet", sets: ["hou","akh"]},
|
||||
|
@ -36,13 +36,13 @@ const Bsets = [
|
|||
{"name": "Ravnica", sets: ["rav","gpt","dis"]},
|
||||
{"name": "Kamigawa 3x", sets: ["chk","bok","sok"]},
|
||||
{"name": "Mirrodin", sets: ["5dn","dst","mrd"]},
|
||||
{"name": "Onslaught", sets: ["ons","lng","scg"]},
|
||||
{"name": "Onslaught", sets: ["ons","lgn","scg"]},
|
||||
{"name": "Odyssey", sets: ["ody","tor","jud"]},
|
||||
{"name": "Invasion", sets: ["inv","pls","apc"]},
|
||||
{"name": "Masques", sets: ["mmq","nem","pcy"]},
|
||||
{"name": "Urza", sets: ["usg","ulg","uds"]},
|
||||
{"name": "Tempest", sets: ["tmp","sth","exo"]},
|
||||
{"name": "Mirage", sets: ["wth","mir","wis"]},
|
||||
{"name": "Mirage", sets: ["wth","mir","vis"]},
|
||||
{"name": "Ice Age", sets: ["csp","ice","all"]},
|
||||
{"name": "Time Spiral", sets: ["fut","tsp","plc","tsb"]},
|
||||
{"name": "Lorwyn-Shadowmoor", sets: ["lrw","shm","mor","eve"]},
|
||||
|
|
|
@ -61,20 +61,36 @@ async function createJson() {
|
|||
include: {
|
||||
sets: {
|
||||
include: {
|
||||
cards: true
|
||||
cards: {
|
||||
include: {
|
||||
decks: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
decks: true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let bsets_export = []
|
||||
let all_cards = []
|
||||
bsets.forEach((bset) => {
|
||||
let icons = []
|
||||
let set_codes = []
|
||||
bset.sets.forEach((set) => {
|
||||
all_cards = [...all_cards, ...set.cards]
|
||||
icons.push(set.icon_svg_uri)
|
||||
set_codes.push(set.code)
|
||||
let cards_temp = set.cards
|
||||
for(let i = 0; i < cards_temp.length; i++){
|
||||
cards_temp[i].bset_id = bset.id
|
||||
}
|
||||
all_cards = [...all_cards, ...cards_temp]
|
||||
})
|
||||
bsets_export.push({name: bset.name, sanitized_name: bset.sanitized_name, icons, set_codes})
|
||||
})
|
||||
|
||||
|
||||
writeFileSync(import.meta.dirname + "/json/misc/bsets.json",JSON.stringify(bsets_export), 'utf8')
|
||||
|
||||
|
||||
|
||||
|
@ -86,23 +102,43 @@ async function createJson() {
|
|||
const colorsData = {"mono-white": structuredClone(type_dict),"mono-black": structuredClone(type_dict),"mono-blue": structuredClone(type_dict),"mono-green": structuredClone(type_dict),"mono-red": structuredClone(type_dict),"colorless": structuredClone(type_dict),"multicolor": structuredClone(type_dict)}
|
||||
|
||||
for (const card of all_cards) {
|
||||
let card_object = {
|
||||
"name": card.name,
|
||||
"sanitized_name": card.sanitized_name,
|
||||
"normal_image": card.normal_image,
|
||||
"small_image": card.small_image,
|
||||
"type": card.type,
|
||||
"layout": card.layout,
|
||||
"price": card.price,
|
||||
"cardmarket_uri": card.cardmarket_uri,
|
||||
"nbr_decks": card.decks.length,
|
||||
"total_decks": bsets.find((bset) => bset.id == card.bset_id).decks.length,
|
||||
"colors": card.colors,
|
||||
}
|
||||
|
||||
card_object.percent_decks = (card_object.total_decks != 0) ? parseInt(10000 * (card_object.nbr_decks / card_object.total_decks)) / 100 : 0
|
||||
|
||||
const colorName = getColorName(card.colors)
|
||||
if (card.type == "land") {
|
||||
if (colorName != "") {
|
||||
landsData[colorName].push(card)
|
||||
landsData[colorName].push(card_object)
|
||||
}
|
||||
}
|
||||
|
||||
if (card.colors.length <= 1) {
|
||||
colorsData[colorName][card.type].push(card)
|
||||
colorsData[colorName][card.type].push(card_object)
|
||||
} else {
|
||||
colorsData["multicolor"][card.type].push(card)
|
||||
colorsData["multicolor"][card.type].push(card_object)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const index of Object.keys(colorsData)) {
|
||||
writeFileSync(import.meta.dirname + "/json/top/" + index + ".json",JSON.stringify(colorsData[index]), 'utf8')
|
||||
let JSONToWrite = colorsData[index]
|
||||
for (const key of Object.keys(JSONToWrite)){
|
||||
JSONToWrite[key].sort((a,b) => b.percent_decks - a.percent_decks)
|
||||
}
|
||||
writeFileSync(import.meta.dirname + "/json/top/" + index + ".json",JSON.stringify(JSONToWrite), 'utf8')
|
||||
}
|
||||
|
||||
const landsJsonRoot = [[],[],[],[]]
|
||||
|
@ -114,7 +150,9 @@ async function createJson() {
|
|||
} else {
|
||||
landsJsonRoot[3].push({ "name": colorName, "count": landsData[colorName].length})
|
||||
}
|
||||
writeFileSync(import.meta.dirname + "/json/lands/" + colorName + ".json",JSON.stringify(landsData[colorName]), 'utf8')
|
||||
let JSONToWrite = landsData[colorName]
|
||||
JSONToWrite.sort((a,b) => b.percent_decks - a.percent_decks)
|
||||
writeFileSync(import.meta.dirname + "/json/lands/" + colorName + ".json",JSON.stringify(JSONToWrite), 'utf8')
|
||||
}
|
||||
writeFileSync(import.meta.dirname + "/json/lands/lands.json",JSON.stringify(landsJsonRoot), 'utf8')
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ console.log('Status Code:', scryfallSets.status);
|
|||
const sets = await scryfallSets.json();
|
||||
|
||||
// Read the data from the exported fr_cards.json extracted from Scryfall Bulk Data
|
||||
const fileBytes = fs.readFileSync(import.meta.dirname + '/data/fr_cards.json')
|
||||
const fileBytes = fs.readFileSync(import.meta.dirname + '/data/default-cards-20241210100712.json')
|
||||
let scryfallData = JSON.parse(fileBytes)
|
||||
|
||||
// Connect to postgres database
|
||||
|
@ -23,6 +23,8 @@ const client = new Client({
|
|||
})
|
||||
await client.connect()
|
||||
|
||||
const two_faced_layouts = ["transform","modal_dfc","double_faced_token","reversible_card"]
|
||||
|
||||
try {
|
||||
const setRes = await client.query('SELECT id FROM set')
|
||||
const preUpdateSetRows = setRes.rows
|
||||
|
@ -47,15 +49,15 @@ try {
|
|||
});
|
||||
|
||||
// Define counter for logging
|
||||
let total_no_fr_name = 0
|
||||
let total_inserted = 0
|
||||
let total_skipped = 0
|
||||
|
||||
// For each card check if we need to upload it to the database
|
||||
for (const carte of scryfallData) {
|
||||
if(!preUpdateCardsIds.includes(carte.id)){
|
||||
let type = null
|
||||
const card_type = carte.type_line.toLowerCase()
|
||||
if(!preUpdateCardsIds.includes(carte.id) && carte.layout != "art_series"){
|
||||
let type = ""
|
||||
const layout = carte.layout
|
||||
const card_type = (carte.type_line == undefined) ? carte.card_faces[0].type_line.toLowerCase() : carte.type_line.toLowerCase()
|
||||
|
||||
if(card_type.includes("creature")){
|
||||
type = "creature"
|
||||
|
@ -73,27 +75,28 @@ try {
|
|||
type = "land"
|
||||
}
|
||||
|
||||
try {
|
||||
if(two_faced_layouts.includes(layout)) {
|
||||
const addingCardsQuery = await client.query('INSERT INTO carte(id, name, released_at, small_image, small_image_back, normal_image, normal_image_back, type_line, colors, set_id, rarity, cardmarket_uri, price, type, sanitized_name, set_code, layout) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)', [carte.id, carte.name, carte.released_at, carte.card_faces[0].image_uris.small, carte.card_faces[1].image_uris.small, carte.card_faces[0].image_uris.normal, carte.card_faces[0].image_uris.normal, carte.type_line, carte.color_identity, carte.set_id, carte.rarity, carte.purchase_uris?.cardmarket, carte.prices.eur, type, carte.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase(), carte.set, layout])
|
||||
|
||||
} else {
|
||||
const addingCardsQuery = await client.query('INSERT INTO carte(id, name, released_at, small_image, normal_image, type_line, colors, set_id, rarity, cardmarket_uri, price, type, sanitized_name, set_code, layout) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)', [carte.id, carte.name, carte.released_at, carte.image_uris.small, carte.image_uris.normal, carte.type_line, carte.color_identity, carte.set_id, carte.rarity, carte.purchase_uris?.cardmarket, carte.prices.eur, type, carte.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase(), carte.set, layout])
|
||||
|
||||
if(carte.printed_name == undefined) {
|
||||
// If the card doesn't have a french name, print it to the console and skip
|
||||
|
||||
//console.log("Erreur sur la carte : " + carte.name)
|
||||
//console.log("Scryfall URI : " + carte.scryfall_uri)
|
||||
//console.log("API URI : " + carte.uri)
|
||||
total_no_fr_name = total_no_fr_name + 1
|
||||
continue
|
||||
}
|
||||
total_inserted = total_inserted + 1
|
||||
} catch (err) {
|
||||
console.log(carte.uri)
|
||||
console.log(carte.layout)
|
||||
console.log(err)
|
||||
total_skipped = total_skipped + 1
|
||||
}
|
||||
|
||||
// Add the card to the database
|
||||
const addingCardsQuery = await client.query('INSERT INTO carte(id, name_en, name_fr, released_at, small_image, normal_image, mana_cost, cmc, type_line_en, type_line_fr, oracle_text_en, oracle_text_fr, power, toughness, colors, keywords, set_id, rarity, cardmarket_uri, type, sanitized_name) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)', [carte.id, carte.name, carte.printed_name, carte.released_at, carte.image_uris.small, carte.image_uris.normal, carte.mana_cost, carte.cmc, carte.type_line, carte.printed_type_line, carte.oracle_text, carte.printed_text, carte.power, carte.toughness, carte.color_identity, carte.keywords, carte.set_id, carte.rarity, carte.purchase_uris?.cardmarket, type, carte.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase()])
|
||||
total_inserted = total_inserted + 1
|
||||
} else {
|
||||
total_skipped = total_skipped + 1
|
||||
}
|
||||
|
||||
}
|
||||
console.log("Un total de " + total_no_fr_name + " cartes n'ont pas de nom français.")
|
||||
console.log("Un total de " + total_inserted + " cartes ont été insérées.")
|
||||
console.log("Un total de " + total_skipped + " cartes ont été ignorées.")
|
||||
} catch (err) {
|
||||
|
|
Loading…
Reference in a new issue