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>
104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import { create } from "zustand";
|
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
|
|
export type SavedAddress = {
|
|
id: string;
|
|
label: string;
|
|
area: string;
|
|
street: string;
|
|
landmark?: string;
|
|
notes?: string;
|
|
isDefault: boolean;
|
|
};
|
|
|
|
type AddressState = {
|
|
addresses: SavedAddress[];
|
|
add: (a: Omit<SavedAddress, "id" | "isDefault"> & { isDefault?: boolean }) => void;
|
|
update: (id: string, patch: Partial<SavedAddress>) => void;
|
|
remove: (id: string) => void;
|
|
setDefault: (id: string) => void;
|
|
defaultAddress: () => SavedAddress | null;
|
|
};
|
|
|
|
export const seedAddresses: SavedAddress[] = [
|
|
{
|
|
id: "addr_home",
|
|
label: "Home",
|
|
area: "Bole, Addis Ababa",
|
|
street: "Rwanda St, Building 12, Apt 4B",
|
|
landmark: "Near Edna Mall",
|
|
notes: "Call on arrival",
|
|
isDefault: true,
|
|
},
|
|
{
|
|
id: "addr_office",
|
|
label: "Office",
|
|
area: "Kazanchis, Addis Ababa",
|
|
street: "Gabon St, Yaltopia Tower, Floor 6",
|
|
landmark: "Opposite UNECA",
|
|
isDefault: false,
|
|
},
|
|
];
|
|
|
|
export const useAddressStore = create<AddressState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
addresses: seedAddresses,
|
|
add: (a) => {
|
|
const id = `addr_${Date.now()}`;
|
|
const makeDefault = a.isDefault || get().addresses.length === 0;
|
|
set({
|
|
addresses: [
|
|
{
|
|
id,
|
|
label: a.label,
|
|
area: a.area,
|
|
street: a.street,
|
|
landmark: a.landmark,
|
|
notes: a.notes,
|
|
isDefault: makeDefault,
|
|
},
|
|
...get().addresses.map((x) =>
|
|
makeDefault ? { ...x, isDefault: false } : x
|
|
),
|
|
],
|
|
});
|
|
},
|
|
update: (id, patch) =>
|
|
set({
|
|
addresses: get().addresses.map((a) =>
|
|
a.id === id ? { ...a, ...patch } : a
|
|
),
|
|
}),
|
|
remove: (id) => {
|
|
const next = get().addresses.filter((a) => a.id !== id);
|
|
if (next.length && !next.some((a) => a.isDefault)) {
|
|
next[0] = { ...next[0], isDefault: true };
|
|
}
|
|
set({ addresses: next });
|
|
},
|
|
setDefault: (id) =>
|
|
set({
|
|
addresses: get().addresses.map((a) => ({
|
|
...a,
|
|
isDefault: a.id === id,
|
|
})),
|
|
}),
|
|
defaultAddress: () =>
|
|
get().addresses.find((a) => a.isDefault) ?? get().addresses[0] ?? null,
|
|
}),
|
|
{
|
|
name: "gishen-addresses",
|
|
storage: createJSONStorage(() => AsyncStorage),
|
|
version: 1,
|
|
migrate: (persisted: unknown) => {
|
|
const state = (persisted ?? {}) as Partial<AddressState>;
|
|
return !state.addresses?.length
|
|
? { ...state, addresses: seedAddresses }
|
|
: state;
|
|
},
|
|
}
|
|
)
|
|
);
|