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.
279 lines
8.3 KiB
Vue
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>
|