Feat: Add card list and top structure

This commit is contained in:
globuzma 2024-12-05 17:08:50 +01:00
parent 8e33dd45fe
commit eec6c6bfe8
19 changed files with 994 additions and 24 deletions

3
.gitignore vendored
View file

@ -19,4 +19,5 @@ app/*.tsbuildinfo
app/next-env.d.ts
# data
app/tools/data/
app/tools/data/*
app/tools/json/*

View file

@ -95,7 +95,8 @@ export default function Home() {
}).then((res) => {
if(res.status == 200) {
res.json().then((apiData) => {
setBsetList(old => [...old, { id: apiData.data, name: bset_name, sets: selectedSets }])
const addedBset : bsetExtended = { sanitized_name: bset_name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase() ,id: apiData.data, name: bset_name, sets: selectedSets }
setBsetList(old => [...old, addedBset])
setSelectedSets([])
})
}

View file

@ -19,7 +19,8 @@ export async function POST(req: NextRequest) {
if(bset_name != undefined && selected_sets != undefined) {
const bset = await db.bset.create({
data: {
name: bset_name
name: bset_name,
sanitized_name: bset_name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase()
}
})

View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/mono-black.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

81
app/app/top/blue/page.tsx Normal file
View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/mono-blue.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/colorless.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/mono-green.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/multicolor.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

81
app/app/top/red/page.tsx Normal file
View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/mono-red.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,81 @@
'use client'
import { useEffect, useState } from 'react'
import { MTGCard } from '@/components/ui/mtg-card'
import type { carte } from "@prisma/client";
export default function Home() {
const [creatureCardList, setCreatureCardList] = useState([])
const [instantCardList, setInstantCardList] = useState([])
const [sorceryCardList, setSorceryCardList] = useState([])
const [planeswalkerCardList, setPlaneswalkerCardList] = useState([])
const [artifactCardList, setArtifactCardList] = useState([])
const [enchantmentCardList, setEnchantmentCardList] = useState([])
const [landCardList, setLandCardList] = useState([])
useEffect(() => {
fetch('http://localhost:8072/top/mono-white.json').then((res) => {
if(res.status == 200) {
res.json().then((data) => {
const limit = 20
setCreatureCardList(data["creature"].slice(0,limit))
setInstantCardList(data["instant"].slice(0,limit))
setSorceryCardList(data["sorcery"].slice(0,limit))
setPlaneswalkerCardList(data["planeswalker"].slice(0,limit))
setArtifactCardList(data["artifact"].slice(0,limit))
setEnchantmentCardList(data["enchantment"].slice(0,limit))
setLandCardList(data["land"].slice(0,limit))
console.log(data)
})
}
})
}, [])
return (
<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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</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}/>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,32 @@
import * as React from "react"
import { cn } from "@/lib/utils"
interface MTGCardProps {
className?: string,
imageURI: string,
cardname: string,
url: string
}
const MTGCard = ({ className, imageURI, cardname, url }: MTGCardProps) => {
const [loaded, setLoaded] = React.useState(false)
return (
<a
href={url}
className={cn(
"flex flex-col w-48",
className
)}
>
{!loaded &&
<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>
</a>
)}
MTGCard.displayName = "MTGCard"
export { MTGCard }

View file

@ -54,31 +54,45 @@ export function NavigationBar ({ isLoggedIn, username}: NavigationProps) {
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/white">
<White className="h-4 w-4"/>
<span>Blanc</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/blue">
<Blue className="h-4 w-4"/>
<span>Bleu</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/blue">
<Black className="h-4 w-4"/>
<span>Noir</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/red">
<Red className="h-4 w-4"/>
<span>Rouge</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/green">
<Green className="h-4 w-4"/>
<span>Vert</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/colorless">
<Colorless className="h-4 w-4"/>
<span>Incolor</span>
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a className="flex flex-row gap-2" href="/top/multicolor">
<span>Multicolor</span>
</a>
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>

10
app/docker-compose.yml Normal file
View file

@ -0,0 +1,10 @@
services:
nginx:
container_name: json_files
image: nginx
ports:
- 8072:80
volumes:
- ./tools/json:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
restart: unless-stopped

56
app/nginx.conf Normal file
View file

@ -0,0 +1,56 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
}
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}

150
app/package-lock.json generated
View file

@ -28,7 +28,8 @@
"react": "^18",
"react-dom": "^18",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"ts-node": "^10.9.2"
},
"devDependencies": {
"@types/node": "^20.17.6",
@ -67,6 +68,28 @@
"node": ">=6.9.0"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
@ -1776,6 +1799,30 @@
"react": ">= 16"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
"license": "MIT"
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"license": "MIT"
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"license": "MIT"
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"license": "MIT"
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@ -1787,7 +1834,6 @@
"version": "20.17.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz",
"integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
@ -2048,7 +2094,6 @@
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@ -2067,6 +2112,18 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -2975,6 +3032,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -3175,6 +3238,15 @@
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"license": "Apache-2.0"
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
@ -5127,6 +5199,12 @@
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"license": "ISC"
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -6856,6 +6934,55 @@
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
"license": "Apache-2.0"
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/ts-node/node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"license": "MIT"
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
@ -7002,7 +7129,6 @@
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@ -7032,7 +7158,6 @@
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"license": "MIT"
},
"node_modules/uri-js": {
@ -7094,6 +7219,12 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"license": "MIT"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -7324,6 +7455,15 @@
"node": ">= 14"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View file

@ -29,7 +29,8 @@
"react": "^18",
"react-dom": "^18",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"ts-node": "^10.9.2"
},
"devDependencies": {
"@types/node": "^20.17.6",

View file

@ -20,6 +20,7 @@ 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
@ -36,12 +37,14 @@ model carte {
set set @relation(fields: [set_id], references: [id])
set_id String @db.Uuid
rarity String
type String?
cardmarket_uri String?
}
model set {
id String @id @default(uuid()) @db.Uuid
name_en String
sanitized_name String
code String
set_type String
released_at String?
@ -54,5 +57,6 @@ model set {
model bset {
id String @id @default(uuid()) @db.Uuid
name String
sanitized_name String
sets set[]
}

122
app/tools/createJson.mjs Normal file
View file

@ -0,0 +1,122 @@
import { PrismaClient } from '@prisma/client'
import { writeFileSync } from 'fs'
const db = new PrismaClient()
const color_names = {
"mono-white": ["W"],
"mono-black": ["B"],
"mono-blue": ["U"],
"mono-green": ["G"],
"mono-red": ["R"],
"colorless": [],
"azorius": ["W","U"],
"dimir": ["U","B"],
"rakdos": ["B","R"],
"gruul": ["R","G"],
"selesnya": ["G","W"],
"orzhov": ["W","B"],
"izzet": ["U","R"],
"golgari": ["B","G"],
"boros": ["R","W"],
"simic": ["G","U"],
"esper": ["W","U","B"],
"grixis": ["U","B","R"],
"jund": ["B","R","G"],
"naya": ["R","G","W"],
"bant": ["G","W","U"],
"abzan": ["W","B","G"],
"jeskai": ["U","R","W"],
"sultai": ["B","G","U"],
"mardu": ["R","W","B"],
"temur": ["G","U","R"],
"yore-tiller": ["W","U","B","R"],
"glint-eye": ["U","B","R","G"],
"dune-brood": ["B","R","G","W"],
"ink-treader": ["R","G","W","U"],
"witch-maw": ["G","W","U","B"],
"five-color": ["G","W","U","B","R"],
}
function getColorName(colorArray) {
const colorArrayID = colorArray.sort().join(',')
for (const colorName of Object.keys(color_names)) {
if(colorArrayID === color_names[colorName].sort().join(',')){
return(colorName)
}
}
return ""
}
// I need to create
// Lands
// lands.json
// All jsons lands from colors
// Types
async function createJson() {
console.log("Fetching data...")
const bsets = await db.bset.findMany({
relationLoadStrategy: "join",
include: {
sets: {
include: {
cards: true
}
}
}
})
let all_cards = []
bsets.forEach((bset) => {
bset.sets.forEach((set) => {
all_cards = [...all_cards, ...set.cards]
})
})
const landsData = {}
for (const colorName of Object.keys(color_names)) {
landsData[colorName] = []
}
const type_dict = {"creature": [],"land": [],"instant": [],"sorcery": [], "planeswalker": [], "artifact": [], "enchantment": []}
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) {
const colorName = getColorName(card.colors)
if (card.type == "land") {
if (colorName != "") {
landsData[colorName].push(card)
}
}
if (card.colors.length <= 1) {
colorsData[colorName][card.type].push(card)
} else {
colorsData["multicolor"][card.type].push(card)
}
}
for (const index of Object.keys(colorsData)) {
writeFileSync(import.meta.dirname + "/json/top/" + index + ".json",JSON.stringify(colorsData[index]), 'utf8')
}
const landsJsonRoot = [[],[],[],[]]
for (const colorName of Object.keys(color_names)){
if(color_names[colorName].length <= 3){
let index = color_names[colorName].length - 1
if(index < 0) { index = 0 }
landsJsonRoot[index].push({ "name": colorName, "count": landsData[colorName].length})
} else {
landsJsonRoot[3].push({ "name": colorName, "count": landsData[colorName].length})
}
writeFileSync(import.meta.dirname + "/json/lands/" + colorName + ".json",JSON.stringify(landsData[colorName]), 'utf8')
}
writeFileSync(import.meta.dirname + "/json/lands/lands.json",JSON.stringify(landsJsonRoot), 'utf8')
}
createJson()

View file

@ -33,7 +33,7 @@ try {
for (const set of sets.data) {
if(!preUpdateSetIds.includes(set.id)){
const addingSetQuery = await client.query('INSERT INTO set(id, name_en, code, set_type, released_at, icon_svg_uri) VALUES($1, $2, $3, $4, $5, $6)', [set.id, set.name, set.code, set.set_type, set.released_at, set.icon_svg_uri])
const addingSetQuery = await client.query('INSERT INTO set(id, name_en, sanitized_name, code, set_type, released_at, icon_svg_uri) VALUES($1, $2, $3, $4, $5, $6, $7)', [set.id, set.name, set.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase(), set.code, set.set_type, set.released_at, set.icon_svg_uri])
}
}
@ -54,6 +54,27 @@ try {
// 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(card_type.includes("creature")){
type = "creature"
} else if (card_type.includes("planeswalker")) {
type = "planeswalker"
} else if (card_type.includes("artifact")) {
type = "artifact"
} else if (card_type.includes("instant")) {
type = "instant"
} else if (card_type.includes("enchantment")) {
type = "enchantment"
} else if (card_type.includes("sorcery")) {
type = "sorcery"
} else if (card_type.includes("land")) {
type = "land"
}
if(carte.printed_name == undefined) {
// If the card doesn't have a french name, print it to the console and skip
@ -65,7 +86,7 @@ try {
}
// 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) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)', [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.colors, carte.keywords, carte.set_id, carte.rarity, carte.purchase_uris?.cardmarket])
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