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>
55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import { create } from "zustand";
|
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
import { seedEmergencyContacts } from "@/lib/data/seed";
|
|
|
|
export type EmergencyContact = {
|
|
id: string;
|
|
name: string;
|
|
phone: string;
|
|
relationship: string;
|
|
};
|
|
|
|
type EcState = {
|
|
contacts: EmergencyContact[];
|
|
graceMinutesDefault: number;
|
|
escalationEnabled: boolean;
|
|
lastEscalationAt?: string;
|
|
add: (c: Omit<EmergencyContact, "id">) => void;
|
|
remove: (id: string) => void;
|
|
setGrace: (m: number) => void;
|
|
setEscalationEnabled: (v: boolean) => void;
|
|
markEscalated: () => void;
|
|
};
|
|
|
|
export const useEmergencyContactStore = create<EcState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
contacts: seedEmergencyContacts,
|
|
graceMinutesDefault: 30,
|
|
escalationEnabled: true,
|
|
add: (c) =>
|
|
set({
|
|
contacts: [{ ...c, id: `ec_${Date.now()}` }, ...get().contacts],
|
|
}),
|
|
remove: (id) =>
|
|
set({ contacts: get().contacts.filter((c) => c.id !== id) }),
|
|
setGrace: (m) => set({ graceMinutesDefault: m }),
|
|
setEscalationEnabled: (v) => set({ escalationEnabled: v }),
|
|
markEscalated: () =>
|
|
set({ lastEscalationAt: new Date().toISOString() }),
|
|
}),
|
|
{
|
|
name: "gishen-emergency",
|
|
storage: createJSONStorage(() => AsyncStorage),
|
|
version: 2,
|
|
migrate: (persisted: unknown) => {
|
|
const state = (persisted ?? {}) as Partial<EcState>;
|
|
return !state.contacts?.length
|
|
? { ...state, contacts: seedEmergencyContacts }
|
|
: state;
|
|
},
|
|
}
|
|
)
|
|
);
|