207 lines
5.0 KiB
TypeScript
207 lines
5.0 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { computed, ref } from 'vue'
|
|
import { apiRequest } from '@/services/http'
|
|
|
|
const STORAGE_KEY = 'ft_catalog_requests'
|
|
|
|
export type CatalogRequestItem = {
|
|
productId: string
|
|
productName: string
|
|
productCode: string
|
|
quantity: number
|
|
}
|
|
|
|
/** UI statuses (legacy) + server statuses mapped in */
|
|
export type CatalogRequestStatus =
|
|
| 'submitted'
|
|
| 'reviewing'
|
|
| 'preparing'
|
|
| 'shipped'
|
|
| 'delivered'
|
|
| 'new'
|
|
| 'approved'
|
|
| 'ready_to_ship'
|
|
| 'returned'
|
|
| 'cancelled'
|
|
|
|
export type CatalogRequest = {
|
|
id: string
|
|
createdAt: string
|
|
status: CatalogRequestStatus
|
|
note?: string
|
|
items: CatalogRequestItem[]
|
|
}
|
|
|
|
const SERVER_TO_UI: Record<string, CatalogRequestStatus> = {
|
|
new: 'submitted',
|
|
approved: 'reviewing',
|
|
ready_to_ship: 'preparing',
|
|
delivered: 'delivered',
|
|
returned: 'delivered',
|
|
cancelled: 'submitted',
|
|
}
|
|
|
|
function readAll(): CatalogRequest[] {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY)
|
|
if (!raw) return []
|
|
const parsed = JSON.parse(raw) as unknown
|
|
return Array.isArray(parsed) ? (parsed as CatalogRequest[]) : []
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
function writeAll(list: CatalogRequest[]) {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(list))
|
|
}
|
|
|
|
const STATUS_LABELS: Record<string, string> = {
|
|
submitted: 'ثبتشده',
|
|
reviewing: 'در حال بررسی',
|
|
preparing: 'آمادهسازی',
|
|
shipped: 'ارسالشده',
|
|
delivered: 'تحویلشده',
|
|
new: 'درخواست جدید',
|
|
approved: 'تأیید شده',
|
|
ready_to_ship: 'آماده ارسال',
|
|
returned: 'بازگردانده شده',
|
|
cancelled: 'لغو شده',
|
|
}
|
|
|
|
function mapServerRow(row: {
|
|
id: string
|
|
createdAt: string
|
|
status: string
|
|
note?: string
|
|
items: Array<{
|
|
productId: string
|
|
productName: string
|
|
productCode: string
|
|
quantity: number
|
|
}>
|
|
}): CatalogRequest {
|
|
return {
|
|
id: row.id,
|
|
createdAt: row.createdAt,
|
|
status: SERVER_TO_UI[row.status] ?? (row.status as CatalogRequestStatus),
|
|
note: row.note,
|
|
items: row.items.map((i) => ({
|
|
productId: i.productId,
|
|
productName: i.productName,
|
|
productCode: i.productCode,
|
|
quantity: i.quantity,
|
|
})),
|
|
}
|
|
}
|
|
|
|
export const useCatalogRequestsStore = defineStore('catalogRequests', () => {
|
|
const requests = ref<CatalogRequest[]>(readAll())
|
|
const useApi = ref(true)
|
|
|
|
const sorted = computed(() =>
|
|
[...requests.value].sort((a, b) => b.createdAt.localeCompare(a.createdAt)),
|
|
)
|
|
|
|
function statusLabel(status: CatalogRequest['status']) {
|
|
return STATUS_LABELS[status] ?? status
|
|
}
|
|
|
|
async function hydrate() {
|
|
if (!useApi.value) {
|
|
requests.value = readAll()
|
|
return
|
|
}
|
|
try {
|
|
const rows = await apiRequest<
|
|
Array<{
|
|
id: string
|
|
createdAt: string
|
|
status: string
|
|
note?: string
|
|
items: Array<{
|
|
productId: string
|
|
productName: string
|
|
productCode: string
|
|
quantity: number
|
|
}>
|
|
}>
|
|
>('/catalog-requests')
|
|
requests.value = rows.map(mapServerRow)
|
|
writeAll(requests.value)
|
|
} catch {
|
|
useApi.value = false
|
|
requests.value = readAll()
|
|
}
|
|
}
|
|
|
|
async function create(input: { items: CatalogRequestItem[]; note?: string }) {
|
|
const items = input.items
|
|
.filter((i) => i.productId && i.quantity > 0)
|
|
.map((i) => ({
|
|
...i,
|
|
quantity: Math.max(1, Math.floor(i.quantity)),
|
|
}))
|
|
if (!items.length) {
|
|
return { success: false as const, message: 'حداقل یک قلم با تعداد معتبر لازم است.' }
|
|
}
|
|
|
|
if (useApi.value) {
|
|
try {
|
|
const row = await apiRequest<{
|
|
id: string
|
|
createdAt: string
|
|
status: string
|
|
note?: string
|
|
items: Array<{
|
|
productId: string
|
|
productName: string
|
|
productCode: string
|
|
quantity: number
|
|
}>
|
|
}>('/catalog-requests', {
|
|
method: 'POST',
|
|
body: {
|
|
note: input.note?.trim() || undefined,
|
|
items: items.map((i) => ({
|
|
productId: i.productId,
|
|
quantity: i.quantity,
|
|
})),
|
|
},
|
|
})
|
|
const mapped = mapServerRow(row)
|
|
requests.value = [mapped, ...requests.value.filter((r) => r.id !== mapped.id)]
|
|
writeAll(requests.value)
|
|
return { success: true as const, request: mapped }
|
|
} catch (err) {
|
|
useApi.value = false
|
|
// fall through to local
|
|
}
|
|
}
|
|
|
|
const row: CatalogRequest = {
|
|
id: `cr-${Date.now()}`,
|
|
createdAt: new Date().toISOString(),
|
|
status: 'submitted',
|
|
note: input.note?.trim() || undefined,
|
|
items,
|
|
}
|
|
requests.value = [row, ...requests.value]
|
|
writeAll(requests.value)
|
|
return { success: true as const, request: row }
|
|
}
|
|
|
|
function getById(id: string) {
|
|
return requests.value.find((r) => r.id === id) ?? null
|
|
}
|
|
|
|
return {
|
|
requests,
|
|
sorted,
|
|
statusLabel,
|
|
create,
|
|
getById,
|
|
hydrate,
|
|
}
|
|
})
|