Compare commits

...

11 Commits

Author SHA1 Message Date
Cal Corum
5c176ebbcf Update supabase.d.ts 2025-07-22 09:27:06 -05:00
Cal Corum
ed33f1886c
Merge pull request #3 from calcorum/marketplace-page
Marketplace page
2025-05-12 21:18:21 -05:00
Cal Corum
2a99551295 Update base url for test build 2025-05-12 00:03:03 -05:00
Cal Corum
0999c1f6ab First pass at interactive marketplace listings 2025-05-12 00:02:09 -05:00
Cal Corum
d64ba33b61 Added pinia for stateful marketplace search
Refactored to marketplace component
2025-05-09 13:27:28 -05:00
Cal Corum
9a294eba54 Functional marketplace with cards 2025-05-09 09:48:46 -05:00
Cal Corum
b67b4709ce Update redirect URLs to use runtime config 2025-05-08 21:34:35 -05:00
Cal Corum
7940f817d8
Merge pull request #2 from calcorum/supabase-auth
Supabase auth
2025-05-08 21:12:00 -05:00
Cal Corum
cfe91c701e Added hamburger menu for nav bar 2025-05-08 21:09:50 -05:00
Cal Corum
2c0eeb96c3 - Implemented discord authentication
- Added script to fetch typescript definitions for the supabase database
2025-05-07 23:04:16 -05:00
Cal Corum
c409ea2e20
Merge pull request #1 from calcorum/master
Master
2025-05-07 09:01:25 -05:00
19 changed files with 1894 additions and 91 deletions

0
assets/css/styles.css Normal file
View File

426
components/Marketplace.vue Normal file
View File

