-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
309 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import {serverSupabaseServiceRole, serverSupabaseUser} from "#supabase/server"; | ||
import {mapDatabaseRowsToGames} from "~/server/utils/mapper/game-mapper"; | ||
import {GameStatus} from "~/types/api/game"; | ||
|
||
export default defineEventHandler(async (event) => { | ||
// Require user to be authenticated | ||
const user = await serverSupabaseUser(event); | ||
if (!user?.id) { | ||
setResponseStatus(event, 401); | ||
return {error: 'unauthenticated'}; | ||
} | ||
|
||
// Get user's games | ||
const client = serverSupabaseServiceRole(event); | ||
const {data, error} = await client.rpc('get_player_games', {p_user_id: user.id} as never).select(); | ||
|
||
if (error) { | ||
setResponseStatus(event, 500); | ||
return {error: error.message}; | ||
} | ||
|
||
const games = mapDatabaseRowsToGames(data); | ||
|
||
return { | ||
active: games.filter(game => game.status === GameStatus.PLAYING && game.creator_id !== user.id), | ||
waiting: games.filter(game => game.status === GameStatus.PLAYING && game.creator_id === user.id), | ||
past: games.filter(game => game.status === GameStatus.FINISHED) | ||
} | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Types from your original interfaces | ||
|
||
import type {Game, GameRound, Song} from "~/types/api/game"; | ||
import type {GetUserResponse} from "~/types/api/users"; | ||
import {GameStatus} from "~/types/api/game"; | ||
|
||
interface DatabaseGameRow { | ||
// Game basic info | ||
game_id: number; | ||
status: string; | ||
playlist_id: string; | ||
playlist_cover: string; | ||
playlist_name: string; | ||
created_at: string; | ||
creator_id: string; // who created the game and thus already started playing | ||
|
||
// Opponent info (the other player's data) | ||
opponent_user_id: string; | ||
opponent_avatar_url: string | null; | ||
opponent_username: string; | ||
opponent_spotify_id: string | null; | ||
opponent_spotify_visibility: boolean; | ||
opponent_daily_streak: number | null; | ||
opponent_daily_streak_updated_at: string | null; | ||
|
||
// Round info (the song being played) | ||
round_number: number; // From game_rounds table - the order of the song | ||
correct_song_id: string; | ||
correct_song_name: string; | ||
correct_song_artist: string; | ||
correct_song_preview_url: string | null; | ||
|
||
// Wrong options (the 3 incorrect choices) | ||
wrong_song_1_id: string; | ||
wrong_song_1_name: string; | ||
wrong_song_1_artist: string; | ||
wrong_song_1_preview_url: string | null; | ||
|
||
wrong_song_2_id: string; // Similar to wrong_song_1 | ||
wrong_song_2_name: string; | ||
wrong_song_2_artist: string; | ||
wrong_song_2_preview_url: string | null; | ||
|
||
wrong_song_3_id: string; // Similar to wrong_song_1 | ||
wrong_song_3_name: string; | ||
wrong_song_3_artist: string; | ||
wrong_song_3_preview_url: string | null; | ||
} | ||
|
||
const createSongFromRow = ( | ||
id: string, | ||
name: string, | ||
artist: string, | ||
previewUrl: string | null | ||
): Song => ({ | ||
id, | ||
name, | ||
artists: [{ | ||
id: 'placeholder', // You might want to adjust this based on your needs | ||
name: artist | ||
}], | ||
preview_url: previewUrl, | ||
is_playable: previewUrl !== null | ||
}); | ||
|
||
|
||
export const mapDatabaseRowsToGame = (rows: DatabaseGameRow[]): Game => { | ||
if (rows.length === 0) { | ||
throw new Error('No rows provided to map to Game'); | ||
} | ||
|
||
const firstRow = rows[0]; | ||
|
||
// Map opponent info | ||
const opponent: GetUserResponse = { | ||
id: firstRow.opponent_user_id, | ||
avatar_url: firstRow.opponent_avatar_url ?? undefined, | ||
username: firstRow.opponent_username, | ||
spotify_id: firstRow.opponent_spotify_id ?? undefined, | ||
spotify_visibility: firstRow.opponent_spotify_visibility, | ||
daily_streak: firstRow.opponent_daily_streak ?? undefined, | ||
daily_streak_updated_at: firstRow.opponent_daily_streak_updated_at ?? undefined | ||
}; | ||
|
||
// Map rounds | ||
const rounds: GameRound[] = rows.map(row => ({ | ||
round: row.round_number, | ||
correct_song: createSongFromRow( | ||
row.correct_song_id, | ||
row.correct_song_name, | ||
row.correct_song_artist, | ||
row.correct_song_preview_url | ||
), | ||
wrong_songs: [ | ||
createSongFromRow( | ||
row.wrong_song_1_id, | ||
row.wrong_song_1_name, | ||
row.wrong_song_1_artist, | ||
row.wrong_song_1_preview_url | ||
), | ||
createSongFromRow( | ||
row.wrong_song_2_id, | ||
row.wrong_song_2_name, | ||
row.wrong_song_2_artist, | ||
row.wrong_song_2_preview_url | ||
), | ||
createSongFromRow( | ||
row.wrong_song_3_id, | ||
row.wrong_song_3_name, | ||
row.wrong_song_3_artist, | ||
row.wrong_song_3_preview_url | ||
) | ||
] | ||
})); | ||
|
||
// Construct final game object with players instead of player_ids | ||
return { | ||
game_id: firstRow.game_id, | ||
status: firstRow.status as GameStatus, | ||
creator_id: firstRow.creator_id, | ||
playlist: { | ||
id: firstRow.playlist_id, | ||
name: firstRow.playlist_name, | ||
cover: firstRow.playlist_cover | ||
}, | ||
opponents: [opponent], | ||
songs: rounds, | ||
created_at: firstRow.created_at | ||
}; | ||
}; | ||
|
||
export const mapDatabaseRowsToGames = (rows: DatabaseGameRow[]): Game[] => { | ||
if (rows.length === 0) return []; | ||
|
||
// Group rows by game_id | ||
const gameRows = new Map<number, DatabaseGameRow[]>(); | ||
rows.forEach(row => { | ||
const currentRows = gameRows.get(row.game_id) ?? []; | ||
gameRows.set(row.game_id, [...currentRows, row]); | ||
}); | ||
|
||
// Map each group of rows to a Game | ||
return Array.from(gameRows.values()) | ||
.map(gameRows => mapDatabaseRowsToGame(gameRows)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
import type url from "node:url"; | ||
|
||
export interface GetUserResponse { | ||
id: string, | ||
avatar_url?: url.URL | null, | ||
avatar_url?: string, | ||
username: string, | ||
spotify_id?: string, | ||
spotify_visibility: boolean, | ||
daily_streak: number, | ||
daily_streak_updated_at: string | ||
daily_streak?: number, | ||
daily_streak_updated_at?: string | ||
} |