first commit
This commit is contained in:
102
app/src/stores/children.ts
Normal file
102
app/src/stores/children.ts
Normal 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
66
app/src/stores/income.ts
Normal 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
32
app/src/stores/index.ts
Normal 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
40
app/src/stores/marital.ts
Normal 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 }
|
||||
}
|
||||
34
app/src/stores/taxpayer.ts
Normal file
34
app/src/stores/taxpayer.ts
Normal 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
121
app/src/stores/taxstore.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
})
|
||||
9
app/src/stores/userstore.ts
Normal file
9
app/src/stores/userstore.ts
Normal 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,
|
||||
}),
|
||||
})
|
||||
Reference in New Issue
Block a user