Files
webapp/app/components/catalog/SupplierCard.vue
Ruslan Bakiev 2b6cccdead
All checks were successful
Build Docker Image / build (push) Successful in 5m8s
Fix all TypeScript errors and remove Storybook
- Remove all Storybook files and configuration
- Add type declarations for @vueuse/core, @formkit/core, vue3-apexcharts
- Fix TypeScript configuration (typeRoots, include paths)
- Fix Sentry config - move settings to plugin
- Fix nullable prop assignments with ?? operator
- Fix type narrowing issues with explicit type assertions
- Fix Card component linkable computed properties
- Update codegen with operationResultSuffix
- Fix GraphQL operation type definitions
2026-01-26 00:32:36 +07:00

98 lines
2.9 KiB
Vue

<template>
<component
:is="linkable ? NuxtLink : 'div'"
:to="linkable ? localePath(`/catalog?supplier=${supplier.uuid}`) : undefined"
class="block"
:class="{ 'cursor-pointer': selectable }"
@click="selectable && $emit('select')"
>
<Card
padding="small"
:interactive="linkable || selectable"
class="relative"
:class="[
isSelected && 'ring-2 ring-primary ring-offset-2'
]"
>
<!-- Verified badge top-right -->
<span v-if="supplier.isVerified" class="absolute -top-2 -right-2 badge badge-neutral badge-sm">
{{ t('catalogSupplier.badges.verified') }}
</span>
<div class="flex flex-col gap-1">
<!-- Logo -->
<div v-if="supplier.logo" class="w-12 h-12 mb-1">
<img :src="supplier.logo" :alt="supplier.name || ''" class="w-full h-full object-contain rounded">
</div>
<div v-else class="w-12 h-12 bg-primary/10 text-primary font-bold rounded flex items-center justify-center text-lg mb-1">
{{ supplier.name?.charAt(0) }}
</div>
<!-- Title -->
<Text size="base" weight="semibold" class="truncate">{{ supplier.name }}</Text>
<!-- Badges -->
<div class="flex flex-wrap gap-1">
<span class="badge badge-neutral badge-dash text-xs">
{{ reliabilityLabel }}
</span>
</div>
<!-- Country below -->
<Text tone="muted" size="sm">
{{ countryFlag }} {{ supplier.country || t('catalogMap.labels.country_unknown') }}
</Text>
</div>
</Card>
</component>
</template>
<script setup lang="ts">
import { NuxtLink } from '#components'
interface Supplier {
uuid?: string | null
teamUuid?: string | null
name?: string | null
country?: string | null
countryCode?: string | null
logo?: string | null
onTimeRate?: number | null
offersCount?: number | null
isVerified?: boolean | null
}
const props = defineProps<{
supplier: Supplier
selectable?: boolean
isSelected?: boolean
}>()
defineEmits<{
(e: 'select'): void
}>()
const localePath = useLocalePath()
const { t } = useI18n()
const linkable = computed(() => !props.selectable && !!props.supplier.uuid)
const reliabilityLabel = computed(() => {
if (props.supplier.onTimeRate !== undefined && props.supplier.onTimeRate !== null) {
return t('catalogSupplier.labels.on_time', { percent: Math.round(props.supplier.onTimeRate * 100) })
}
if (props.supplier.isVerified) {
return t('catalogSupplier.labels.trusted_partner')
}
return t('catalogSupplier.labels.on_time_default')
})
// ISO code to emoji flag
const isoToEmoji = (code: string): string => {
return code.toUpperCase().split('').map(char => String.fromCodePoint(0x1F1E6 - 65 + char.charCodeAt(0))).join('')
}
const countryFlag = computed(() => {
if (props.supplier.countryCode) {
return isoToEmoji(props.supplier.countryCode)
}
return '🌍'
})
</script>