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/profileModeStore.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

110 lines
3.4 KiB
TypeScript

import AsyncStorage from "@react-native-async-storage/async-storage";
import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";
export type ProfileMode = "personal" | "corporate";
export type OrgMembership = {
orgId: string;
orgName: string;
planName: string;
remainingAllowance: number;
monthlyCap: number;
};
type ProfileState = {
mode: ProfileMode;
memberships: OrgMembership[];
activeOrgId: string | null;
setMode: (mode: ProfileMode) => void;
setActiveOrg: (orgId: string | null) => void;
joinOrg: (code: string) => { ok: boolean; message: string };
activeMembership: () => OrgMembership | null;
quoteSplit: (subtotal: number) => { covered: number; selfPay: number };
consumeAllowance: (amount: number) => void;
};
const DEMO_ORGS: Record<string, OrgMembership> = {
"GISHEN-BANK": {
orgId: "org_bank",
orgName: "Demo Bank Ethiopia",
planName: "Staff",
remainingAllowance: 2500,
monthlyCap: 5000,
},
"GISHEN-NGO": {
orgId: "org_ngo",
orgName: "Demo NGO",
planName: "Standard",
remainingAllowance: 1200,
monthlyCap: 3000,
},
};
const seededMembership = { ...DEMO_ORGS["GISHEN-BANK"] };
export const useProfileModeStore = create<ProfileState>()(
persist(
(set, get) => ({
mode: "personal",
memberships: [seededMembership],
activeOrgId: null,
setMode: (mode) => set({ mode }),
setActiveOrg: (orgId) =>
set({ activeOrgId: orgId, mode: orgId ? "corporate" : "personal" }),
joinOrg: (code) => {
const key = code.trim().toUpperCase();
const org = DEMO_ORGS[key];
if (!org) return { ok: false, message: "Invalid join code" };
const memberships = get().memberships;
if (memberships.some((m) => m.orgId === org.orgId)) {
set({ activeOrgId: org.orgId, mode: "corporate" });
return { ok: true, message: "Already a member — switched to org" };
}
set({
memberships: [...memberships, { ...org }],
activeOrgId: org.orgId,
mode: "corporate",
});
return { ok: true, message: `Joined ${org.orgName}` };
},
activeMembership: () => {
const { activeOrgId, memberships, mode } = get();
if (mode !== "corporate" || !activeOrgId) return null;
return memberships.find((m) => m.orgId === activeOrgId) ?? null;
},
quoteSplit: (subtotal) => {
const m = get().activeMembership();
if (!m) return { covered: 0, selfPay: subtotal };
const covered = Math.min(subtotal, m.remainingAllowance);
return { covered, selfPay: Math.max(0, subtotal - covered) };
},
consumeAllowance: (amount) => {
const { activeOrgId, memberships } = get();
if (!activeOrgId || amount <= 0) return;
set({
memberships: memberships.map((m) =>
m.orgId === activeOrgId
? {
...m,
remainingAllowance: Math.max(0, m.remainingAllowance - amount),
}
: m
),
});
},
}),
{
name: "gishen-profile-mode",
storage: createJSONStorage(() => AsyncStorage),
version: 2,
migrate: (persisted: unknown) => {
const state = (persisted ?? {}) as Partial<ProfileState>;
return !state.memberships?.length
? { ...state, memberships: [seededMembership] }
: state;
},
}
)
);