diff --git a/src/stores.ts b/src/stores.ts new file mode 100644 index 0000000..df4a672 --- /dev/null +++ b/src/stores.ts @@ -0,0 +1,184 @@ +import { createContext } from "solid-js"; +import { createStore as createStore_ } from "solid-js/store"; +import { addressSchema, createAddress } from "./components/Address"; +import { createLocalStore as createLocalStore_ } from "./localStore"; +import { getUnixTime } from "date-fns"; +import z, { Infer } from "myzod"; + +export const POSITION_TYPE_QUANTITY = "QUANTITY"; +export const POSITION_TYPE_AGILE = "AGILE"; + +export const positionSchema = z.object({ + id: z.number(), + name: z.string(), + enabled: z.boolean(), + type: z.literals(POSITION_TYPE_QUANTITY, POSITION_TYPE_AGILE), + agilePointsMin: z.number().optional(), + agilePointsMax: z.number().optional(), + agileRiskFactor: z.number().optional(), + number: z.string().optional(), + description: z.string().optional(), + quantity: z.number(), + fixedDiscountPrice: z.number().optional(), + itemPrice: z.number().optional(), +}); + +export type Position = Infer; + +export const PRINT_TYPE_OFFER = "OFFER"; +export const PRINT_TYPE_CONFIRMATION = "CONFIRMATION"; +export const PRINT_TYPE_INVOICE = "INVOICE"; + +export const createUiStore = () => + createStore_({ + printType: PRINT_TYPE_INVOICE as + | typeof PRINT_TYPE_OFFER + | typeof PRINT_TYPE_CONFIRMATION + | typeof PRINT_TYPE_INVOICE, + selectedPosition: undefined as undefined | number, + }); +export type UiStore = ReturnType; +export const UiStoreContext = createContext(); + +export const storeSchema = z.object({ + version: z.number(), + project: z.object({ + orderNumber: z.string(), + projectNumber: z.string(), + deliveryNumber: z.string(), + deliveryDate: z.number().optional(), + date: z.number(), + preface: z.string().optional(), + conclusion: z.string().optional(), + }), + invoice: z.object({ + reference: z.string(), + message: z.string(), + }), + fullWidthInvoice: z.boolean(), + useCustomerAlternativeAddress: z.boolean(), + customer: z.object({ + customerNumber: z.string(), + vatNumber: z.string(), + alternativeAddress: addressSchema, + debtorAddress: addressSchema, + }), + defaultItemPrice: z.number(), + agileRiskFactor: z.number(), + agileHoursPerStoryPoint: z.number(), + defaultPositionType: z.literals(POSITION_TYPE_QUANTITY, POSITION_TYPE_AGILE), + positions: z.array(positionSchema), +}); +export type StoreObject = Infer; + +export const createStore = () => + createStore_({ + version: 1, + project: { + orderNumber: "", + projectNumber: "", + deliveryNumber: "", + date: getUnixTime(new Date()), + }, + invoice: { + reference: "", + message: "", + }, + fullWidthInvoice: true, + useCustomerAlternativeAddress: false, + customer: { + customerNumber: "", + vatNumber: "", + alternativeAddress: createAddress(), + debtorAddress: createAddress(), + }, + defaultPositionType: POSITION_TYPE_QUANTITY, + defaultItemPrice: 0, + agileRiskFactor: 0.7, + agileHoursPerStoryPoint: 4, + positions: [ + { + id: 0, + name: "Entwicklung", + enabled: true, + quantity: 0, + agilePointsMin: 8, + agilePointsMax: 13, + itemPrice: 80, + type: POSITION_TYPE_AGILE, + }, + { + id: 1, + name: "Kaffee Trinken", + enabled: true, + quantity: 2, + itemPrice: 160, + type: POSITION_TYPE_QUANTITY, + }, + { + id: 2, + name: "Pizza Essen", + enabled: true, + quantity: 1, + itemPrice: 280, + type: POSITION_TYPE_QUANTITY, + }, + ] as Position[], + }); + +export type Store = ReturnType; +export const StoreContext = createContext(); + +export const localStoreSchema = z.object({ + showWelcome: z.boolean(), + version: z.number(), + vatNumber: z.string(), + vatRate: z.number(), + paymentTerms: z.string().optional(), + iban: z.string(), + creditor: addressSchema, + customAddress: addressSchema, + contact: z.object({ + name: z.string(), + phone: z.string(), + email: z.string(), + }), + showLufraiWatermark: z.boolean(), + // TODO: Signature Image + logo: z + .object({ + type: z.string(), + url: z.string(), + width: z.number(), + height: z.number(), + }) + .optional(), + useCustomAddress: z.boolean(), +}); +export type LocalStoreObject = Infer; + +export const createLocalStore = () => + createLocalStore_( + { + version: 1, + showWelcome: true, + vatNumber: "", + vatRate: 0.0, + paymentTerms: undefined, + creditor: createAddress(), + customAddress: createAddress(), + contact: { + name: "", + phone: "", + email: "", + }, + logo: undefined, + showLufraiWatermark: false, + useCustomAddress: false, + iban: "", + }, + { prefix: "invoice-app" } + ); + +export type LocalStore = ReturnType; +export const LocalStoreContext = createContext();