Files
webapp/app/components/KYCFormRussia.vue
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

279 lines
8.3 KiB
Vue

<template>
<div class="p-0 sm:p-2">
<form @submit.prevent="submitKYC" class="space-y-6">
<!-- Company Section -->
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body gap-4">
<h3 class="card-title text-base-content">{{ t('kycRussia.form.companyDetails') }}</h3>
<div class="space-y-4">
<!-- Company search with DADATA -->
<div>
<label class="block text-sm font-medium text-base-content mb-2">
{{ t('kycRussia.form.organizationSearch') }}
</label>
<CompanySearchRussia v-model="formData.company" @select="onCompanySelect" />
</div>
<!-- Company details (auto-filled from DADATA) -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.inn') }}</label>
<input
v-model="formData.company.inn"
class="input input-bordered w-full"
readonly
/>
</div>
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.kpp') }}</label>
<input
v-model="formData.company.kpp"
class="input input-bordered w-full"
readonly
/>
</div>
</div>
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.ogrn') }}</label>
<input
v-model="formData.company.ogrn"
class="input input-bordered w-full"
readonly
/>
</div>
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.address') }}</label>
<textarea
v-model="formData.company.address"
class="textarea textarea-bordered w-full min-h-[120px]"
rows="3"
readonly
></textarea>
</div>
</div>
</div>
</div>
<!-- Bank Section -->
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body gap-4">
<h3 class="card-title text-base-content">{{ t('kycRussia.form.bankDetails') }}</h3>
<div class="space-y-4">
<!-- Bank search with DADATA -->
<div>
<label class="block text-sm font-medium text-base-content mb-2">
{{ t('kycRussia.form.bankSearch') }}
</label>
<BankSearchRussia v-model="formData.bank" @select="onBankSelect" />
</div>
<!-- Bank details -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.bic') }}</label>
<input
v-model="formData.bank.bik"
class="input input-bordered w-full"
readonly
/>
</div>
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.corrAccount') }}</label>
<input
v-model="formData.bank.correspondentAccount"
class="input input-bordered w-full"
readonly
/>
</div>
</div>
</div>
</div>
</div>
<!-- Contact Section -->
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body gap-4">
<h3 class="card-title text-base-content">{{ t('kycRussia.form.contactDetails') }}</h3>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-base-content mb-2">
{{ t('kycRussia.form.contactPerson') }} *
</label>
<input
v-model="formData.contact.person"
type="text"
required
class="input input-bordered w-full"
:placeholder="t('kycRussia.form.placeholders.contactPerson')"
/>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.email') }} *</label>
<input
v-model="formData.contact.email"
type="email"
required
class="input input-bordered w-full"
:placeholder="t('kycRussia.form.placeholders.email')"
/>
</div>
<div>
<label class="block text-sm font-medium text-base-content mb-2">{{ t('kycRussia.form.phone') }} *</label>
<input
v-model="formData.contact.phone"
type="tel"
required
class="input input-bordered w-full"
:placeholder="t('kycRussia.form.placeholders.phone')"
/>
</div>
</div>
</div>
</div>
</div>
<!-- Submit Button -->
<div class="flex justify-end">
<button
type="submit"
:disabled="loading || !isFormValid"
class="btn btn-primary"
>
{{ loading ? t('kycRussia.form.sending') : t('kycRussia.form.submit') }}
</button>
</div>
</form>
</div>
</template>
<script setup lang="ts">
interface KycSubmitData {
company_name: string
company_full_name: string
inn: string
kpp: string
ogrn: string
address: string
bank_name: string
bik: string
correspondent_account: string
contact_person: string
contact_email: string
contact_phone: string
}
interface CompanySuggestion {
value: string
unrestricted_value: string
data: {
inn: string
kpp?: string
ogrn?: string
address?: { value: string }
}
}
interface BankSuggestion {
value: string
data: {
bic: string
correspondent_account?: string
}
}
const { t } = useI18n()
const emit = defineEmits<{
submit: [data: KycSubmitData]
}>()
const loading = ref(false)
const formData = ref({
company: {
companyName: '',
companyFullName: '',
inn: '',
kpp: '',
ogrn: '',
address: ''
},
bank: {
bankName: '',
bik: '',
correspondentAccount: ''
},
contact: {
person: '',
email: '',
phone: ''
}
})
// Form validation
const isFormValid = computed(() => {
return formData.value.company.companyName &&
formData.value.company.inn &&
formData.value.bank.bankName &&
formData.value.bank.bik &&
formData.value.contact.person &&
formData.value.contact.email &&
formData.value.contact.phone
})
// Handlers
const onCompanySelect = (company: CompanySuggestion) => {
formData.value.company = {
companyName: company.value,
companyFullName: company.unrestricted_value,
inn: company.data.inn,
kpp: company.data.kpp || '',
ogrn: company.data.ogrn || '',
address: company.data.address?.value || ''
}
}
const onBankSelect = (bank: BankSuggestion) => {
formData.value.bank = {
bankName: bank.value,
bik: bank.data.bic,
correspondentAccount: bank.data.correspondent_account || ''
}
}
const submitKYC = async () => {
if (!isFormValid.value) return
loading.value = true
try {
const submitData = {
company_name: formData.value.company.companyName,
company_full_name: formData.value.company.companyFullName,
inn: formData.value.company.inn,
kpp: formData.value.company.kpp,
ogrn: formData.value.company.ogrn,
address: formData.value.company.address,
bank_name: formData.value.bank.bankName,
bik: formData.value.bank.bik,
correspondent_account: formData.value.bank.correspondentAccount,
contact_person: formData.value.contact.person,
contact_email: formData.value.contact.email,
contact_phone: formData.value.contact.phone
}
emit('submit', submitData)
} catch (error) {
console.error('Error submitting KYC:', error)
} finally {
loading.value = false
}
}
</script>