refactor: remove all any types, add strict GraphQL scalar typing
All checks were successful
Build Docker Image / build (push) Successful in 4m3s

- 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.
This commit is contained in:
Ruslan Bakiev
2026-01-27 11:34:12 +07:00
parent ff34c564e1
commit 2dbe600d8a
42 changed files with 614 additions and 324 deletions

View File

@@ -16,8 +16,8 @@
<Grid :cols="1" :md="2" :lg="3" :gap="4">
<Card
v-for="addr in teamAddresses"
:key="addr.uuid"
v-for="(addr, index) in teamAddresses"
:key="addr.uuid ?? index"
padding="small"
interactive
@click="selectTeamAddress(addr)"
@@ -57,8 +57,8 @@
<Grid v-else :cols="1" :md="2" :lg="3" :gap="4">
<HubCard
v-for="location in locationsData"
:key="location.uuid"
v-for="(location, index) in locationsData"
:key="location.uuid ?? index"
:hub="location"
selectable
@select="selectLocation(location)"
@@ -69,7 +69,17 @@
</template>
<script setup lang="ts">
import { HubsListDocument } from '~/composables/graphql/public/geo-generated'
import { HubsListDocument, type HubsListQueryResult } from '~/composables/graphql/public/geo-generated'
type HubItem = NonNullable<NonNullable<HubsListQueryResult['hubsList']>[number]>
type HubWithDistance = HubItem & { distance?: string }
interface TeamAddress {
uuid?: string | null
name?: string | null
address?: string | null
isDefault?: boolean | null
}
const { t } = useI18n()
const searchStore = useSearchStore()
@@ -85,35 +95,37 @@ const calculateDistance = (lat: number, lng: number) => {
// Load logistics hubs
const { data: locationsDataRaw, pending, error, refresh } = await useServerQuery('locations', HubsListDocument, { limit: 100 }, 'public', 'geo')
const locationsData = computed(() => {
return (locationsDataRaw.value?.hubsList || []).map((location: any) => ({
...location,
distance: location?.latitude && location?.longitude
? calculateDistance(location.latitude, location.longitude)
: undefined,
}))
const locationsData = computed<HubWithDistance[]>(() => {
return (locationsDataRaw.value?.hubsList || [])
.filter((location): location is HubItem => location !== null)
.map((location) => ({
...location,
distance: location.latitude && location.longitude
? calculateDistance(location.latitude, location.longitude)
: undefined,
}))
})
// Load team addresses (if authenticated)
const teamAddresses = ref<any[]>([])
const teamAddresses = ref<TeamAddress[]>([])
if (isAuthenticated.value) {
try {
const { GetTeamAddressesDocument } = await import('~/composables/graphql/team/teams-generated')
const { data: addressData } = await useServerQuery('locations-team-addresses', GetTeamAddressesDocument, {}, 'team', 'teams')
teamAddresses.value = addressData.value?.teamAddresses || []
teamAddresses.value = (addressData.value?.teamAddresses || []).filter((a): a is NonNullable<typeof a> => a !== null)
} catch (e) {
console.log('Team addresses not available')
}
}
const selectLocation = (location: any) => {
const selectLocation = (location: HubWithDistance) => {
searchStore.setLocation(location.name)
searchStore.setLocationUuid(location.uuid)
history.back()
}
const selectTeamAddress = (addr: any) => {
const selectTeamAddress = (addr: TeamAddress) => {
searchStore.setLocation(addr.address)
searchStore.setLocationUuid(addr.uuid)
history.back()