From 15d98a80d2144240cdabed1abd4735a11882f0f2 Mon Sep 17 00:00:00 2001 From: Zain Adam Date: Sat, 14 Sep 2024 01:21:39 +0800 Subject: [PATCH] Restruktur data dan menambahkan tipe `ProductMovement` --- src/@types/base-64-blob.ts | 4 +-- src/@types/iso-date.ts | 1 + .../data/products/[id]/_hook.ts | 2 +- .../_components/product-card/product-card.tsx | 24 ++++++------- .../_components/product-form/_hook.ts | 10 +----- .../_components/product-form/_props.ts | 2 +- src/components/image-input/image-input.tsx | 2 +- src/enums/page-url.ts | 6 ++++ src/models/db.ts | 12 +++++-- src/models/table-types/product-movement.ts | 35 +++++++++++++++++++ src/models/table-types/product.ts | 33 ++++++++++------- src/models/table-types/warehouse.ts | 11 ++++++ 12 files changed, 99 insertions(+), 43 deletions(-) create mode 100644 src/@types/iso-date.ts create mode 100644 src/models/table-types/product-movement.ts create mode 100644 src/models/table-types/warehouse.ts diff --git a/src/@types/base-64-blob.ts b/src/@types/base-64-blob.ts index a35a623..4a766d2 100644 --- a/src/@types/base-64-blob.ts +++ b/src/@types/base-64-blob.ts @@ -1,3 +1 @@ -type Base64Blob = string - -export default Base64Blob +export type Base64Blob = string diff --git a/src/@types/iso-date.ts b/src/@types/iso-date.ts new file mode 100644 index 0000000..de3cec2 --- /dev/null +++ b/src/@types/iso-date.ts @@ -0,0 +1 @@ +export type ISODate = string diff --git a/src/app/(authenticated user)/data/products/[id]/_hook.ts b/src/app/(authenticated user)/data/products/[id]/_hook.ts index 1f129d6..defadb8 100644 --- a/src/app/(authenticated user)/data/products/[id]/_hook.ts +++ b/src/app/(authenticated user)/data/products/[id]/_hook.ts @@ -1,5 +1,5 @@ // types -import type Product from '@/models/table-types/product' +import type { Product } from '@/models/table-types/product' import type { ProductFormProps } from '../_components/product-form/_props' // vendors import { useRouter } from 'next/navigation' diff --git a/src/app/(authenticated user)/data/products/_components/product-card/product-card.tsx b/src/app/(authenticated user)/data/products/_components/product-card/product-card.tsx index da4d09a..0cd0bb8 100644 --- a/src/app/(authenticated user)/data/products/_components/product-card/product-card.tsx +++ b/src/app/(authenticated user)/data/products/_components/product-card/product-card.tsx @@ -1,7 +1,7 @@ 'use client' // types -import type Product from '@/models/table-types/product' +import type { Product } from '@/models/table-types/product' // vendors import { Card, @@ -23,16 +23,7 @@ import PageUrlEnum from '@/enums/page-url' import { useHook } from './_hook' export function ProductCard({ - data: { - id, - name, - base_cost, - default_price, - qty_unit, - qty, - category, - image_file, - }, + data: { id, name, default_price, qty_unit, category, image_file, stocks }, className, as, }: { @@ -43,6 +34,12 @@ export function ProductCard({ }) { const { handleOpenDeleteModal, deleteConfirmationModal } = useHook(id) + const totalStock = stocks.reduce((acc, { qty }) => acc + qty, 0) + const cost = + totalStock === 0 + ? 0 + : stocks.reduce((acc, { qty, cost }) => acc + cost * qty, 0) / totalStock + return ( {category ?? 'Tanpa Kategori'} - {formatNumber(qty)} {qty_unit} + {formatNumber(totalStock)} + {qty_unit}

HPP

-

{formatNumber(base_cost)}

+

{formatNumber(cost)}