@ -0,0 +1,426 @@
<template>
<main class="marketplace-layout">
<section class="filters-section">
<!-- Filters Toggle -->
<details class="filters-toggle" :open="showFilters">
<summary @click.prevent="showFilters = !showFilters">
Filters
<small v-if="hasActiveFilters" style="margin-left: 0.5rem;">({{ activeFilterCount }} active)</small>
</summary>
<form @submit.prevent class="filters">
<fieldset>
<div class="grid">
<label>
Min Cost
<input type="number" v-model.number="marketplace.minCost" inputmode="numeric" />
</label>
<label>
Max Cost
<input type="number" v-model.number="marketplace.maxCost" inputmode="numeric" />
</label>
</div>
<label>
Rarity
<select v-model="marketplace.rarities" multiple size="6">
<option value="Replacement">Replacement</option>
<option value="Reserve">Reserve</option>
<option value="Starter">Starter</option>
<option value="All-Star">All-Star</option>
<option value="MVP">MVP</option>
<option value="Hall of Fame">Hall of Fame</option>
</select>
</label>
<label>
Cardset
<select v-model="marketplace.cardset" multiple size="5">
<option v-for="name in cardsetNames" :key="name" :value="name">
{{ name }}
</option>
</select>
</label>
<button type="button" @click="marketplace.clearFilters" class="secondary">
Clear Filters
</button>
</fieldset>
</form>
</details>
<!-- Active Filter Chips -->
<div v-if="hasActiveFilters" class="filter-chips">
<span v-if="marketplace.minCost" class="chip">
Min: {{ marketplace.minCost }}
<button @click="marketplace.minCost = null" aria-label="Remove Min Cost">&times;</button>
</span>
<span v-if="marketplace.maxCost" class="chip">
Max: {{ marketplace.maxCost }}
<button @click="marketplace.maxCost = null" aria-label="Remove Max Cost">&times;</button>
</span>
<span v-for="rar in marketplace.rarities" :key="rar" class="chip">
{{ rar }}
<button @click="removeRarity(rar)" aria-label="Remove Rarity">&times;</button>
</span>
<span v-for="set in marketplace.cardset" :key="set" class="chip">
{{ set }}
<button @click="removeCardset(set)" aria-label="Remove Cardset">&times;</button>
</span>
</div>
</section>
<!-- Player List -->
<section class="player-list">
<div v-if="loading">
<article v-for="n in 6" :key="n" aria-busy="true">
<header><h2>Loading...</h2></header>
<p>Loading player data...</p>
</article>
</div>
<div v-else>
<article
v-for="player in players"
:key="player.player_id"
class="player-card"
@click="toggleExpanded(player.player_id)"
:aria-expanded="expandedPlayerId === player.player_id"
>
<header class="clickable-header">
<h2 class="player-name">{{ player.player_name }}</h2>
<div class="summary-info">
<small>
{{ player.cardset_name }} {{ player.franchise_name }}
<span class="rarity-badge" :style="{ backgroundColor: '#' + player.rarity_color }">
{{ player.rarity_name }}
</span> {{ player.player_cost }}
</small>
</div>
</header>
<transition name="fade">
<div v-if="expandedPlayerId === player.player_id" class="expanded-content">
<img :src="player.player_headshot" alt="Player Headshot" class="headshot" />
<div class="strat-card-container">
<img :src="player.player_card_image" alt="Card Image" class="strat-card" />
<img v-if="player.player_card_image2" :src="player.player_card_image2" alt="Card Image 2" class="strat-card" />
</div>
</div>
</transition>
</article>
</div>
</section>
<!-- Pagination -->
<nav class="pagination-controls">
<ul>
<li>
<button @click="previousPage" :disabled="page === 1">Previous</button>
</li>
<li>Page {{ page }}</li>
<li>
<button @click="nextPage">Next</button>
</li>
</ul>
</nav>
</main>
</template>
<script setup lang="ts">
import { ref, onMounted, watch, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useMarketplaceStore } from '@/stores/marketplace'
import type { MarketplacePlayer } from '~/types/MarketplacePlayer'
const route = useRoute()
const router = useRouter()
const client = useSupabaseClient()
const marketplace = useMarketplaceStore()
const players = ref<MarketplacePlayer[]>([])
const loading = ref(false)
const pageSize = ref(20)
const page = ref(1)
const expandedPlayerId = ref<number | null>(null)
const showFilters = ref(false)
// Example cardset list
const cardsetNames = [
'2021 Season', '2022 Season', '2023 Season', 'Mario Super Sluggers', 'Backyard Baseball'
]
// Computed
const hasActiveFilters = computed(() => {
return (
marketplace.minCost !== null ||
marketplace.maxCost !== null ||
marketplace.rarities.length > 0 ||
marketplace.cardset.length > 0
)
})
const activeFilterCount = computed(() => {
let count = 0
if (marketplace.minCost !== null) count++
if (marketplace.maxCost !== null) count++
count += marketplace.rarities.length
count += marketplace.cardset.length
return count
})
const fetchPlayers = async () => {
loading.value = true
const from = (page.value - 1) * pageSize.value
const to = from + pageSize.value - 1
let query = client.from('marketplace').select('*').range(from, to)
if (marketplace.minCost !== null && marketplace.minCost > 0) {
query = query.gte('player_cost', marketplace.minCost)
}
if (marketplace.maxCost !== null && marketplace.maxCost > 0) {
query = query.lte('player_cost', marketplace.maxCost)
}
if (marketplace.rarities?.length > 0) {
query = query.in('rarity_name', marketplace.rarities)
}
if (marketplace.cardset?.length > 0) {
query = query.in('cardset_name', marketplace.cardset)
}
const { data, error } = await query
if (error) console.error('Supabase error:', error)
loading.value = false
players.value = data || []
}
const toggleExpanded = (playerId: number) => {
expandedPlayerId.value = expandedPlayerId.value === playerId ? null : playerId
}
const removeRarity = (rarity: string) => {
marketplace.rarities = marketplace.rarities.filter(r => r !== rarity)
}
const removeCardset = (cardset: string) => {
marketplace.cardset = marketplace.cardset.filter(c => c !== cardset)
}
const updateRoute = () => {
router.replace({
query: {
page: page.value.toString(),
...(marketplace.minCost != null && { minCost: marketplace.minCost }),
...(marketplace.maxCost != null && { maxCost: marketplace.maxCost }),
...(marketplace.rarities.length && { rarity: marketplace.rarities }),
...(marketplace.cardset.length && { cardset: marketplace.cardset }),
}
})
}
const previousPage = () => {
if (page.value > 1) {
page.value--
updateRoute()
fetchPlayers()
}
}
const nextPage = () => {
page.value++
updateRoute()
fetchPlayers()
}
onMounted(async () => {
const { getNumber, getArray } = useSafeQuery()
page.value = getNumber('page') || 1
marketplace.setFilters({
minCost: getNumber('minCost'),
maxCost: getNumber('maxCost'),
rarities: getArray('rarities'),
cardset: getArray('cardset'),
})
await fetchPlayers()
})
watch(
[() => marketplace.minCost, () => marketplace.maxCost, () => marketplace.rarities, () => marketplace.cardset],
() => {
page.value = 1
updateRoute()
fetchPlayers()
},
{ deep: true }
)
</script>
<style scoped>
.marketplace-layout {
display: flex;
flex-direction: column;
min-height: 100vh; /* Full height of screen */
}
.filters-section {
padding-left: 1rem;
padding-right: 1rem;
padding-top: 1rem;
}
.player-list {
flex: 1 1 auto; /* Take up the leftover space */
overflow-y: auto; /* Scroll if too many players */
padding-left: 1rem;
padding-right: 1rem;
padding-bottom: 1rem;
}
.pagination-controls {
padding: 1rem;
text-align: center;
}
.grid {
display: grid;
gap: 1rem;
grid-template-columns: 1fr 1fr;
}
.filters-toggle summary {
cursor: pointer;
font-size: 1.25rem;
}
.filter-chips {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin: 1rem 0;
}
.chip {
display: inline-flex;
align-items: center;
background: var(--pico-primary-background);
color: var(--pico-primary-contrast);
padding: 0.25rem 0.5rem;
border-radius: var(--pico-border-radius);
}
.chip button {
background: transparent;
border: none;
color: inherit;
margin-left: 0.25rem;
cursor: pointer;
font-size: 1rem;
}
.player-card {
padding: 1rem;
margin-bottom: 1rem;
border: 1px solid var(--pico-border-color);
border-radius: var(--pico-border-radius);
cursor: pointer;
transition: background 0.3s;
display: flex;
flex-direction: column;
}
.player-card .clickable-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap; /* Allow wrapping of content if it exceeds screen width */
gap: 0.5rem; /* Space between name and summary info */
}
.player-card .player-name {
font-size: 1.25rem;
font-weight: bold;
}
.player-card .summary-info {
display: flex;
align-items: center;
gap: 0.5rem;
}
.player-card .summary-info small {
font-size: 1rem;
color: var(--pico-muted-color);
}
.player-card:hover {
background: var(--pico-muted-color);
}
.rarity-badge {
display: inline-block;
padding: 0.2rem 0.5rem;
border-radius: 999px;
font-weight: bold;
font-size: 0.85rem;
line-height: 1;
}
.clickable-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.expanded-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}
.strat-card-container {
display: flex;
justify-content: center;
gap: 1rem;
flex-wrap: wrap; /* Wrap on small screens */
}
img.strat-card {
width: 100%;
height: auto;
margin-bottom: 1rem;
}
img.headshot {
min-width: 80px;
max-width: 120px;
width: 20%;
aspect-ratio: 1/1; /* Force it to be a perfect square */
object-fit: cover;
border-radius: 50%;
border: 3px solid white;
background: white;
margin: 0 auto 8px;
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>

View File

@ -1,20 +1,185 @@
<script setup lang="ts">
const user = useSupabaseUser()
const client = useSupabaseClient()
const router = useRouter()
const isLoggingOut = ref(false)
async function logout() {
isLoggingOut.value = true
const { error } = await client.auth.signOut()
isLoggingOut.value = false
if (error) {
console.error('Logout failed:', error)
} else {
router.push('/')
}
}
const menuOpen = ref(false)
function toggleMenu() {
menuOpen.value = !menuOpen.value
}
</script>
<template>
<nav class="container">
<ul>
<li>
<NuxtLink to="/">
<strong>Paper Dynasty</strong>
</NuxtLink>
</li>
</ul>
<ul>
<li>
<NuxtLink to='/players/random'>Random Card</NuxtLink>
</li>
<li>
<NuxtLink to='/players/69'>Card 69</NuxtLink>
</li>
<li><a href="#">Shop</a></li>
</ul>
</nav>
</template>
<nav class="container">
<!-- Left side -->
<ul>
<li>
<NuxtLink to="/">
<strong>Paper Dynasty</strong>
</NuxtLink>
</li>
</ul>
<!-- Hamburger (mobile only) -->
<button class="hamburger" @click="toggleMenu" aria-label="Toggle menu" :class="{ open: menuOpen }">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
<!-- Menu -->
<ul class="menu" :class="{ open: menuOpen }">
<li>
<NuxtLink to="/marketplace">Marketplace</NuxtLink>
</li>
<li>
<NuxtLink to="/players/random">Random Cards</NuxtLink>
</li>
<li>
<NuxtLink to="/players/69">Card 69</NuxtLink>
</li>
<li>
<a href="https://ko-fi.com/manticorum">Shop</a>
</li>
<li v-if="user?.id" class="user-info">
<NuxtLink to='/my-team'>
<img
:src='user.user_metadata?.avatar_url || "/default-avatar.png"'
alt="My Team"
class="profile-pic"
/>
</NuxtLink>
<button
@click="logout"
:disabled="isLoggingOut"
class="logout-btn"
>
<template v-if="isLoggingOut">
<svg class="animate-spin h-4 w-4 text-red-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"></path>
</svg>
<span>Logging out...</span>
</template>
<template v-else>
<span>Logout</span>
</template>
</button>
</li>
<li v-else>
<NuxtLink to="/login/auto">Login with Discord</NuxtLink>
</li>
</ul>
</nav>
</template>
<style scoped>
/* Basic layout */
nav.container {
display: flex;
justify-content: space-between;
align-items: center;
padding-block: 1rem;
position: relative;
}
/* Menu */
.menu {
display: flex;
list-style: none;
gap: 0.25rem;
align-items: center;
}
/* Set a fixed size for the profile image */
.profile-pic {
width: 32px; /* Shrinks to 24px */
height: 32px;
border-radius: 50%;
object-fit: cover; /* Ensures image maintains aspect ratio */
margin-right: 10px; /* Adds space between the image and other elements */
}
/* Styling for the logout button */
.logout-btn {
font-size: 0.8rem;
color: grey;
background: none;
border: none;
cursor: pointer;
}
/* Hamburger button */
.hamburger {
display: none;
flex-direction: column;
gap: 5px;
cursor: pointer;
background: none;
border: none;
padding: 0;
position: relative;
z-index: 100; /* stays above the menu */
}
.hamburger .bar {
width: 24px;
height: 3px;
background-color: currentColor;
border-radius: 2px;
transition: 0.3s ease;
}
/* Animate hamburger to X */
.hamburger.open .bar:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.hamburger.open .bar:nth-child(2) {
opacity: 0;
}
.hamburger.open .bar:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
/* Mobile styles */
@media (max-width: 768px) {
.hamburger {
display: flex;
}
.menu {
display: none;
flex-direction: column;
position: absolute;
top: 100%;
right: 1rem;
background: var(--pico-background-color, #fff);
padding: 1rem;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.menu.open {
display: flex;
}
}
</style>

View File

@ -14,7 +14,7 @@
<p class="description">Description: {{ player?.description }}</p>
<p class="cost">Cost: ${{ player?.cost }}</p>
<p class="cost">Cost: {{ player?.cost }}</p>
</div>
</template>
@ -24,20 +24,13 @@ import type { Player } from '~/types/Player';
const props = defineProps<{
player: Player
}>()
// defineProps({
// player: {
// type: Player,
// required: true
// }
// })
</script>
<style scoped>
.player-card {
max-width: 400px;
background: white;
border-radius: 12px;
background: var(--pico-card-background-color);
border-radius: var(--pico-border-radius);
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
padding: 16px;

View File

@ -0,0 +1,37 @@
// composables/useSafeQuery.ts
import { useRoute } from 'vue-router'
export const useSafeQuery = () => {
const route = useRoute()
const getNumber = (key: string): number | undefined => {
const value = route.query[key]
if (typeof value === 'string') {
const parsed = Number(value)
return isNaN(parsed) ? undefined : parsed
}
return undefined
}
const getArray = (key: string): string[] => {
const value = route.query[key]
if (Array.isArray(value)) {
return value.map(String)
}
if (typeof value === 'string') {
return [value]
}
return []
}
const getString = (key: string): string | undefined => {
const value = route.query[key]
return typeof value === 'string' ? value : undefined
}
return {
getNumber,
getArray,
getString,
}
}

View File

@ -1,19 +1,5 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2024-11-01',
devtools: {
enabled: true,
timeline: {
enabled: true,
},
},
modules: ['@nuxtjs/supabase'],
css: ['@picocss/pico'],
app: {
head: {
title: 'Paper Dynasty',
@ -26,10 +12,36 @@ export default defineNuxtConfig({
}
},
compatibilityDate: '2024-11-01',
css: [
'@picocss/pico',
'/assets/css/styles.css'
],
devtools: {
enabled: true,
timeline: {
enabled: true,
},
},
imports: {
dirs: [
'utils',
]
},
modules: ['@nuxtjs/supabase', '@pinia/nuxt'],
runtimeConfig: {
public: {
supabaseKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNucGhwbnV2aGp2cXprY2J3emRrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDU4MTE3ODQsImV4cCI6MjA2MTM4Nzc4NH0.k3V9c2oiG8kufPa3_a4v6UdiGI6ML6-5lH2oifStB3I',
supabaseUrl: 'https://cnphpnuvhjvqzkcbwzdk.supabase.co'
supabaseUrl: 'https://cnphpnuvhjvqzkcbwzdk.supabase.co',
supabaseRestURL: 'https://cnphpnuvhjvqzkcbwzdk.supabase.co/rest/v1',
// webpageBaseUrl: 'http://localhost:3000',
webpageBaseUrl: 'https://paper-dynasty.netlify.app',
}
},
@ -37,7 +49,7 @@ export default defineNuxtConfig({
redirectOptions: {
login: '/login',
callback: '/confirm',
exclude: ['/'],
exclude: ['/', '/login/auto'],
saveRedirectToCookie: true,
},
},

163
package-lock.json generated
View File

@ -9,9 +9,15 @@
"dependencies": {
"@nuxtjs/supabase": "^1.5.0",
"@picocss/pico": "^2.1.1",
"@pinia/nuxt": "^0.11.0",
"nuxt": "^3.17.1",
"pinia": "^3.0.2",
"vue": "^3.5.13",
"vue-router": "^4.5.1"
},
"devDependencies": {
"prettier": "^3.5.3",
"supabase": "^2.22.12"
}
},
"node_modules/@ampproject/remapping": {
@ -3013,6 +3019,21 @@
"integrity": "sha512-kIDugA7Ps4U+2BHxiNHmvgPIQDWPDU4IeU6TNRdvXQM1uZX+FibqDQT2xUOnnO2yq/LUHcwnGlu1hvf4KfXnMg==",
"license": "MIT"
},
"node_modules/@pinia/nuxt": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.11.0.tgz",
"integrity": "sha512-QGFlUAkeVAhPCTXacrtNP4ti24sGEleVzmxcTALY9IkS6U5OUox7vmNL1pkqBeW39oSNq/UC5m40ofDEPHB1fg==",
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.9.0"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"pinia": "^3.0.2"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -4611,6 +4632,23 @@
],
"license": "MIT"
},
"node_modules/bin-links": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bin-links/-/bin-links-5.0.0.tgz",
"integrity": "sha512-sdleLVfCjBtgO5cNjA2HVRvWBJAHs4zwenaCPMNJAJU0yNxpzj80IpjOIimkpkr+mhlA+how5poQtt53PygbHA==",
"dev": true,
"license": "ISC",
"dependencies": {
"cmd-shim": "^7.0.0",
"npm-normalize-package-bin": "^4.0.0",
"proc-log": "^5.0.0",
"read-cmd-shim": "^5.0.0",
"write-file-atomic": "^6.0.0"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
@ -5003,6 +5041,16 @@
"node": ">=0.10.0"
}
},
"node_modules/cmd-shim": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-7.0.0.tgz",
"integrity": "sha512-rtpaCbr164TPPh+zFdkWpCyZuKkjpAzODfaZCf/SVJZzJN+4bHQb/LP3Jzq5/+84um3XXY8r548XiWKSborwVw==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/color": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
@ -8366,6 +8414,16 @@
"node": ">=0.10.0"
}
},
"node_modules/npm-normalize-package-bin": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
"integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm-run-path": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
@ -8957,6 +9015,36 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pinia": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.2.tgz",
"integrity": "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^7.7.2"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.4.4",
"vue": "^2.7.0 || ^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/@vue/devtools-api": {
"version": "7.7.6",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.6.tgz",
"integrity": "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==",
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^7.7.6"
}
},
"node_modules/pkg-types": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
@ -9539,6 +9627,22 @@
"node": "^14.14.0 || >=16.0.0"
}
},
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-bytes": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz",
@ -9551,6 +9655,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/proc-log": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz",
"integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@ -9686,6 +9800,16 @@
"destr": "^2.0.3"
}
},
"node_modules/read-cmd-shim": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-5.0.0.tgz",
"integrity": "sha512-SEbJV7tohp3DAAILbEMPXavBjAnMN0tVnh4+9G8ihV4Pq3HYF9h8QNez9zkJ1ILkv9G2BjdzwctznGZXgu/HGw==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/read-package-up": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
@ -10627,6 +10751,45 @@
"node": ">=4"
}
},
"node_modules/supabase": {
"version": "2.22.12",
"resolved": "https://registry.npmjs.org/supabase/-/supabase-2.22.12.tgz",
"integrity": "sha512-PWQT+uzwAXcamM/FK60CaWRjVwsX2SGW5vF7edbiTQC6vsNvTBnSIvd1yiXsIpq32uzQFu+iOrayxaTQytNiTw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"bin-links": "^5.0.0",
"https-proxy-agent": "^7.0.2",
"node-fetch": "^3.3.2",
"tar": "7.4.3"
},
"bin": {
"supabase": "bin/supabase"
},
"engines": {
"npm": ">=8"
}
},
"node_modules/supabase/node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/superjson": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",

