aggiunto ProfessionalExpenses form
This commit is contained in:
@@ -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
|
||||
})
|
||||
|
||||
|
||||
198
app/src/components/steps/ProfessionalExpensesStep.vue
Normal file
198
app/src/components/steps/ProfessionalExpensesStep.vue
Normal 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>
|
||||
@@ -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',
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user