import { ROUTES } from "@/lib/dashboards/ecommerce/nav"
import { type Order, type Product } from "@/lib/sample-data"
import { type StatusVariant } from "@/components/ui/status-badge"
/**
* The E-commerce dashboard's words, and its one rule about a sale: how an
* order's and a product's status are toned and called, which orders count as
* sold, and where an order, a product and a customer live. One module the
* pages share, so "paid" wears the same tone on the order book, an order and
* a product's history, and a sale means the same thing on the catalogue and
* on a product's page. Plain constants and pure functions — the entity types
* above are erased — so a client island and a server file can both import it
* without the store coming along.
*/
/**
* How an order's status is toned wherever it is shown. Paid is money in hand
* with the goods not yet gone, so it reads as information, not success; a
* refund is money gone back, a warning rather than a failure.
*/
export const ORDER_STATUS_MAP: Record<Order["status"], StatusVariant> = {
pending: "warning",
paid: "info",
fulfilled: "success",
refunded: "warning",
cancelled: "danger",
}
export const PRODUCT_STATUS_LABELS: Record<Product["status"], string> = { active: "Active", archived: "Archived" }
/**
* Each way an order is paid, as a reader reads it: the words the order book
* uses, so a row never prints the stored value under a CSS capital.
*/
export const PAYMENT_LABEL: Record<Order["paymentMethod"], string> = {
card: "Card",
wallet: "Wallet",
bank: "Bank",
cash: "Cash",
voucher: "Voucher",
}
export const PRODUCT_STATUS_MAP: Record<Product["status"], StatusVariant> = { active: "success", archived: "neutral" }
/**
* The order states whose goods count as sold: the money was taken and kept.
* A pending order has not been paid for, and a cancelled cart and a refund are
* not sales.
*/
export const SOLD_STATUSES: readonly Order["status"][] = ["paid", "fulfilled"]
export function isSold(order: Pick<Order, "status">): boolean {
return SOLD_STATUSES.includes(order.status)
}
/** What one product sold over a window: its units, and what those lines charged in cents. */
export type ProductSales = { units: number; cents: number }
/**
* What each product sold between two instants, in epoch milliseconds: the
* lines of every sold order placed after `from` and at or before `to`. Each
* line is counted at the price its order charged, never today's. Products
* that sold nothing are absent from the map.
*/
export function salesBetween(orders: readonly Order[], from: number, to: number): Map<string, ProductSales> {
const sales = new Map<string, ProductSales>()
for (const order of orders) {
if (!isSold(order)) continue
const placed = order.placedAt.getTime()
if (placed <= from || placed > to) continue
for (const item of order.items) {
const sale = sales.get(item.productId) ?? { units: 0, cents: 0 }
sale.units += item.qty
sale.cents += item.qty * item.unitCents
sales.set(item.productId, sale)
}
}
return sales
}
/** An order's own page, from the dashboard's route table. */
export const orderHref = (id: string) => ROUTES.order.replace("[id]", id)
/** A product's own page. */
export const productHref = (id: string) => ROUTES.product.replace("[id]", id)
/** A customer's record. */
export const customerHref = (id: string) => ROUTES.customer.replace("[id]", id)