diff --git a/src/modules/matches/matches.service.ts b/src/modules/matches/matches.service.ts index 4b4c93e..deb7e9d 100755 --- a/src/modules/matches/matches.service.ts +++ b/src/modules/matches/matches.service.ts @@ -40,6 +40,82 @@ export class MatchesService { } } + /** + * Generate flag URL from country code or name using flagcdn.com + * Falls back to a name-to-code mapping for Turkish country names + */ + private getCountryFlagUrl( + countryCode?: string | null, + countryName?: string | null, + ): string | undefined { + // If we have a 2-letter ISO code, use it directly + if (countryCode && countryCode.length === 2) { + return `https://flagcdn.com/w40/${countryCode.toLowerCase()}.png`; + } + + // Fallback: map common Turkish country names to ISO codes + const COUNTRY_NAME_TO_CODE: Record = { + "Türkiye": "tr", + "İngiltere": "gb-eng", + "İspanya": "es", + "İtalya": "it", + "Almanya": "de", + "Fransa": "fr", + "Portekiz": "pt", + "Hollanda": "nl", + "Belçika": "be", + "İskoçya": "gb-sct", + "Galler": "gb-wls", + "İrlanda": "ie", + "Avusturya": "at", + "İsviçre": "ch", + "Yunanistan": "gr", + "Polonya": "pl", + "Çekya": "cz", + "Hırvatistan": "hr", + "Sırbistan": "rs", + "Danimarka": "dk", + "Norveç": "no", + "İsveç": "se", + "Finlandiya": "fi", + "Rusya": "ru", + "Ukrayna": "ua", + "Romanya": "ro", + "Macaristan": "hu", + "Bulgaristan": "bg", + "Arjantin": "ar", + "Brezilya": "br", + "Meksika": "mx", + "ABD": "us", + "Japonya": "jp", + "Güney Kore": "kr", + "Çin": "cn", + "Avustralya": "au", + "Suudi Arabistan": "sa", + "BAE": "ae", + "Katar": "qa", + "Mısır": "eg", + "Güney Afrika": "za", + "Kolombiya": "co", + "Şili": "cl", + "Peru": "pe", + "Ekvador": "ec", + "Paraguay": "py", + "Uruguay": "uy", + "Avrupa": "eu", + "Dünya": "un", + }; + + if (countryName) { + const code = COUNTRY_NAME_TO_CODE[countryName]; + if (code) { + return `https://flagcdn.com/w40/${code}.png`; + } + } + + return undefined; + } + private getLiveFilter(): Prisma.LiveMatchWhereInput { return { OR: [ @@ -298,7 +374,7 @@ export class MatchesService { country: { id: match.league?.country?.id || "", name: match.league?.country?.name || "", - flagUrl: match.league?.country?.flagUrl || undefined, + flagUrl: match.league?.country?.flagUrl || this.getCountryFlagUrl(null, match.league?.country?.name), }, sport: sport, matches: [], @@ -372,20 +448,37 @@ export class MatchesService { * Get active leagues with match counts */ async getActiveLeagues(sport: Sport): Promise { + // Start of today in UTC — same reference point as findMatches browse filter + const today = new Date(); + today.setUTCHours(0, 0, 0, 0); + const todayMs = BigInt(today.getTime()); + + // Build finished statuses/states for exclusion (mirroring getBrowseFilter logic) + const finishedStatuses = FINISHED_STATUS_VALUES_FOR_DB; + const finishedStates = FINISHED_STATE_VALUES_FOR_DB; + const liveStatuses = LIVE_STATUS_VALUES_FOR_DB; + const liveStates = LIVE_STATE_VALUES_FOR_DB; + // Use raw query for complex aggregation + // Filter: (mstUtc >= today AND NOT finished) OR is currently live const leagues = await this.prisma.$queryRaw` SELECT l.id, l.name, l.code, c.name as country_name, c.flag_url as country_flag, COUNT(lm.id)::int as match_count, - COUNT(CASE WHEN lm.status IN ('LIVE', '1H', '2H', 'HT', '1Q', '2Q', '3Q', '4Q', 'Playing', 'Half Time') - OR lm.state IN ('live', 'firsthalf', 'secondhalf') THEN 1 END)::int as live_count + COUNT(CASE WHEN lm.status IN (${Prisma.join(liveStatuses)}) + OR lm.state IN (${Prisma.join(liveStates)}) THEN 1 END)::int as live_count FROM live_matches lm JOIN leagues l ON lm.league_id = l.id LEFT JOIN countries c ON l.country_id = c.id WHERE lm.sport = ${sport} ${this.topLeagueIds.length > 0 ? Prisma.sql`AND l.id IN (${Prisma.join(this.topLeagueIds)})` : Prisma.empty} + AND ( + (lm.mst_utc >= ${todayMs} AND lm.status NOT IN (${Prisma.join(finishedStatuses)}) AND COALESCE(lm.state, '') NOT IN (${Prisma.join(finishedStates)})) + OR lm.status IN (${Prisma.join(liveStatuses)}) + OR lm.state IN (${Prisma.join(liveStates)}) + ) GROUP BY l.id, l.name, l.code, c.name, c.flag_url ORDER BY l.name ASC `; @@ -404,6 +497,7 @@ export class MatchesService { ]; return leagues + .filter((l) => l.match_count > 0) .sort((a, b) => { const aIdx = PRIORITY.findIndex((p) => a.name?.includes(p)); const bIdx = PRIORITY.findIndex((p) => b.name?.includes(p)); @@ -419,7 +513,7 @@ export class MatchesService { name: l.name, code: l.code, countryName: l.country_name, - countryFlag: l.country_flag, + countryFlag: l.country_flag || this.getCountryFlagUrl(null, l.country_name), matchCount: l.match_count, liveCount: l.live_count, }));