aggiunto ProfessionalExpenses form

This commit is contained in:
fabio
2026-02-19 10:12:08 +01:00
parent d479e1ae73
commit 823a5054a0
4 changed files with 231 additions and 0 deletions

View File

@@ -68,6 +68,7 @@ const currentComponent = computed(() => {
if (id === 'marital') return defineAsyncComponent(() => import('./steps/MaritalStep.vue'))
if (id === 'children') return defineAsyncComponent(() => import('./steps/ChildrenStep.vue'))
if (id === 'income') return defineAsyncComponent(() => import('./steps/IncomeStep.vue'))
if (id === 'professionalExpenses') return defineAsyncComponent(() => import('./steps/ProfessionalExpensesStep.vue'))
return null
})

View File

@@ -0,0 +1,198 @@
<template>
<q-card flat class="full-width q-pa-none">
<q-card-section class="full-width">
<div class="row items-center">
<div class="col">
<div class="text-h6">{{ t('PRO') }}</div>
</div>
<div class="col-auto">
<q-btn flat :label="t('button.prev')" @click="emitPrev" class="q-mr-sm" />
<q-btn color="primary" :label="t('button.next')" @click="saveAndNext" />
</div>
</div>
<q-separator class="q-my-sm" />
<q-form ref="formRef" class="q-gutter-md q-mt-md">
<div class="row items-center">
<div class="col">
<q-toggle v-model="form.expensesChanged" :label="t('professionalExpenses.expensesChanged')" />
</div>
</div>
<div v-if="form.expensesChanged" class="q-mt-md">
<q-input
v-model="form.workplaceDescription"
:label="t('professionalExpenses.workplaceDescription')"
type="text"
outlined
/>
<div class="row">
<div class="col-6 q-pr-md">
<q-select
v-model="form.commuteMethod"
:options="commuteMethodOptions"
:label="t('professionalExpenses.commuteMethod')"
emit-value
map-options
outlined
class="q-mt-md"
/>
</div>
<div class="col-6">
<q-input
v-model.number="form.commuteKm"
:label="t('professionalExpenses.commuteKm')"
type="number"
outlined
class="q-mt-md"
/>
</div>
</div>
<div class="column">
<q-toggle
v-model="form.lunchAtHome"
:label="t('professionalExpenses.lunchAtHome')"
class="q-mt-md"
/>
<q-toggle
v-model="form.eatsOut"
:label="t('professionalExpenses.eatsOut')"
class="q-mt-md"
/>
<q-toggle
v-if="form.eatsOut"
v-model="form.hasCanteenOrVouchers"
:label="t('professionalExpenses.hasCanteenOrVouchers')"
:rules="[requiredWhenEatsOut]"
class="q-mt-md"
/>
</div>
</div>
</q-form>
</q-card-section>
</q-card>
</template>
<script setup lang="ts">
import { reactive, onMounted, ref, nextTick, watch, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import type { StepDescriptor } from '../../types/types'
type CommuteMethod = 'CAR' | 'BUS' | 'BIKE' | 'WALK'
type ProfessionalExpensesForm = {
expensesChanged: boolean
workplaceDescription: string
commuteMethod: CommuteMethod | null
commuteKm: number | null
lunchAtHome: boolean
eatsOut: boolean
hasCanteenOrVouchers: boolean
}
const props = defineProps<{ step?: StepDescriptor }>()
const emit = defineEmits(['next', 'prev'])
const { t } = useI18n()
// QForm ref
const formRef = ref<{ validate?: () => Promise<boolean> | boolean; resetValidation?: () => void } | null>(null)
/* const required = (msg?: string) => (v: unknown) => {
const message = msg || requiredMessage()
if (v === null || v === undefined) return message
if (typeof v === 'string') return (v.trim() !== '') || message
if (Array.isArray(v)) return v.length > 0 || message
return true
}
const minLength = (n: number, msg?: string) => (v: unknown) => {
const message = msg || `${t('validation.minLength') || `Minimum ${n} chars`}`
if (v === null || v === undefined) return true
if (typeof v === 'string') return (v.trim().length >= n) || message
return true
} */
const form = reactive<ProfessionalExpensesForm>({
expensesChanged: false,
workplaceDescription: '',
commuteMethod: null,
commuteKm: null,
lunchAtHome: false,
eatsOut: false,
hasCanteenOrVouchers: false
})
const commuteMethodOptions = computed<Array<{ label: string; value: CommuteMethod }>>(() => [
{ label: t('professionalExpenses.commuteMethodOptions.car'), value: 'CAR' },
{ label: t('professionalExpenses.commuteMethodOptions.bus'), value: 'BUS' },
{ label: t('professionalExpenses.commuteMethodOptions.bike'), value: 'BIKE' },
{ label: t('professionalExpenses.commuteMethodOptions.walk'), value: 'WALK' }
])
const requiredWhenEatsOut = (v: boolean | null) => {
if (!form.eatsOut) return true
return v !== null || t('validation.required')
}
/* const professionalExpensesSchema = {
fields: [
{ key: "expensesChanged", type: "boolean", required: true },
{ key: "workplaceDescription", type: "string" },
{ key: "commuteMethod", type: "enum", values: ["CAR", "BUS", "BIKE", "WALK"] },
{ key: "commuteKm", type: "number" },
{ key: "lunchAtHome", type: "boolean" },
{ key: "eatsOut", type: "boolean" },
{ key: "hasCanteenOrVouchers", type: "boolean", requiredIf: { eatsOut: true } },
],
} as const;
*/
onMounted(async () => {
await nextTick()
formRef.value?.resetValidation?.()
})
// persist when expensesChanged toggles
watch(() => form.expensesChanged, () => {
//store.setChildren(buildPayload())
})
watch(() => form.eatsOut, (value) => {
if (!value) form.hasCanteenOrVouchers = false
})
async function saveAndNext() {
try {
const ok = await (formRef.value?.validate?.() ?? true)
if (ok === false) return
} catch {
return
}
emit('next', props.step?.next)
}
function emitPrev() {
emit('prev', props.step?.prev)
}
//defineExpose({ buildPayload })
</script>
<style scoped>
.full-width { width: 100%; }
.contained-card { min-width: 480px; max-width: 720px; }
.contained-card .q-card-section { padding: 16px; }
.contained-card .q-card-actions { padding: 12px 16px; }
.child-modal { min-width: 480px; }
</style>

View File

@@ -96,6 +96,22 @@ export default {
noAttachments: 'Attach documents'
},
professionalExpenses: {
expensesChanged: 'Have your professional expenses changed?',
workplaceDescription: 'Workplace description',
commuteMethod: 'Commute method',
commuteMethodOptions: {
car: 'Car',
bus: 'Bus',
bike: 'Bike',
walk: 'Walk'
},
commuteKm: 'Commute distance (km)',
lunchAtHome: 'Do you have lunch at home?',
eatsOut: 'Do you eat out?',
hasCanteenOrVouchers: 'Do you have a canteen or meal vouchers?'
},
informazionesualimenti: 'Alimony information',
inserireindirizzocogniuge: 'Enter spouse address',
inserireindirizzopartner: 'Enter partner address',

View File

@@ -96,6 +96,22 @@ export default {
noAttachments: 'Allega documenti'
},
professionalExpenses: {
expensesChanged: 'Le spese professionali sono cambiate?',
workplaceDescription: 'Descrizione del luogo di lavoro',
commuteMethod: 'Metodo di trasporto',
commuteMethodOptions: {
car: 'Auto',
bus: 'Bus',
bike: 'Bici',
walk: 'A piedi'
},
commuteKm: 'Km di percorrenza',
lunchAtHome: 'Pranzi a casa?',
eatsOut: 'Mangi fuori?',
hasCanteenOrVouchers: 'Hai mensa o buoni pasto?'
},
informazionesualimenti: 'Informazioni su alimenti',
inserireindirizzocogniuge: "Inserire l'indirizzo del coniuge",
inserireindirizzopartner: "Inserire l'indirizzo del partner",