2026.06.05 frontend javítgatás és új belépési logika megvalósítva

This commit is contained in:
Roo
2026-06-05 05:46:04 +00:00
parent 59a30ac428
commit 18524a08f2
38 changed files with 3967 additions and 1028 deletions

View File

@@ -79,10 +79,10 @@
</div>
</div>
<!-- ==================== STEP 2: Address ==================== -->
<!-- ==================== STEP 2: Address (Soft KYC) ==================== -->
<div v-if="currentStep === 2">
<h2 class="text-xl font-semibold text-white mb-1">Lakcím adatok</h2>
<p class="text-white/40 text-sm mb-6">Pontos cím a garázs és flotta kezeléshez</p>
<p class="text-white/40 text-sm mb-6">Csak az irányítószám és város kötelező <span class="text-[#D4AF37]">(Soft KYC)</span></p>
<div class="space-y-4">
<!-- Country selector (EU-ready) -->
@@ -141,7 +141,7 @@
<div class="grid grid-cols-3 gap-3">
<div class="col-span-2">
<label class="block text-sm text-white/60 mb-1">Utca neve</label>
<label class="block text-sm text-white/60 mb-1">Utca neve <span class="text-white/20">(opcionális)</span></label>
<input
v-model="kycForm.address_street_name"
type="text"
@@ -150,7 +150,7 @@
/>
</div>
<div>
<label class="block text-sm text-white/60 mb-1">Típus</label>
<label class="block text-sm text-white/60 mb-1">Típus <span class="text-white/20">(opcionális)</span></label>
<select
v-model="kycForm.address_street_type"
class="w-full bg-white/5 border border-white/10 rounded-lg px-4 py-2.5 text-white focus:outline-none focus:border-[#00E5A0] focus:ring-1 focus:ring-[#00E5A0]/30 transition"
@@ -171,12 +171,13 @@
</div>
<div>
<label class="block text-sm text-white/60 mb-1">Házszám</label>
<label class="block text-sm text-white/60 mb-1">Házszám <span class="text-white/20">(opcionális)</span></label>
<input
v-model="kycForm.address_house_number"
type="text"
placeholder="10/A"
class="w-full bg-white/5 border border-white/10 rounded-lg px-4 py-2.5 text-white placeholder-white/30 focus:outline-none focus:border-[#00E5A0] focus:ring-1 focus:ring-[#00E5A0]/30 transition"
@keydown.tab.exact="handleHouseNumberTab"
/>
</div>
</div>
@@ -185,7 +186,7 @@
<!-- ==================== STEP 3: Security ==================== -->
<div v-if="currentStep === 3">
<h2 class="text-xl font-semibold text-white mb-1">Okmányok</h2>
<p class="text-white/40 text-sm mb-6">Személyi igazolvány és jogosítvány adatok</p>
<p class="text-white/40 text-sm mb-6">Személyi igazolvány és jogosítvány adatok <span class="text-[#D4AF37]">(opcionális)</span></p>
<div class="space-y-6">
<!-- Identity Documents -->
@@ -193,8 +194,8 @@
<!-- ID Card -->
<div class="bg-white/5 rounded-lg p-4 mb-3 border border-white/5">
<div class="flex items-center gap-2 mb-3">
<div class="w-2 h-2 rounded-full bg-[#00E5A0]" />
<span class="text-sm text-white/80">Személyi igazolvány</span>
<div class="w-2 h-2 rounded-full bg-white/20" />
<span class="text-sm text-white/50">Személyi igazolvány <span class="text-white/20">(opcionális)</span></span>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
@@ -288,6 +289,7 @@
<button
v-if="currentStep < 3"
@click="nextStep"
ref="nextButton"
class="px-6 py-2.5 rounded-lg bg-[#00E5A0] text-[#04151F] font-semibold hover:bg-[#00E5A0]/90 hover:shadow-lg hover:shadow-[#00E5A0]/20 transition-all text-sm"
>
Tovább →
@@ -330,7 +332,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import { ref, reactive, watch, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '../stores/auth'
@@ -348,6 +350,7 @@ const currentStep = ref(1)
const isSubmitting = ref(false)
const errorMessage = ref<string | null>(null)
const isCityLoading = ref(false)
const nextButton = ref<HTMLButtonElement | null>(null)
// ── KYC Form (minimal — only DB-required fields) ──
const kycForm = reactive({
@@ -367,7 +370,7 @@ const kycForm = reactive({
preferred_currency: 'HUF',
})
// ── Debounced ZIP → City auto-fill via zippopotam.us ──
// ── Debounced ZIP → City auto-fill via internal API ──
let zipTimeout: ReturnType<typeof setTimeout>
watch(
() => kycForm.address_zip,
@@ -377,11 +380,11 @@ watch(
isCityLoading.value = true
zipTimeout = setTimeout(async () => {
try {
const country = kycForm.region_code.toLowerCase()
const response = await fetch(`https://api.zippopotam.us/${country}/${newZip}`)
const country = kycForm.region_code || 'HU'
const response = await fetch(`/api/v1/system/zip-lookup?country_code=${country}&zip_code=${newZip}`)
if (response.ok) {
const data = await response.json()
kycForm.address_city = data.places[0]['place name']
kycForm.address_city = data.city
}
} catch (error) {
console.error('Cím lekérdezési hiba:', error)
@@ -407,7 +410,7 @@ function stepCircleClass(idx: number): string {
return 'bg-white/5 text-white/30 border border-white/10'
}
// ── Simple step validation ──
// ── Simple step validation (Soft KYC) ──
function validateStep(): boolean {
errorMessage.value = null
@@ -419,16 +422,11 @@ function validateStep(): boolean {
if (currentStep.value === 2) {
if (!kycForm.address_zip) { errorMessage.value = 'Kérlek add meg az irányítószámot.'; return false }
if (!kycForm.address_city) { errorMessage.value = 'Kérlek add meg a várost.'; return false }
if (!kycForm.address_street_name) { errorMessage.value = 'Kérlek add meg az utca nevét.'; return false }
if (!kycForm.address_street_type) { errorMessage.value = 'Kérlek válaszd ki az utca típusát.'; return false }
if (!kycForm.address_house_number) { errorMessage.value = 'Kérlek add meg a házszámot.'; return false }
}
if (currentStep.value === 3) {
if (!kycForm.identity_docs.ID_CARD.number) { errorMessage.value = 'Kérlek add meg a személyi igazolvány számát.'; return false }
if (!kycForm.identity_docs.ID_CARD.expiry_date) { errorMessage.value = 'Kérlek add meg a személyi lejárati dátumát.'; return false }
// Soft KYC: Utca, típus, házszám már NEM kötelező
}
// Step 3 has no required validations anymore (Soft KYC - all optional)
return true
}
@@ -447,6 +445,16 @@ function prevStep() {
}
}
// ── Tab order fix: Házszám → Tovább gomb ──
function handleHouseNumberTab(event: KeyboardEvent) {
if (currentStep.value === 2 && nextButton.value) {
event.preventDefault()
nextTick(() => {
nextButton.value?.focus()
})
}
}
// ── Submit ──
async function handleSubmit() {
if (!validateStep()) return
@@ -455,34 +463,42 @@ async function handleSubmit() {
errorMessage.value = null
try {
// Build the minimal payload matching UserKYCComplete schema
const payload = {
last_name: kycForm.last_name,
// Build the payload matching UserKYCComplete schema (Soft KYC)
const payload: any = {
first_name: kycForm.first_name,
last_name: kycForm.last_name,
region_code: kycForm.region_code,
address_zip: kycForm.address_zip,
address_city: kycForm.address_city,
address_street_name: kycForm.address_street_name,
address_street_type: kycForm.address_street_type,
address_house_number: kycForm.address_house_number,
identity_docs: {
ID_CARD: {
number: kycForm.identity_docs.ID_CARD.number,
expiry_date: kycForm.identity_docs.ID_CARD.expiry_date,
},
...(kycForm.identity_docs.LICENSE.number
? {
LICENSE: {
number: kycForm.identity_docs.LICENSE.number,
expiry_date: kycForm.identity_docs.LICENSE.expiry_date,
},
}
: {}),
},
preferred_language: kycForm.preferred_language,
preferred_currency: kycForm.preferred_currency,
}
// Soft KYC: Csak akkor küldjük a részletes címet, ha ki van töltve
if (kycForm.address_street_name) payload.address_street_name = kycForm.address_street_name
if (kycForm.address_street_type) payload.address_street_type = kycForm.address_street_type
if (kycForm.address_house_number) payload.address_house_number = kycForm.address_house_number
// Only include identity_docs if at least one document is filled
const hasIdCard = kycForm.identity_docs.ID_CARD.number || kycForm.identity_docs.ID_CARD.expiry_date
const hasLicense = kycForm.identity_docs.LICENSE.number || kycForm.identity_docs.LICENSE.expiry_date
if (hasIdCard || hasLicense) {
payload.identity_docs = {}
if (hasIdCard) {
payload.identity_docs.ID_CARD = {
number: kycForm.identity_docs.ID_CARD.number || null,
expiry_date: kycForm.identity_docs.ID_CARD.expiry_date || null,
}
}
if (hasLicense) {
payload.identity_docs.LICENSE = {
number: kycForm.identity_docs.LICENSE.number || null,
expiry_date: kycForm.identity_docs.LICENSE.expiry_date || null,
}
}
}
await authStore.completeKyc(payload)
// Navigate to dashboard on success