View File

@ -7,13 +7,20 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
"postinstall": "nuxt prepare",
"gen:types": "npx supabase gen types typescript --project-id cnphpnuvhjvqzkcbwzdk > types/supabase.d.ts && prettier --write types/supabase.d.ts"
},
"dependencies": {
"@nuxtjs/supabase": "^1.5.0",
"@picocss/pico": "^2.1.1",
"@pinia/nuxt": "^0.11.0",
"nuxt": "^3.17.1",
"pinia": "^3.0.2",
"vue": "^3.5.13",
"vue-router": "^4.5.1"
},
"devDependencies": {
"prettier": "^3.5.3",
"supabase": "^2.22.12"
}
}

View File

@ -1,15 +1,41 @@
<script setup lang="ts">
import type { Database } from '~/types/supabase'
const user = useSupabaseUser()
const client = useSupabaseClient<Database>()
const redirectInfo = useSupabaseCookieRedirect()
watch(user, () => {
watch(user, async (newUser) => {
if (newUser) {
console.log('Logged-in user: ', newUser)
// Update profile with Discord username and avatar
const { error } = await client.from('profiles')
.upsert({
id: newUser.id,
discord_username: newUser.user_metadata?.full_name || 'Unknown',
avatar_url: newUser.user_metadata?.avatar_url || '',
discord_id: newUser.user_metadata?.provider_id || '',
})
.eq('id', newUser.id)
if (error) {
console.error('Error updating profile with Discord info:', error)
}
else {
console.log('Profile updated with Discord username and avatar')
}
}
if (user.value) {
// Get redirect path, and clear it from the cookie
const path = redirectInfo.pluck()
let path = redirectInfo.pluck()
// Redirect to the saved path, or fallback to home
if (path?.includes('login')) path = '/'
return navigateTo(path || '/')
}
}, { immediate: true })
}},
{ immediate: true }
)
</script>
<template>

