This repository has been archived on 2026-08-11. You can view files and clone it, but cannot push or open issues or pull requests.
Gishen-Mob/lib/stores/ordersStore.ts
kirukib 7310a349c5 Add Gishen mobile app with complete demo shopping and care flows.
Ship Expo Router screens, seeded stores, and polished UX so auth, shop, checkout, prescriptions, loyalty, family, and account processes work end-to-end offline.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-07 01:21:32 +03:00

175 lines
5.3 KiB
TypeScript

import AsyncStorage from "@react-native-async-storage/async-storage";
import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";
import { seedOrders } from "@/lib/data/seed";
import type { CartItem } from "@/lib/stores/cartStore";
import type { Fulfillment, PaymentMethod } from "@/lib/stores/locationStore";
export type OrderStatus =
| "requested"
| "confirmed"
| "paid"
| "dispatched"
| "delivered"
| "completed"
| "cancelled";
export type Order = {
id: string;
createdAt: string;
items: CartItem[];
subtotal: number;
deliveryFee: number;
discount: number;
voucherCode?: string | null;
total: number;
fulfillment: Fulfillment;
branchId?: string | null;
areaLabel?: string;
addressId?: string | null;
addressLine?: string;
paymentMethod: PaymentMethod;
status: OrderStatus;
riderAssigned?: boolean;
corporateCovered?: number;
selfPay?: number;
customerName?: string;
customerPhone?: string;
notes?: string;
timeline?: { at: string; label: string; status: OrderStatus | "created" }[];
};
type OrdersState = {
orders: Order[];
addOrder: (
order: Omit<Order, "id" | "createdAt" | "status" | "timeline" | "discount"> & {
discount?: number;
status?: OrderStatus;
}
) => Order;
updateStatus: (id: string, status: OrderStatus) => void;
cancelOrder: (id: string) => void;
getById: (id: string) => Order | undefined;
};
function timelineFor(status: OrderStatus, createdAt: string) {
const steps: Order["timeline"] = [
{ at: createdAt, label: "Order placed", status: "created" },
];
const add = (label: string, s: OrderStatus, hours: number) => {
const d = new Date(createdAt);
d.setHours(d.getHours() + hours);
steps!.push({ at: d.toISOString(), label, status: s });
};
if (["confirmed", "paid", "dispatched", "delivered", "completed"].includes(status)) {
add("Confirmed by pharmacy", "confirmed", 0.2);
}
if (["paid", "dispatched", "delivered", "completed"].includes(status) && status !== "confirmed") {
add("Payment received", "paid", 0.4);
}
if (["dispatched", "delivered", "completed"].includes(status)) {
add("Out for delivery / ready for pickup", "dispatched", 1);
}
if (["delivered", "completed"].includes(status)) {
add("Delivered / collected", "delivered", 3);
}
if (status === "cancelled") {
steps.push({
at: new Date().toISOString(),
label: "Order cancelled",
status: "cancelled",
});
}
return steps;
}
export const useOrdersStore = create<OrdersState>()(
persist(
(set, get) => ({
orders: seedOrders.map((o) => ({
...o,
discount: o.discount ?? 0,
customerName: o.customerName ?? "Kirukib Abebe",
customerPhone: o.customerPhone ?? "+251911000000",
notes: o.notes ?? "",
timeline: o.timeline ?? timelineFor(o.status, o.createdAt),
})),
addOrder: (payload) => {
const createdAt = new Date().toISOString();
const discount = payload.discount ?? 0;
const status =
payload.status ??
(payload.paymentMethod === "pay_at_branch" ? "confirmed" : "paid");
const order: Order = {
...payload,
discount,
id: `ord_${Date.now()}`,
createdAt,
status,
riderAssigned: false,
timeline: timelineFor(status, createdAt),
};
set({ orders: [order, ...get().orders] });
return order;
},
updateStatus: (id, status) =>
set({
orders: get().orders.map((o) => {
if (o.id !== id) return o;
const next = {
...o,
status,
riderAssigned:
status === "dispatched" || status === "delivered"
? true
: o.riderAssigned,
};
const stamp = new Date().toISOString();
const label =
status === "dispatched"
? "Rider assigned / ready"
: status === "delivered"
? "Delivered / collected"
: status === "cancelled"
? "Order cancelled"
: `Status: ${status}`;
return {
...next,
timeline: [...(o.timeline ?? []), { at: stamp, label, status }],
};
}),
}),
cancelOrder: (id) => get().updateStatus(id, "cancelled"),
getById: (id) => get().orders.find((o) => o.id === id),
}),
{
name: "gishen-orders",
storage: createJSONStorage(() => AsyncStorage),
version: 3,
migrate: (persisted: unknown) => {
const state = (persisted ?? {}) as Partial<OrdersState>;
if (!state.orders?.length) {
return {
...state,
orders: seedOrders.map((o) => ({
...o,
discount: 0,
customerName: "Kirukib Abebe",
customerPhone: "+251911000000",
timeline: timelineFor(o.status, o.createdAt),
})),
};
}
return {
...state,
orders: state.orders.map((o) => ({
...o,
discount: o.discount ?? 0,
timeline: o.timeline ?? timelineFor(o.status, o.createdAt),
})),
};
},
}
)
);