Added Notifications
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import { computed, ComputedRef } from 'vue'
|
||||
import { Flight } from '@/Types/types'
|
||||
|
||||
export interface Continent {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
internal_name: string
|
||||
}
|
||||
|
||||
export interface ContinentPairEntry {
|
||||
key: string
|
||||
label: string
|
||||
flights: Flight[]
|
||||
}
|
||||
|
||||
/** Stable undirected key — always alphabetically sorted so A|B === B|A */
|
||||
export function undirectedKey(a: string, b: string): string {
|
||||
return [a, b].sort().join('|')
|
||||
}
|
||||
|
||||
/** Directed key — order preserved */
|
||||
export function directedKey(dep: string, arr: string): string {
|
||||
return `${dep}|${arr}`
|
||||
}
|
||||
|
||||
export function labelFor(a: string, b: string): string {
|
||||
return `${a} ↔ ${b}`
|
||||
}
|
||||
|
||||
export function continentNameOf(flight: Flight, side: 'departure' | 'arrival'): string | null {
|
||||
const airport = side === 'departure' ? flight.departure_airport : flight.arrival_airport
|
||||
return airport.region?.continent?.name ?? null
|
||||
}
|
||||
|
||||
export function isInternational(flight: Flight): boolean {
|
||||
const depCountry = flight.departure_airport.region?.country_id
|
||||
const arrCountry = flight.arrival_airport.region?.country_id
|
||||
if (depCountry == null || arrCountry == null) return true
|
||||
return depCountry !== arrCountry
|
||||
}
|
||||
|
||||
/** Filter flights to only those that qualify for continent-pair achievements */
|
||||
export function qualifyingFlights(flights: Flight[]): Flight[] {
|
||||
return flights.filter(flight => {
|
||||
const dep = continentNameOf(flight, 'departure')
|
||||
const arr = continentNameOf(flight, 'arrival')
|
||||
if (!dep || !arr) return false
|
||||
if (dep === arr && !isInternational(flight)) return false
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// ── One-way (undirected) pairs ─────────────────────────────────────────────
|
||||
|
||||
export function useUndirectedContinentPairs(
|
||||
flights: ComputedRef<Flight[]>,
|
||||
continents: ComputedRef<Continent[]>,
|
||||
) {
|
||||
const allKeys = computed<string[]>(() => {
|
||||
const names = continents.value.map(c => c.name).sort()
|
||||
const keys: string[] = []
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
for (let j = i; j < names.length; j++) {
|
||||
keys.push(undirectedKey(names[i], names[j]))
|
||||
}
|
||||
}
|
||||
return keys.sort((a, b) => {
|
||||
const [a1, a2] = a.split('|')
|
||||
const [b1, b2] = b.split('|')
|
||||
return labelFor(a1, a2).localeCompare(labelFor(b1, b2))
|
||||
})
|
||||
})
|
||||
|
||||
const flightsByKey = computed<Map<string, Flight[]>>(() => {
|
||||
const map = new Map(allKeys.value.map(k => [k, [] as Flight[]]))
|
||||
for (const flight of qualifyingFlights(flights.value)) {
|
||||
const dep = continentNameOf(flight, 'departure')!
|
||||
const arr = continentNameOf(flight, 'arrival')!
|
||||
const key = undirectedKey(dep, arr)
|
||||
map.get(key)?.push(flight)
|
||||
}
|
||||
return map
|
||||
})
|
||||
|
||||
const entries = computed<ContinentPairEntry[]>(() =>
|
||||
allKeys.value.map(key => {
|
||||
const [a, b] = key.split('|')
|
||||
return { key, label: labelFor(a, b), flights: flightsByKey.value.get(key) ?? [] }
|
||||
})
|
||||
)
|
||||
|
||||
const completedCount = computed(() => entries.value.filter(e => e.flights.length > 0).length)
|
||||
const totalCount = computed(() => entries.value.length)
|
||||
|
||||
return { entries, completedCount, totalCount }
|
||||
}
|
||||
|
||||
// ── Both-ways (directed) pairs ─────────────────────────────────────────────
|
||||
|
||||
export function useDirectedContinentPairs(
|
||||
flights: ComputedRef<Flight[]>,
|
||||
continents: ComputedRef<Continent[]>,
|
||||
) {
|
||||
/** All directed keys grouped by the departure continent name */
|
||||
const keysByDeparture = computed<Map<string, string[]>>(() => {
|
||||
const names = continents.value.map(c => c.name).sort()
|
||||
const map = new Map<string, string[]>()
|
||||
for (const dep of names) {
|
||||
map.set(dep, names.map(arr => directedKey(dep, arr)).sort((a, b) => {
|
||||
const [, a2] = a.split('|')
|
||||
const [, b2] = b.split('|')
|
||||
return a2.localeCompare(b2)
|
||||
}))
|
||||
}
|
||||
return map
|
||||
})
|
||||
|
||||
const flightsByKey = computed<Map<string, Flight[]>>(() => {
|
||||
const map = new Map<string, Flight[]>()
|
||||
for (const keys of keysByDeparture.value.values()) {
|
||||
for (const key of keys) map.set(key, [])
|
||||
}
|
||||
for (const flight of qualifyingFlights(flights.value)) {
|
||||
const dep = continentNameOf(flight, 'departure')!
|
||||
const arr = continentNameOf(flight, 'arrival')!
|
||||
const key = directedKey(dep, arr)
|
||||
map.get(key)?.push(flight)
|
||||
}
|
||||
return map
|
||||
})
|
||||
|
||||
/** Entries grouped by departure continent, each sorted by arrival continent name */
|
||||
const entriesByDeparture = computed<Map<string, ContinentPairEntry[]>>(() => {
|
||||
const map = new Map<string, ContinentPairEntry[]>()
|
||||
for (const [dep, keys] of keysByDeparture.value) {
|
||||
map.set(dep, keys.map(key => {
|
||||
const [a, b] = key.split('|')
|
||||
return { key, label: `${a} → ${b}`, flights: flightsByKey.value.get(key) ?? [] }
|
||||
}))
|
||||
}
|
||||
return map
|
||||
})
|
||||
|
||||
const departureNames = computed(() => [...keysByDeparture.value.keys()])
|
||||
|
||||
const completedCount = computed(() => {
|
||||
let count = 0
|
||||
for (const entries of entriesByDeparture.value.values()) {
|
||||
count += entries.filter(e => e.flights.length > 0).length
|
||||
}
|
||||
return count
|
||||
})
|
||||
|
||||
const totalCount = computed(() => {
|
||||
let count = 0
|
||||
for (const entries of entriesByDeparture.value.values()) {
|
||||
count += entries.length
|
||||
}
|
||||
return count
|
||||
})
|
||||
|
||||
return { entriesByDeparture, departureNames, completedCount, totalCount }
|
||||
}
|
||||
Reference in New Issue
Block a user