first commit

This commit is contained in:
fabio
2026-02-18 21:04:57 +01:00
parent 3f675be1c3
commit ce1fb7b23f
141 changed files with 24621 additions and 2 deletions

102
app/src/stores/children.ts Normal file
View File

@@ -0,0 +1,102 @@
import { defineStore } from 'pinia'
import { LocalStorage } from 'quasar'
import type { Address } from '../types/address'
interface CommentAttachment {
comments: string
attachments: string[]
}
export interface ChildItem {
firstName: string
lastName: string
birthDate: string
sameHousehold: boolean
alimentiVersati?: boolean
school: string
hasCareCost: boolean
careCosts: CommentAttachment
address?: Address | null
}
export interface ChildrenData {
hasChildren: boolean
children: ChildItem[]
moreThanFiveChildrenNote: string
}
const STORAGE_KEY = 'children:v1'
const DEFAULT: ChildrenData = {
hasChildren: false,
children: [],
moreThanFiveChildrenNote: ''
}
export const useChildrenStore = defineStore('childrenstore', {
state: () => {
try {
let saved: unknown = LocalStorage.getItem(STORAGE_KEY)
if (typeof saved === 'string') {
try {
saved = JSON.parse(saved)
} catch {
saved = null
}
}
if (saved && typeof saved === 'object') {
return { data: { ...(saved as ChildrenData) } }
}
} catch {
// ignore and fall back to default
}
return { data: { ...DEFAULT } as ChildrenData }
},
actions: {
persist() {
try {
// LocalStorage (and JSON) can fail when trying to serialize
// File objects. Build a serializable copy: drop `careCosts`
// (or convert to file meta) before persisting.
const serializable: ChildrenData = {
hasChildren: !!this.data.hasChildren,
children: Array.isArray(this.data.children)
? this.data.children.map(c => {
return {
firstName: c.firstName,
lastName: c.lastName,
birthDate: c.birthDate,
sameHousehold: c.sameHousehold,
alimentiVersati: (c as Partial<ChildItem>).alimentiVersati ?? false,
school: c.school,
hasCareCost: (c as Partial<ChildItem>).hasCareCost ?? false,
careCosts: c.careCosts,
address: (c as Partial<ChildItem>).address ?? null,
}
})
: [],
moreThanFiveChildrenNote: this.data.moreThanFiveChildrenNote || ''
}
LocalStorage.set(STORAGE_KEY, serializable)
} catch (err) {
// keep errors visible in console to aid debugging but don't throw
console.error('children.store: persist error', err)
}
},
getChildren() {
return this.data
},
setChildren(partial: Partial<ChildrenData>) {
this.data = { ...this.data, ...partial }
this.persist()
},
replaceChildren(payload: ChildrenData) {
this.data = payload
this.persist()
},
resetChildren() {
this.data = { ...DEFAULT }
this.persist()
}
}
})

66
app/src/stores/income.ts Normal file
View File

@@ -0,0 +1,66 @@
import { defineStore } from 'pinia'
import { LocalStorage } from 'quasar'
import type { IncomeData } from '../types/types'
const STORAGE_KEY = 'income:v1'
const DEFAULT: IncomeData = {
employType: null,
attachments: {
salaryCertificate: { comments: '', attachments: [] },
accountingDocuments: { comments: '', attachments: [] },
avsCertificate: { comments: '', attachments: [] },
lppCertificate: { comments: '', attachments: [] },
unemploymentCertificate: { comments: '', attachments: [] }
}
}
function isRecord(v: unknown): v is Record<string, unknown> {
return !!v && typeof v === 'object' && !Array.isArray(v)
}
export const useIncomeStore = defineStore('incomestore', {
state: () => {
try {
let saved: unknown = LocalStorage.getItem(STORAGE_KEY)
if (typeof saved === 'string') {
try {
saved = JSON.parse(saved)
} catch {
saved = null
}
}
if (isRecord(saved)) {
return { data: { ...DEFAULT, ...(saved as Partial<IncomeData>) } as IncomeData }
}
} catch {
// ignore and fall back to default
}
return { data: { ...DEFAULT } as IncomeData }
},
actions: {
persist() {
try {
LocalStorage.set(STORAGE_KEY, this.data)
} catch (err) {
console.error('income.store: persist error', err)
}
},
getIncome() {
return this.data
},
setIncome(partial: Partial<IncomeData>) {
this.data = { ...this.data, ...partial }
this.persist()
},
replaceIncome(payload: IncomeData) {
this.data = payload
this.persist()
},
resetIncome() {
this.data = { ...DEFAULT }
this.persist()
}
}
})

32
app/src/stores/index.ts Normal file
View File

@@ -0,0 +1,32 @@
import { defineStore } from '#q-app/wrappers';
import { createPinia } from 'pinia';
/*
* When adding new properties to stores, you should also
* extend the `PiniaCustomProperties` interface.
* @see https://pinia.vuejs.org/core-concepts/plugins.html#typing-new-store-properties
*/
declare module 'pinia' {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface PiniaCustomProperties {
// add your custom properties here, if any
}
}
/*
* If not building with SSR mode, you can
* directly export the Store instantiation;
*
* The function below can be async too; either use
* async/await or return a Promise which resolves
* with the Store instance.
*/
export default defineStore((/* { ssrContext } */) => {
const pinia = createPinia();
// You can add Pinia plugins here
// pinia.use(SomePiniaPlugin)
return pinia;
});

40
app/src/stores/marital.ts Normal file
View File