View File

@ -1,35 +0,0 @@
<script setup lang="ts">
const supabase = useSupabaseClient()
const email = ref('')
// const sighInWithDiscord = async () => {
// const { data, error } = await supabase.auth.signInWithOAuth({
// provider: 'discord',
// options: {
// redirectTo: 'http://localhost:3000/confirm'
// }
// })
// if (error) console.log(error)
// }
const signInWithOtp = async () => {
const { error } = await supabase.auth.signInWithOtp({
email: email.value,
options: {
emailRedirectTo: 'http://localhost:3000/confirm',
}
})
if (error) console.log(error)
}
</script>
<template>
<div>
<button @click="signInWithOtp">
Sign In with E-Mail
</button>
<input
v-model="email"
type="email"
/>
</div>
</template>

View File

@ -0,0 +1,35 @@
<script setup lang="ts">
const supabase = useSupabaseClient()
const client = useSupabaseClient()
const config = useRuntimeConfig()
onMounted(async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'discord',
options: {
redirectTo: `${config.public.webpageBaseUrl}/confirm`
}
})
if (error) {
console.error('OAuth login failed:', error)
}
})
</script>
<template>
<div class="flex justify-center items-center min-h-screen">
<Transition name="fade">
<p class="text-lg">Redirecting to Discord...</p>
</Transition>
</div>
</template>
<style scoped>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>

