working team update/create (still need enroll)

This commit is contained in:
yohlo
2025-09-16 13:24:39 -05:00
parent cde74a04d5
commit c170e1e1fe
16 changed files with 845 additions and 175 deletions

View File

@@ -31,6 +31,7 @@ import { Route as AuthedAdminTournamentsRunIdRouteImport } from './routes/_authe
import { ServerRoute as ApiTournamentsUploadLogoServerRouteImport } from './routes/api/tournaments/upload-logo'
import { ServerRoute as ApiTeamsUploadLogoServerRouteImport } from './routes/api/teams/upload-logo'
import { ServerRoute as ApiSpotifyTokenServerRouteImport } from './routes/api/spotify/token'
import { ServerRoute as ApiSpotifySearchServerRouteImport } from './routes/api/spotify/search'
import { ServerRoute as ApiSpotifyResumeServerRouteImport } from './routes/api/spotify/resume'
import { ServerRoute as ApiSpotifyPlaybackServerRouteImport } from './routes/api/spotify/playback'
import { ServerRoute as ApiSpotifyCaptureServerRouteImport } from './routes/api/spotify/capture'
@@ -146,6 +147,11 @@ const ApiSpotifyTokenServerRoute = ApiSpotifyTokenServerRouteImport.update({
path: '/api/spotify/token',
getParentRoute: () => rootServerRouteImport,
} as any)
const ApiSpotifySearchServerRoute = ApiSpotifySearchServerRouteImport.update({
id: '/api/spotify/search',
path: '/api/spotify/search',
getParentRoute: () => rootServerRouteImport,
} as any)
const ApiSpotifyResumeServerRoute = ApiSpotifyResumeServerRouteImport.update({
id: '/api/spotify/resume',
path: '/api/spotify/resume',
@@ -310,6 +316,7 @@ export interface FileServerRoutesByFullPath {
'/api/spotify/capture': typeof ApiSpotifyCaptureServerRoute
'/api/spotify/playback': typeof ApiSpotifyPlaybackServerRoute
'/api/spotify/resume': typeof ApiSpotifyResumeServerRoute
'/api/spotify/search': typeof ApiSpotifySearchServerRoute
'/api/spotify/token': typeof ApiSpotifyTokenServerRoute
'/api/teams/upload-logo': typeof ApiTeamsUploadLogoServerRoute
'/api/tournaments/upload-logo': typeof ApiTournamentsUploadLogoServerRoute
@@ -322,6 +329,7 @@ export interface FileServerRoutesByTo {
'/api/spotify/capture': typeof ApiSpotifyCaptureServerRoute
'/api/spotify/playback': typeof ApiSpotifyPlaybackServerRoute
'/api/spotify/resume': typeof ApiSpotifyResumeServerRoute
'/api/spotify/search': typeof ApiSpotifySearchServerRoute
'/api/spotify/token': typeof ApiSpotifyTokenServerRoute
'/api/teams/upload-logo': typeof ApiTeamsUploadLogoServerRoute
'/api/tournaments/upload-logo': typeof ApiTournamentsUploadLogoServerRoute
@@ -335,6 +343,7 @@ export interface FileServerRoutesById {
'/api/spotify/capture': typeof ApiSpotifyCaptureServerRoute
'/api/spotify/playback': typeof ApiSpotifyPlaybackServerRoute
'/api/spotify/resume': typeof ApiSpotifyResumeServerRoute
'/api/spotify/search': typeof ApiSpotifySearchServerRoute
'/api/spotify/token': typeof ApiSpotifyTokenServerRoute
'/api/teams/upload-logo': typeof ApiTeamsUploadLogoServerRoute
'/api/tournaments/upload-logo': typeof ApiTournamentsUploadLogoServerRoute
@@ -349,6 +358,7 @@ export interface FileServerRouteTypes {
| '/api/spotify/capture'
| '/api/spotify/playback'
| '/api/spotify/resume'
| '/api/spotify/search'
| '/api/spotify/token'
| '/api/teams/upload-logo'
| '/api/tournaments/upload-logo'
@@ -361,6 +371,7 @@ export interface FileServerRouteTypes {
| '/api/spotify/capture'
| '/api/spotify/playback'
| '/api/spotify/resume'
| '/api/spotify/search'
| '/api/spotify/token'
| '/api/teams/upload-logo'
| '/api/tournaments/upload-logo'
@@ -373,6 +384,7 @@ export interface FileServerRouteTypes {
| '/api/spotify/capture'
| '/api/spotify/playback'
| '/api/spotify/resume'
| '/api/spotify/search'
| '/api/spotify/token'
| '/api/teams/upload-logo'
| '/api/tournaments/upload-logo'
@@ -386,6 +398,7 @@ export interface RootServerRouteChildren {
ApiSpotifyCaptureServerRoute: typeof ApiSpotifyCaptureServerRoute
ApiSpotifyPlaybackServerRoute: typeof ApiSpotifyPlaybackServerRoute
ApiSpotifyResumeServerRoute: typeof ApiSpotifyResumeServerRoute
ApiSpotifySearchServerRoute: typeof ApiSpotifySearchServerRoute
ApiSpotifyTokenServerRoute: typeof ApiSpotifyTokenServerRoute
ApiTeamsUploadLogoServerRoute: typeof ApiTeamsUploadLogoServerRoute
ApiTournamentsUploadLogoServerRoute: typeof ApiTournamentsUploadLogoServerRoute
@@ -538,6 +551,13 @@ declare module '@tanstack/react-start/server' {
preLoaderRoute: typeof ApiSpotifyTokenServerRouteImport
parentRoute: typeof rootServerRouteImport
}
'/api/spotify/search': {
id: '/api/spotify/search'
path: '/api/spotify/search'
fullPath: '/api/spotify/search'
preLoaderRoute: typeof ApiSpotifySearchServerRouteImport
parentRoute: typeof rootServerRouteImport
}
'/api/spotify/resume': {
id: '/api/spotify/resume'
path: '/api/spotify/resume'
@@ -651,6 +671,7 @@ const rootServerRouteChildren: RootServerRouteChildren = {
ApiSpotifyCaptureServerRoute: ApiSpotifyCaptureServerRoute,
ApiSpotifyPlaybackServerRoute: ApiSpotifyPlaybackServerRoute,
ApiSpotifyResumeServerRoute: ApiSpotifyResumeServerRoute,
ApiSpotifySearchServerRoute: ApiSpotifySearchServerRoute,
ApiSpotifyTokenServerRoute: ApiSpotifyTokenServerRoute,
ApiTeamsUploadLogoServerRoute: ApiTeamsUploadLogoServerRoute,
ApiTournamentsUploadLogoServerRoute: ApiTournamentsUploadLogoServerRoute,

View File

@@ -0,0 +1,81 @@
import { createServerFileRoute } from '@tanstack/react-start/server'
// Function to get Client Credentials access token
async function getClientCredentialsToken(): Promise<string> {
const clientId = process.env.VITE_SPOTIFY_CLIENT_ID
const clientSecret = process.env.SPOTIFY_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw new Error('Missing Spotify client credentials')
}
const response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,
},
body: 'grant_type=client_credentials',
})
if (!response.ok) {
throw new Error('Failed to get Spotify access token')
}
const data = await response.json()
return data.access_token
}
export const ServerRoute = createServerFileRoute('/api/spotify/search').methods({
GET: async ({ request }: { request: Request }) => {
try {
const url = new URL(request.url)
const query = url.searchParams.get('q')
if (!query) {
return new Response(
JSON.stringify({ error: 'Query parameter q is required' }),
{
status: 400,
headers: { 'Content-Type': 'application/json' },
}
)
}
// Get client credentials access token
const accessToken = await getClientCredentialsToken()
// Search using Spotify API directly
const searchUrl = `https://api.spotify.com/v1/search?q=${encodeURIComponent(query)}&type=track&limit=20`
const searchResponse = await fetch(searchUrl, {
headers: {
'Authorization': `Bearer ${accessToken}`,
},
})
if (!searchResponse.ok) {
throw new Error('Spotify search request failed')
}
const searchResult = await searchResponse.json()
return new Response(
JSON.stringify({ tracks: searchResult.tracks.items }),
{
status: 200,
headers: { 'Content-Type': 'application/json' },
}
)
} catch (error) {
console.error('Search error:', error)
return new Response(
JSON.stringify({ error: 'Search failed', details: error instanceof Error ? error.message : 'Unknown error' }),
{
status: 500,
headers: { 'Content-Type': 'application/json' },
}
)
}
},
})