/** * Import types from Nadal. */ import type { GameCategoriesResponseData, GameGamesRequestPayload, GameTopChampionResponseData, GameTopWinningResponseData, } from '@kira-dancer/nadal' import type { GameItem, GamesRequestPayload, ProviderGameItem, Period, GameTopWinningRequest, } from '#lib/types' import { useJackpot } from '#lib/composables/jackpot' import { useGames } from '#lib/composables/game/use-games' import { useAsyncData, useNuxtData } from 'nuxt/app' import { reactive, ref } from 'vue' import { useApiFetch } from '#lib/composables/service/use-api-fetch' import { GAME_API } from '#lib/configs' import { AppDataEnum } from '#lib/enums' import { useNadal } from '#lib/composables' /** * Provides functionality for managing and interacting with lobby games, * including fetching games, providers, categories, top winners, and champions. * This composable also supports filtering, searching, and pagination of games. * * @returns {Object} An object containing functions and reactive variables for managing lobby games. * @namespace */ export function useLobbyGames(key: string = 'game') { const { getJackpotNumberByGameId, fetchGameJackpots } = useJackpot() const { playGame } = useGames() const { request } = useApiFetch() const { game } = useNadal() const isLoadingGame = ref(false) const allLobbyGames = ref([]) const totalGame = ref(0) const gameProviders = ref([]) const gameCategories = ref([]) const { data: lobbyGames } = useNuxtData( AppDataEnum.LobbyGames + key, ) const { data: gameTopChampion } = useNuxtData( AppDataEnum.TopChampion, ) const { data: topWinners } = useNuxtData( AppDataEnum.TopWinning, ) const providerSelected = reactive({ name: '', slug: '', }) const categorySelected = reactive({ name: '', slug: '', }) const gamePayload = reactive({ cats: '', paged: 1, offset: 0, groups: '', prov: '', search: '', }) /** * Fetches games based on the given request payload. * * @param {GamesRequestPayload} payload The payload containing filters and options for fetching games. * @returns {Promise} A promise that resolves to a list of games. */ const fetchGames = async ( payload: GamesRequestPayload, ): Promise => { isLoadingGame.value = true const { data } = await useAsyncData( AppDataEnum.LobbyGames + key, async () => { return await requestFetchGames(payload) }, ) isLoadingGame.value = false return data.value! } /** * Fetches games based on the given request payload. * * @param {GamesRequestPayload} payload The payload containing filters and options for fetching games. * @returns {Promise} A promise that resolves to a list of games. */ const requestFetchGames = async (payload: GamesRequestPayload) => { const { data } = await request( GAME_API.GAMES, payload, ) if (data?.length) { data.forEach((game: GameItem) => { game.partnerGameId = game?.partner_game_id }) return data } return [] } /** * Fetches games with additional metadata based on the provided request payload. * * @param {GamesRequestPayload} payload - The payload containing filters and options for fetching games. * @returns {Promise<{ data: GameItem[], metaData: { currentPage: number, total: number, totalPages: number } }>} A promise that resolves to an object containing the list of games and metadata. */ const requestFetchGamesV2 = async (payload: GamesRequestPayload) => { const { data, metaData } = await request( GAME_API.GAMES, payload, ) if (data?.length) { data.forEach((game: GameItem) => { game.partnerGameId = game?.partner_game_id }) return { data, metaData } } return { data: [], metaData: { currentPage: 0, total: 0, totalPages: 0 } } } /** * Fetches all games for the lobby based on the given category and limits the number of games. * * @param {GamesRequestPayload} payload The payload containing filters and options for fetching games. * @param {number} gameLimit The maximum number of games to fetch. * @returns {Promise} A promise that resolves to a list of games. */ const fetchAllLobbyGameByCategory = async ( payload: GamesRequestPayload, gameLimit: number, ): Promise => { const games = await fetchGames(payload) allLobbyGames.value = games lobbyGames.value = allLobbyGames.value.slice(0, gameLimit) totalGame.value = allLobbyGames.value.length return games } /** * Fetches the list of game providers. * * @returns {Promise} A promise that resolves to a list of game providers. */ const fetchGameProviders = async (): Promise => { const providers = await game.gameProviders() if (providers?.length) { gameProviders.value = providers return providers } return [] } /** * Fetches the list of game categories. * * GameCategoriesResponseData type is imported from the Nadal module. * * GameGamesRequestPayload type is imported from the Nadal module. * * @param {GameGamesRequestPayload} [payload] Optional payload for fetching categories. * @returns {Promise} A promise that resolves to a list of game categories. */ const fetchGameCategories = async ( payload?: GameGamesRequestPayload, ): Promise => { const categories = await game.gameCategories< GameGamesRequestPayload, GameCategoriesResponseData[] >(payload) if (categories?.length) { gameCategories.value = categories return categories } return [] } /** * Fetches the top winning games based on the game type and period. * * GameTopWinningResponseData type is imported from the Nadal module. * * @param {string} [gameType=''] The type of game to filter by. * @param {Period} period The period for which to fetch top winners. * @returns {Promise} A promise that resolves to a list of top winning games. */ const fetchTopWinning = async ( gameType = '', period: Period, ): Promise => { const { data } = await useAsyncData(AppDataEnum.TopWinning, async () => { try { const { data } = await request< GameTopWinningRequest, GameTopWinningResponseData[] >(GAME_API.TOP_WINNING_GAME, { gameType, period, }) return data } catch (ex) { console.error(' ~ fetchTopWinning ~ ex:', ex) return [] } }) return data.value! } /** * Fetches the top champions based on the game type. * * GameTopChampionResponseData type is imported from the Nadal module. * * @param {string} gameType The type of game to filter by. * @returns {Promise} A promise that resolves to a list of top champions. */ const fetchGameTopChampion = async ( gameType: string, ): Promise => { const { data } = await useAsyncData(AppDataEnum.TopChampion, async () => { try { const { data } = await request< { gameType: string }, GameTopChampionResponseData[] >(GAME_API.TOP_CHAMPION, { gameType, }) return data } catch { return [] } }) return data.value! } /** * Filters the lobby games based on the given payload and updates the displayed games. * * @param {GamesRequestPayload} payload The payload containing filters for games. * @param {number} gameLimit The maximum number of games to display. * @param {boolean} [isLoadMore=false] Flag indicating if more games should be loaded. */ const filterLobbyGames = ( payload: GamesRequestPayload, gameLimit: number, isLoadMore = false, ): void => { const currentLobbyGames: GameItem[] = [...allLobbyGames.value].filter( (item) => { let flag = true if (payload.prov) { flag = item.provider?.includes(payload.prov) ?? false } if (flag && payload.groups) { flag = item.group?.includes(payload.groups) ?? false } return flag }, ) totalGame.value = currentLobbyGames.length ?? 0 const offset: number = ((payload.paged ?? 1) - 1) * gameLimit const itemPerPage: number = Math.min(offset + gameLimit, totalGame.value) const newItems = currentLobbyGames.slice(offset, itemPerPage) if (isLoadMore) { lobbyGames.value = [...lobbyGames.value!, ...newItems] } else { lobbyGames.value = newItems } } /** * Applies the provided filters and fetches the filtered games. * * @param {GameGamesRequestPayload} payload The payload containing filters and options for fetching games. */ const onFilter = async (payload: GameGamesRequestPayload) => { gamePayload.prov = payload.prov gamePayload.cats = payload.cats gamePayload.paged = 1 providerSelected.name = payload.providerName ?? '' providerSelected.slug = payload.prov ?? '' categorySelected.name = payload.categoryName ?? '' categorySelected.slug = payload.cats ?? '' await fetchGames(gamePayload) } /** * Searches for games based on the given keyword. * * @param {string} keyword The keyword to search for in game names. */ const onSearch = async (keyword: string) => { gamePayload.paged = 1 gamePayload.offset = 0 gamePayload.search = keyword await fetchGames(gamePayload) } /** * Loads more games and updates the displayed list based on the current page. * * @param {number} limit The maximum number of games to load. */ const onLoadMore = (limit: number): void => { const isLoadMore = true let currentPage = gamePayload.paged ?? 1 gamePayload.paged = ++currentPage filterLobbyGames(gamePayload, limit, isLoadMore) } /** * Updates the displayed games based on the selected page and limit. * * @param {number} page The page number to display. * @param {number} limit The maximum number of games to display per page. */ const onPaginate = (page: number, limit: number): void => { gamePayload.paged = page filterLobbyGames(gamePayload, limit) } return { fetchGames, fetchGameProviders, fetchGameCategories, fetchTopWinning, fetchGameTopChampion, getJackpotNumberByGameId, fetchGameJackpots, onFilter, fetchAllLobbyGameByCategory, onSearch, playGame, onPaginate, onLoadMore, requestFetchGames, requestFetchGamesV2, totalGame, isLoadingGame, lobbyGames, topWinners, gameCategories, gameTopChampion, gameProviders, gamePayload, providerSelected, categorySelected, } }