23
pages/login/index.vue Normal file
View File

@ -0,0 +1,23 @@
<script setup lang="ts">
const supabase = useSupabaseClient()
const email = ref('')
const config = useRuntimeConfig()
const signInWithDiscord = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'discord',
options: {
redirectTo: `${config.public.webpageBaseUrl}/confirm`
}
})
if (error) console.log('OAuth login failed:', error)
}
</script>
<template>
<div>
<button @click="signInWithDiscord">
Login with Discord
</button>
</div>
</template>

9
pages/marketplace.vue Normal file
View File

@ -0,0 +1,9 @@
<template>
<section>
<h1>Marketplace</h1>
<Marketplace />
</section>
</template>
<script lang="ts" setup>
</script>

View File

@ -4,8 +4,11 @@
const route = useRoute()
const playerId = route.params.id
const user = useSupabaseUser()
const client = useSupabaseClient()
console.log('current user:', user)
const { data: player, pending, error } = await useAsyncData<Player | null>(
'players',
async () => {
@ -14,8 +17,7 @@
.eq('id', playerId)
.single()
console.log(`player:`)
console.log(data)
console.log(`player:`, data)
return data
},
{

View File

@ -2,19 +2,19 @@
import type { Player } from '~/types/Player'
// const config = useRuntimeConfig()
const user = useSupabaseUser()
const client = useSupabaseClient()
console.log('current user:', user)
const { data: playerList, pending, error } = await useAsyncData<Player[] | null>(
'random_player',
async () => {
const { data } = await client.from('random_player')
.select('*,rarity!inner(*),mlb_player!inner(*)')
.eq('franchise', 'Baltimore Orioles')
.eq('mlb_player.offense_col', 1)
.limit(3)
console.log('players from supabase: ')
console.log(data)
console.log('players from supabase: ', data)
return data
},
{

24
stores/marketplace.ts Normal file
View File

@ -0,0 +1,24 @@
import { defineStore } from 'pinia'
export const useMarketplaceStore = defineStore('marketplace', {
state: () => ({
minCost: null as number | null,
maxCost: null as number | null,
rarities: [] as string[],
cardset: [] as string[],
}),
actions: {
setFilters(filters: Partial<{ minCost: number, maxCost: number, rarities: string[], cardset: string[] }>) {
if (filters.minCost !== undefined) this.minCost = filters.minCost
if (filters.maxCost !== undefined) this.maxCost = filters.maxCost
if (filters.rarities !== undefined) this.rarities = filters.rarities
if (filters.cardset !== undefined) this.cardset = filters.cardset
},
clearFilters() {
this.minCost = null
this.maxCost = null
this.rarities = []
this.cardset = []
}
}
})

12
types/MarketplacePlayer.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
export interface MarketplacePlayer {
player_id: number
player_name: string
cardset_name: string
player_cost: number
rarity_name: string
rarity_color: string
franchise_name: string
player_headshot: string
player_card_image: string
player_card_image2: string
}

884
types/supabase.d.ts vendored Normal file
View File

@ -0,0 +1,884 @@
export type Json =
| string
| number
| boolean
| null
| { [key: string]: Json | undefined }
| Json[];
export type Database = {
public: {
Tables: {
cards: {
Row: {
created_at: string;
id: number;
pack_id: number | null;
player_id: number;
team_id: number;
variant: number | null;
};
Insert: {
created_at?: string;
id?: number;
pack_id?: number | null;
player_id: number;
team_id: number;
variant?: number | null;
};
Update: {
created_at?: string;
id?: number;
pack_id?: number | null;
player_id?: number;
team_id?: number;
variant?: number | null;
};
Relationships: [
{
foreignKeyName: "cards_pack_id_fkey";
columns: ["pack_id"];
isOneToOne: false;
referencedRelation: "packs";
referencedColumns: ["id"];
},
{
foreignKeyName: "cards_player_id_fkey";
columns: ["player_id"];
isOneToOne: false;
referencedRelation: "marketplace";
referencedColumns: ["player_id"];
},
{
foreignKeyName: "cards_player_id_fkey";
columns: ["player_id"];
isOneToOne: false;
referencedRelation: "players";
referencedColumns: ["id"];
},
{
foreignKeyName: "cards_player_id_fkey";
columns: ["player_id"];
isOneToOne: false;
referencedRelation: "random_player";
referencedColumns: ["id"];
},
{
foreignKeyName: "cards_team_id_fkey";
columns: ["team_id"];
isOneToOne: false;
referencedRelation: "teams";
referencedColumns: ["id"];
},
];
};
cardsets: {
Row: {
created_at: string;
description: string | null;
for_purchase: boolean;
id: number;
in_packs: boolean;
name: string;
ranked_legal: boolean;
total_cards: number | null;
};
Insert: {
created_at?: string;
description?: string | null;
for_purchase?: boolean;
id?: number;
in_packs?: boolean;
name: string;
ranked_legal?: boolean;
total_cards?: number | null;
};
Update: {
created_at?: string;
description?: string | null;
for_purchase?: boolean;
id?: number;
in_packs?: boolean;
name?: string;
ranked_legal?: boolean;
total_cards?: number | null;
};
Relationships: [];
};
lineups: {
Row: {
batting_order: number | null;
created_at: string;
id: number;
position: string;
rostered_player_id: number;
};
Insert: {
batting_order?: number | null;
created_at?: string;
id?: number;
position: string;
rostered_player_id: number;
};
Update: {
batting_order?: number | null;
created_at?: string;
id?: number;
position?: string;
rostered_player_id?: number;
};
Relationships: [
{
foreignKeyName: "lineups_rostered_player_id_fkey";
columns: ["rostered_player_id"];
isOneToOne: false;
referencedRelation: "rostered_players";
referencedColumns: ["id"];
},
];
};
mlb_player: {
Row: {
first_name: string | null;
id: number;
key_bbref: string | null;
key_fangraphs: number | null;
key_mlbam: number | null;
key_retro: string | null;
last_name: string | null;
offense_col: number | null;
};
Insert: {
first_name?: string | null;
id?: number;
key_bbref?: string | null;
key_fangraphs?: number | null;
key_mlbam?: number | null;
key_retro?: string | null;
last_name?: string | null;
offense_col?: number | null;
};
Update: {
first_name?: string | null;
id?: number;
key_bbref?: string | null;
key_fangraphs?: number | null;
key_mlbam?: number | null;
key_retro?: string | null;
last_name?: string | null;
offense_col?: number | null;
};
Relationships: [];
};
pack_type: {
Row: {
card_count: number | null;
cost: number;
created_at: string;
description: string | null;
for_purchase: boolean | null;
id: number;
name: string;
};
Insert: {
card_count?: number | null;
cost: number;
created_at?: string;
description?: string | null;
for_purchase?: boolean | null;
id?: number;
name: string;
};
Update: {
card_count?: number | null;
cost?: number;
created_at?: string;
description?: string | null;
for_purchase?: boolean | null;
id?: number;
name?: string;
};
Relationships: [];
};
packs: {
Row: {
created_at: string;
id: number;
open_time: string | null;
owner_team_id: number | null;
pack_cardset_id: number | null;
pack_team_id: number | null;
pack_type_id: number | null;
};
Insert: {
created_at?: string;
id?: number;
open_time?: string | null;
owner_team_id?: number | null;
pack_cardset_id?: number | null;
pack_team_id?: number | null;
pack_type_id?: number | null;
};
Update: {
created_at?: string;
id?: number;
open_time?: string | null;
owner_team_id?: number | null;
pack_cardset_id?: number | null;
pack_team_id?: number | null;
pack_type_id?: number | null;
};
Relationships: [
{
foreignKeyName: "packs_owner_team_id_fkey";
columns: ["owner_team_id"];
isOneToOne: false;
referencedRelation: "teams";
referencedColumns: ["id"];
},
{
foreignKeyName: "packs_pack_cardset_id_fkey";
columns: ["pack_cardset_id"];
isOneToOne: false;
referencedRelation: "cardsets";
referencedColumns: ["id"];
},
{
foreignKeyName: "packs_pack_team_id_fkey";
columns: ["pack_team_id"];
isOneToOne: false;
referencedRelation: "teams";
referencedColumns: ["id"];
},
{
foreignKeyName: "packs_pack_type_id_fkey";
columns: ["pack_type_id"];
isOneToOne: false;
referencedRelation: "pack_type";
referencedColumns: ["id"];
},
];
};
players: {
Row: {
bbref_id: string | null;
cardset_id: number;
cost: number;
created_at: string;
description: string;
fangr_id: string | null;
franchise: Database["public"]["Enums"]["franchise"] | null;
headshot: string | null;
id: number;
image: string;
image2: string | null;
mlbclub: Database["public"]["Enums"]["franchise"] | null;
mlbplayer_id: number | null;
name: string;
positions: string[] | null;
quantity: number;
rarity_id: number;
set_num: number | null;
strat_code: string | null;
vanity_card: string | null;
};
Insert: {
bbref_id?: string | null;
cardset_id: number;
cost: number;
created_at?: string;
description: string;
fangr_id?: string | null;
franchise?: Database["public"]["Enums"]["franchise"] | null;
headshot?: string | null;
id?: number;
image: string;
image2?: string | null;
mlbclub?: Database["public"]["Enums"]["franchise"] | null;
mlbplayer_id?: number | null;
name: string;
positions?: string[] | null;
quantity?: number;
rarity_id: number;
set_num?: number | null;
strat_code?: string | null;
vanity_card?: string | null;
};
Update: {
bbref_id?: string | null;
cardset_id?: number;
cost?: number;
created_at?: string;
description?: string;
fangr_id?: string | null;
franchise?: Database["public"]["Enums"]["franchise"] | null;
headshot?: string | null;
id?: number;
image?: string;
image2?: string | null;
mlbclub?: Database["public"]["Enums"]["franchise"] | null;
mlbplayer_id?: number | null;
name?: string;
positions?: string[] | null;
quantity?: number;
rarity_id?: number;
set_num?: number | null;
strat_code?: string | null;
vanity_card?: string | null;
};
Relationships: [
{
foreignKeyName: "players_cardset_id_fkey";
columns: ["cardset_id"];
isOneToOne: false;
referencedRelation: "cardsets";
referencedColumns: ["id"];
},
{
foreignKeyName: "players_mlbplayer_id_fkey";
columns: ["mlbplayer_id"];
isOneToOne: false;
referencedRelation: "mlb_player";
referencedColumns: ["id"];
},
{
foreignKeyName: "players_rarity_id_fkey";
columns: ["rarity_id"];
isOneToOne: false;
referencedRelation: "rarity";
referencedColumns: ["id"];
},
];
};
profiles: {
Row: {
avatar_url: string | null;
created_at: string | null;
discord_id: string | null;
discord_username: string | null;
email: string | null;
id: string;
};
Insert: {
avatar_url?: string | null;
created_at?: string | null;
discord_id?: string | null;
discord_username?: string | null;
email?: string | null;
id: string;
};
Update: {
avatar_url?: string | null;
created_at?: string | null;
discord_id?: string | null;
discord_username?: string | null;
email?: string | null;
id?: string;
};
Relationships: [];
};
rarity: {
Row: {
color: string;
created_at: string;
id: number;
name: string;
value: number;
};
Insert: {
color: string;
created_at?: string;
id?: number;
name: string;
value: number;
};
Update: {
color?: string;
created_at?: string;
id?: number;
name?: string;
value?: number;
};
Relationships: [];
};
rostered_players: {
Row: {
card_id: number;
created_at: string;
id: number;
roster_id: number;
};
Insert: {
card_id: number;
created_at?: string;
id?: number;
roster_id: number;
};
Update: {
card_id?: number;
created_at?: string;
id?: number;
roster_id?: number;
};
Relationships: [
{
foreignKeyName: "rostered_players_card_id_fkey";
columns: ["card_id"];
isOneToOne: false;
referencedRelation: "cards";
referencedColumns: ["id"];
},
{
foreignKeyName: "rostered_players_roster_id_fkey";
columns: ["roster_id"];
isOneToOne: false;
referencedRelation: "rosters";
referencedColumns: ["id"];
},
];
};
rosters: {
Row: {
created_at: string;
description: string | null;
id: number;
name: string;
team_id: number;
};
Insert: {
created_at?: string;
description?: string | null;
id?: number;
name: string;
team_id: number;
};
Update: {
created_at?: string;
description?: string | null;
id?: number;
name?: string;
team_id?: number;
};
Relationships: [
{
foreignKeyName: "rosters_team_id_fkey";
columns: ["team_id"];
isOneToOne: false;
referencedRelation: "teams";
referencedColumns: ["id"];
},
];
};
teams: {
Row: {
abbrev: string | null;
career: string | null;
collection_value: string | null;
color: string | null;
discord_id: string;
event_id: string | null;
gm_profile_id: string | null;
gmid: number | null;
gmname: string | null;
gsheet: string | null;
has_guide: string | null;
id: number;
is_ai: number | null;
lname: string | null;
logo: string | null;
ranking: number | null;
season: number | null;
sname: string | null;
team_value: string | null;
wallet: number | null;
};
Insert: {
abbrev?: string | null;
career?: string | null;
collection_value?: string | null;
color?: string | null;
discord_id: string;
event_id?: string | null;
gm_profile_id?: string | null;
gmid?: number | null;
gmname?: string | null;
gsheet?: string | null;
has_guide?: string | null;
id?: number;
is_ai?: number | null;
lname?: string | null;
logo?: string | null;
ranking?: number | null;
season?: number | null;
sname?: string | null;
team_value?: string | null;
wallet?: number | null;
};
Update: {
abbrev?: string | null;
career?: string | null;
collection_value?: string | null;
color?: string | null;
discord_id?: string;
event_id?: string | null;
gm_profile_id?: string | null;
gmid?: number | null;
gmname?: string | null;
gsheet?: string | null;
has_guide?: string | null;
id?: number;
is_ai?: number | null;
lname?: string | null;
logo?: string | null;
ranking?: number | null;
season?: number | null;
sname?: string | null;
team_value?: string | null;
wallet?: number | null;
};
Relationships: [
{
foreignKeyName: "teams_gm_profile_id_fkey";
columns: ["gm_profile_id"];
isOneToOne: false;
referencedRelation: "profiles";
referencedColumns: ["id"];
},
];
};
};
Views: {
marketplace: {
Row: {
cardset_name: string | null;
franchise_name: Database["public"]["Enums"]["franchise"] | null;
player_card_image: string | null;
player_card_image2: string | null;
player_cost: number | null;
player_headshot: string | null;
player_id: number | null;
player_name: string | null;
player_positions: string[] | null;
rarity_color: string | null;
rarity_name: string | null;
};
Relationships: [];
};
random_player: {
Row: {
bbref_id: string | null;
cardset_id: number | null;
cost: number | null;
created_at: string | null;
description: string | null;
fangr_id: string | null;
franchise: Database["public"]["Enums"]["franchise"] | null;
headshot: string | null;
id: number | null;
image: string | null;
image2: string | null;
mlbclub: Database["public"]["Enums"]["franchise"] | null;
mlbplayer_id: number | null;
name: string | null;
positions: string[] | null;
quantity: number | null;
rarity_id: number | null;
set_num: number | null;
strat_code: string | null;
vanity_card: string | null;
};
Insert: {
bbref_id?: string | null;
cardset_id?: number | null;
cost?: number | null;
created_at?: string | null;
description?: string | null;
fangr_id?: string | null;
franchise?: Database["public"]["Enums"]["franchise"] | null;
headshot?: string | null;
id?: number | null;
image?: string | null;
image2?: string | null;
mlbclub?: Database["public"]["Enums"]["franchise"] | null;
mlbplayer_id?: number | null;
name?: string | null;
positions?: string[] | null;
quantity?: number | null;
rarity_id?: number | null;
set_num?: number | null;
strat_code?: string | null;
vanity_card?: string | null;
};
Update: {
bbref_id?: string | null;
cardset_id?: number | null;
cost?: number | null;
created_at?: string | null;
description?: string | null;
fangr_id?: string | null;
franchise?: Database["public"]["Enums"]["franchise"] | null;
headshot?: string | null;
id?: number | null;
image?: string | null;
image2?: string | null;
mlbclub?: Database["public"]["Enums"]["franchise"] | null;
mlbplayer_id?: number | null;
name?: string | null;
positions?: string[] | null;
quantity?: number | null;
rarity_id?: number | null;
set_num?: number | null;
strat_code?: string | null;
vanity_card?: string | null;
};
Relationships: [
{
foreignKeyName: "players_cardset_id_fkey";
columns: ["cardset_id"];
isOneToOne: false;
referencedRelation: "cardsets";
referencedColumns: ["id"];
},
{
foreignKeyName: "players_mlbplayer_id_fkey";
columns: ["mlbplayer_id"];
isOneToOne: false;
referencedRelation: "mlb_player";
referencedColumns: ["id"];
},
{
foreignKeyName: "players_rarity_id_fkey";
columns: ["rarity_id"];
isOneToOne: false;
referencedRelation: "rarity";
referencedColumns: ["id"];
},
];
};
};
Functions: {
[_ in never]: never;
};
Enums: {
franchise:
| "Arizona Diamondbacks"
| "Atlanta Braves"
| "Baltimore Orioles"
| "Boston Red Sox"
| "Chicago Cubs"
| "Chicago White Sox"
| "Cincinnati Reds"
| "Cleveland Guardians"
| "Colorado Rockies"
| "Detroit Tigers"
| "Houston Astros"
| "Kansas City Royals"
| "Los Angeles Angels"
| "Los Angeles Dodgers"
| "Miami Marlins"
| "Milwaukee Brewers"
| "Minnesota Twins"
| "New York Mets"
| "New York Yankees"
| "Oakland Athletics"
| "Philadelphia Phillies"
| "Pittsburgh Pirates"
| "San Diego Padres"
| "San Francisco Giants"
| "Seattle Mariners"
| "St Louis Cardinals"
| "Tampa Bay Rays"
| "Texas Rangers"
| "Toronto Blue Jays"
| "Washington Nationals"
| "Anaheim Angels"
| "Brilliant Stars"
| "Cleveland Indians"
| "Custom Ballplayers"
| "Junior All Stars"
| "Mario Super Sluggers"
| "Montreal Expos"
| "Tampa Bay Devil Rays";
position:
| "Pitcher"
| "Catcher"
| "First Base"
| "Second Base"
| "Third Base"
| "Shorstop"
| "Left Field"
| "Center Field"
| "Right Field"
| "Pinch Hitter"
| "Pinch Runner";
};
CompositeTypes: {
[_ in never]: never;
};
};
};
type DefaultSchema = Database[Extract<keyof Database, "public">];
export type Tables<
DefaultSchemaTableNameOrOptions extends
| keyof (DefaultSchema["Tables"] & DefaultSchema["Views"])
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database;
}
? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends {
Row: infer R;
}
? R
: never
: DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] &
DefaultSchema["Views"])
? (DefaultSchema["Tables"] &
DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends {
Row: infer R;
}
? R
: never
: never;
export type TablesInsert<
DefaultSchemaTableNameOrOptions extends
| keyof DefaultSchema["Tables"]
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Insert: infer I;
}
? I
: never
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"]
? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends {
Insert: infer I;
}
? I
: never
: never;
export type TablesUpdate<
DefaultSchemaTableNameOrOptions extends
| keyof DefaultSchema["Tables"]
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Update: infer U;
}
? U
: never
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"]
? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends {
Update: infer U;
}
? U
: never
: never;
export type Enums<
DefaultSchemaEnumNameOrOptions extends
| keyof DefaultSchema["Enums"]
| { schema: keyof Database },
EnumName extends DefaultSchemaEnumNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"]
: never = never,
> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName]
: DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"]
? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions]
: never;
export type CompositeTypes<
PublicCompositeTypeNameOrOptions extends
| keyof DefaultSchema["CompositeTypes"]
| { schema: keyof Database },
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"]
: never = never,
> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }
? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName]
: PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"]
? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions]
: never;
export const Constants = {
public: {
Enums: {
franchise: [
"Arizona Diamondbacks",
"Atlanta Braves",
"Baltimore Orioles",
"Boston Red Sox",
"Chicago Cubs",
"Chicago White Sox",
"Cincinnati Reds",
"Cleveland Guardians",
"Colorado Rockies",
"Detroit Tigers",
"Houston Astros",
"Kansas City Royals",
"Los Angeles Angels",
"Los Angeles Dodgers",
"Miami Marlins",
"Milwaukee Brewers",
"Minnesota Twins",
"New York Mets",
"New York Yankees",
"Oakland Athletics",
"Philadelphia Phillies",
"Pittsburgh Pirates",
"San Diego Padres",
"San Francisco Giants",
"Seattle Mariners",
"St Louis Cardinals",
"Tampa Bay Rays",
"Texas Rangers",
"Toronto Blue Jays",
"Washington Nationals",
"Anaheim Angels",
"Brilliant Stars",
"Cleveland Indians",
"Custom Ballplayers",
"Junior All Stars",
"Mario Super Sluggers",
"Montreal Expos",
"Tampa Bay Devil Rays",
],
position: [
"Pitcher",
"Catcher",
"First Base",
"Second Base",
"Third Base",
"Shorstop",
"Left Field",
"Center Field",
"Right Field",
"Pinch Hitter",
"Pinch Runner",
],
},
},
} as const;

20
utils/playerMapper.ts Normal file
View File

@ -0,0 +1,20 @@
import type { MarketplacePlayer } from "~/types/MarketplacePlayer";
import type { Player } from "~/types/Player";
export function mapMarketplacePlayersToPlayers(marketplacePlayers: MarketplacePlayer[]): Player[] {
return marketplacePlayers.map(mp => ({
id: mp.player_id,
name: mp.player_name,
cost: mp.player_cost,
image: mp.player_card_image,
headshot: mp.player_headshot,
description: '',
franchise: mp.franchise_name,
rarity: {
id: 0,
name: mp.rarity_name,
color: mp.rarity_color,
value: 0,
},
}))
}