diff --git a/src/app/(authenticated user)/data/products/_components/product-form/_hook.ts b/src/app/(authenticated user)/data/products/_components/product-form/_hook.ts index a58f184..a0e84a4 100644 --- a/src/app/(authenticated user)/data/products/_components/product-form/_hook.ts +++ b/src/app/(authenticated user)/data/products/_components/product-form/_hook.ts @@ -1,4 +1,4 @@ -import type Product from '@/models/table-types/product' +import type { Product } from '@/models/table-types/product' import { type FormEvent, useState } from 'react' import type { ProductFormProps } from './_props' import { useDebouncedCallback } from 'use-debounce' @@ -53,14 +53,6 @@ export function useHook( formValues.code = formValues.id.toString() } - if (!formValues.base_cost) { - formValues.base_cost = 0 - } - - if (!formValues.qty) { - formValues.qty = 0 - } - onSubmit?.(formValues) }, } diff --git a/src/app/(authenticated user)/data/products/_components/product-form/_props.ts b/src/app/(authenticated user)/data/products/_components/product-form/_props.ts index daf3064..441df7a 100644 --- a/src/app/(authenticated user)/data/products/_components/product-form/_props.ts +++ b/src/app/(authenticated user)/data/products/_components/product-form/_props.ts @@ -1,4 +1,4 @@ -import type Product from '@/models/table-types/product' +import type { Product } from '@/models/table-types/product' export interface ProductFormProps { id: HTMLFormElement['id'] diff --git a/src/components/image-input/image-input.tsx b/src/components/image-input/image-input.tsx index 19ece9a..8d00535 100644 --- a/src/components/image-input/image-input.tsx +++ b/src/components/image-input/image-input.tsx @@ -1,6 +1,6 @@ 'use client' -import Base64Blob from '@/@types/base-64-blob' +import { Base64Blob } from '@/@types/base-64-blob' import resizeImage from '@/components/image-input/functions/resize-image' import { Button, Image, Tooltip } from '@nextui-org/react' import { diff --git a/src/enums/page-url.ts b/src/enums/page-url.ts index 2650764..3d9cae1 100644 --- a/src/enums/page-url.ts +++ b/src/enums/page-url.ts @@ -1,12 +1,18 @@ enum PageUrlEnum { HOME = '/', + PURCHASE_LIST = '/purchases', + PURCHASE_CREATE = '/purchases/create', + PURCHASE_EDIT = '/purchases/:id', + APP_SETTING_PAGE_URL = '/settings', PRODUCT_LIST = '/data/products', PRODUCT_CREATE = '/data/products/create', PRODUCT_EDIT = '/data/products/:id', + WAREHOUSE_LIST = '/data/warehouses', + USER_LIST = '/data/users', BACKUPS = '/data/backups', diff --git a/src/models/db.ts b/src/models/db.ts index 73af808..5c09a0a 100644 --- a/src/models/db.ts +++ b/src/models/db.ts @@ -1,8 +1,12 @@ import Dexie, { type EntityTable } from 'dexie' -import type Product from './table-types/product' +import type { Product } from './table-types/product' +import type { Warehouse } from './table-types/warehouse' +import type { ProductMovement } from './table-types/product-movement' interface Tables { + warehouses: EntityTable products: EntityTable + productMovements: EntityTable } const db = new Dexie('sensasi-pos-db') as Dexie & Tables @@ -11,8 +15,10 @@ const db = new Dexie('sensasi-pos-db') as Dexie & Tables * @see https://dexie.org/docs/Version/Version.stores() */ db.version(1).stores({ - products: - '++id, &code, &barcode_reg_id, &name, description, category, created_at, updated_at, deleted_at', + warehouses: '++id, &name, note', + products: '++id, &code, &barcode_reg_id, &name, description, category', + productMovements: + '&uuid, at, type, note, warehouse_state, details.product_state', }) export default db diff --git a/src/models/table-types/product-movement.ts b/src/models/table-types/product-movement.ts new file mode 100644 index 0000000..4f44362 --- /dev/null +++ b/src/models/table-types/product-movement.ts @@ -0,0 +1,35 @@ +import type { UUID } from 'crypto' +import type { Warehouse } from './warehouse' +import type { Product } from './product' +import type { Base64Blob } from '@/@types/base-64-blob' +import type { ISODate } from '@/@types/iso-date' + +export interface ProductMovement { + uuid: Readonly + + at: ISODate + type: 'sale' | 'purchase' | 'return' | 'adjustment' + note?: string + + warehouse_state: Readonly + + details: { + product_state: Readonly + + qty: number + price: number + }[] + + additional_costs: { + name: string + value: number + }[] + + created_at: ISODate + updated_at: ISODate + + files: { + blob: Base64Blob + description?: string + }[] +} diff --git a/src/models/table-types/product.ts b/src/models/table-types/product.ts index 143716b..a95d049 100644 --- a/src/models/table-types/product.ts +++ b/src/models/table-types/product.ts @@ -1,7 +1,10 @@ -import type Base64Blob from '@/@types/base-64-blob' +import type { Base64Blob } from '@/@types/base-64-blob' +import type { ISODate } from '@/@types/iso-date' +import type { Warehouse } from './warehouse' + +export interface Product { + id: Readonly -interface Product { - id: number code?: string barcode_reg_id?: string @@ -9,17 +12,23 @@ interface Product { description?: string category?: string - qty: number + image_file?: Base64Blob + + created_at: ISODate + updated_at: ISODate + deleted_at?: ISODate + qty_unit: string + default_price: number // per unit - base_cost: number - default_price: number + low_qty_threshold?: number - image_file?: Base64Blob + stocks: { + warehouse_id: Warehouse['id'] - created_at: string - updated_at: string - deleted_at?: string + qty: number + cost: number // per unit + default_price?: number // use parent product.default_price_per_unit if not set + low_qty_threshold?: number // use parent product.low_qty_threshold if not set + }[] } - -export default Product diff --git a/src/models/table-types/warehouse.ts b/src/models/table-types/warehouse.ts new file mode 100644 index 0000000..bdf17b5 --- /dev/null +++ b/src/models/table-types/warehouse.ts @@ -0,0 +1,11 @@ +import type { ISODate } from '@/@types/iso-date' + +export interface Warehouse { + id: Readonly + name: string + note?: string + + created_at: ISODate + updated_at: ISODate + deleted_at?: ISODate +}