Files
webapp/app/composables/useTeamAddresses.ts
Ruslan Bakiev 2dbe600d8a
All checks were successful
Build Docker Image / build (push) Successful in 4m3s
refactor: remove all any types, add strict GraphQL scalar typing
- Add strictScalars: true to codegen.ts with proper scalar mappings
  (Date, Decimal, JSONString, JSON, UUID, BigInt → string/Record)
- Replace all ref<any[]> with proper GraphQL-derived types
- Add type guards for null filtering in arrays
- Fix bugs exposed by typing (locationLatitude vs latitude, etc.)
- Add interfaces for external components (MapboxSearchBox)

This enables end-to-end type safety from GraphQL schema to frontend.
2026-01-27 11:34:12 +07:00

78 lines
2.1 KiB
TypeScript

import type { GetTeamAddressesQueryResult } from '~/composables/graphql/team/teams-generated'
type TeamAddress = NonNullable<NonNullable<GetTeamAddressesQueryResult['teamAddresses']>[number]>
const items = ref<TeamAddress[]>([])
const isLoading = ref(false)
const isInitialized = ref(false)
export function useTeamAddresses() {
const { t } = useI18n()
const { execute, mutate } = useGraphQL()
const itemsWithCoords = computed(() =>
items.value
.filter(a => a.latitude && a.longitude)
.map(a => ({
uuid: a.uuid,
name: a.name,
latitude: a.latitude,
longitude: a.longitude,
country: a.countryCode
}))
)
const load = async () => {
isLoading.value = true
try {
const { GetTeamAddressesDocument } = await import('~/composables/graphql/team/teams-generated')
const data = await execute(GetTeamAddressesDocument, {}, 'team', 'teams')
items.value = (data?.teamAddresses || []).filter((a): a is TeamAddress => a !== null)
isInitialized.value = true
} catch (e) {
console.error('Failed to load addresses', e)
} finally {
isLoading.value = false
}
}
const deleteAddress = async (uuid: string) => {
if (!confirm(t('profileAddresses.actions.confirm_delete'))) return false
try {
const { DeleteTeamAddressDocument } = await import('~/composables/graphql/team/teams-generated')
const result = await mutate(DeleteTeamAddressDocument, { uuid }, 'team', 'teams')
if (result.deleteTeamAddress?.success) {
await load()
return true
}
} catch (e) {
console.error('Failed to delete address', e)
}
return false
}
const init = async () => {
if (!isInitialized.value && items.value.length === 0) {
await load()
}
}
// ISO code to emoji flag
const isoToEmoji = (code: string | null | undefined): string => {
if (!code) return '🌍'
return code.toUpperCase().split('').map(char => String.fromCodePoint(0x1F1E6 - 65 + char.charCodeAt(0))).join('')
}
return {
items,
isLoading,
itemsWithCoords,
load,
deleteAddress,
init,
isoToEmoji
}
}