@@ -0,0 +1,40 @@
// Thin compatibility wrapper: marital API now lives in the `taxstore`.
import { computed } from 'vue'
import { useTaxstore } from './taxstore'
import type { AddressOut } from 'src/components/AddressInput.vue'
import type { CommentAttachmentData } from 'src/components/CommentAttachment.vue'
export interface MaritalData {
alimentiVersati: boolean
alimentiCommenti: CommentAttachmentData
maritalStatus: string
spouseFirstName: string | number | null
spouseLastName: string | number | null
spouseBirthDate: string | number | FileList | null | undefined
spouseDeadDate: string | number | FileList | null | undefined
spouseTaxNumber: string
spouseAddress: AddressOut
marriageDate: string
separated: boolean
spouseAlimentiVersati: boolean
}
export const useMaritalStore = () => {
const store = useTaxstore()
const data = computed(() => store.getMarital())
function set(partial: Partial<MaritalData>) {
store.setMarital(partial)
}
function replace(payload: MaritalData) {
store.replaceMarital(payload)
}
function reset() {
store.resetMarital()
}
return { data, set, replace, reset }
}

View File

@@ -0,0 +1,34 @@
import { computed } from 'vue'
import { useTaxstore } from './taxstore'
import type { AddressOut } from 'src/components/AddressInput.vue'
import type { CommentAttachmentData } from 'src/components/CommentAttachment.vue'
export interface TaxpayerForm {
prevPreparedByUs: boolean
prevDeclaration: CommentAttachmentData
firstName: string
lastName: string
birthDate: string
address: AddressOut
}
// Compatibility wrapper around `taxstore` for code expecting `useTaxpayerStore()`
export const useTaxpayerStore = () => {
const store = useTaxstore()
const data = computed(() => store.getTaxpayer())
function set(partial: Partial<TaxpayerForm>) {
store.setTaxpayer(partial)
}
function replace(payload: TaxpayerForm) {
store.replaceTaxpayer(payload)
}
function reset() {
store.resetTaxpayer()
}
return { data, set, replace, reset }
}

121
app/src/stores/taxstore.ts Normal file
View File

@@ -0,0 +1,121 @@
import { defineStore } from 'pinia'
import { LocalStorage } from 'quasar'
import { type TaxpayerForm } from './taxpayer'
import { type MaritalData } from './marital'
const STORAGE_KEY = 'taxstore:v1'
const defaultTaxpayer: TaxpayerForm = {
prevPreparedByUs: false,
prevDeclaration: { comments: '', attachments: [] },
firstName: '',
lastName: '',
birthDate: '',
address: {
street: '',
cap: '',
city: '',
country: { code: '', name: '' },
canton: ''
}
}
const defaultMarital: MaritalData = {
alimentiVersati: false,
alimentiCommenti: { comments: '', attachments: [] },
maritalStatus: '',
spouseFirstName: '',
spouseLastName: '',
spouseBirthDate: '',
spouseDeadDate : '',
spouseTaxNumber: '',
spouseAddress: { street: '', cap: '', city: '', country: { code: '', name: '' }, canton: '' },
marriageDate: '',
separated: false,
spouseAlimentiVersati: false
}
export const useTaxstore = defineStore('taxstore', {
state: () => {
// try to load persisted state from Quasar LocalStorage
try {
const saved: unknown = LocalStorage.getItem(STORAGE_KEY)
if (saved && typeof saved === 'object') {
const s = saved as Record<string, unknown>
if (Array.isArray(s.items)) {
const items = s.items as Array<
| { key: 'taxpayer'; data: TaxpayerForm }
| { key: 'marital'; data: MaritalData }
>
return { items }
}
}
} catch {
// ignore parsing errors and fall back to defaults
}
return {
items: [
{ key: 'taxpayer', data: { ...defaultTaxpayer } as TaxpayerForm },
{ key: 'marital', data: { ...defaultMarital } as MaritalData }
] as Array<{ key: 'taxpayer'; data: TaxpayerForm } | { key: 'marital'; data: MaritalData }>
}
},
actions: {
// persist helper
persist() {
try {
LocalStorage.set(STORAGE_KEY, { items: this.items })
} catch {
// ignore storage errors (e.g., quota exceeded)
}
},
// Type-guard helpers
_findTaxpayer(): { key: 'taxpayer'; data: TaxpayerForm } | undefined {
return this.items.find((i): i is { key: 'taxpayer'; data: TaxpayerForm } => i.key === 'taxpayer')
},
_findMarital(): { key: 'marital'; data: MaritalData } | undefined {
return this.items.find((i): i is { key: 'marital'; data: MaritalData } => i.key === 'marital')
},
// Taxpayer-specific helpers
getTaxpayer() {
return this._findTaxpayer()?.data
},
setTaxpayer(partial: Partial<TaxpayerForm>) {
const it = this._findTaxpayer()
if (it) it.data = { ...it.data, ...partial }
this.persist()
},
replaceTaxpayer(payload: TaxpayerForm) {
const it = this._findTaxpayer()
if (it) it.data = payload
this.persist()
},
resetTaxpayer() {
const it = this._findTaxpayer()
if (it) it.data = { ...defaultTaxpayer }
this.persist()
},
// Marital-specific helpers
getMarital() {
return this._findMarital()?.data
},
setMarital(partial: Partial<MaritalData>) {
const it = this._findMarital()
if (it) it.data = { ...it.data, ...partial }
this.persist()
},
replaceMarital(payload: MaritalData) {
const it = this._findMarital()
if (it) it.data = payload
this.persist()
},
resetMarital() {
const it = this._findMarital()
if (it) it.data = { ...defaultMarital }
this.persist()
}
}
})

View File

@@ -0,0 +1,9 @@
import { defineStore } from 'pinia'
const ZERO_UUID = '00000000-0000-0000-0000-000000000000'
export const useUserstore = defineStore('userstore', {
state: () => ({
id: ZERO_UUID,
}),
})