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/data/clinical.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

323 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { Product } from "@/lib/data/products";
export type StorageNote = {
icon: "thermometer-outline" | "sunny-outline" | "happy-outline" | "water-outline";
title: string;
body: string;
};
export type DrugFacts = {
/** Short therapeutic label shown above the product name. */
useCase: string;
/** Dose form: Tablet, Syrup, Cream, Device… */
form: string;
genericName: string;
brandNames: string;
drugClass: string;
/** Selectable strengths on the detail page. Empty for non-dosed products. */
dosages: string[];
sideEffects: { mild: string[]; severe: string[] };
storage: StorageNote[];
directions: { title: string; body: string }[];
stockCount: number;
/** Pharmacist guidance shown in the safety callout. */
advice: string;
};
const CATEGORY_USE_CASE: Record<string, string> = {
medicines: "General Medicine",
vitamins: "Supplements",
"personal-care": "Personal Care",
diabetic: "Diabetes Care",
devices: "Medical Device",
baby: "Baby Care",
"first-aid": "First Aid",
wellness: "Sexual Wellness",
};
const CATEGORY_FORM: Record<string, string> = {
medicines: "Tablet",
vitamins: "Tablet",
"personal-care": "Topical",
diabetic: "Tablet",
devices: "Device",
baby: "Topical",
"first-aid": "Supply",
wellness: "Tablet",
};
/** Per-product clinical overrides. Everything else falls back to category defaults. */
const OVERRIDES: Record<string, Partial<DrugFacts>> = {
"panadol-advance": {
useCase: "Pain & Fever",
genericName: "Paracetamol (Acetaminophen)",
brandNames: "Panadol, Tylenol, Calpol",
drugClass: "Analgesic / Antipyretic",
dosages: ["500mg", "650mg"],
sideEffects: {
mild: ["Nausea", "Sleepiness", "Stomach upset"],
severe: ["Liver damage", "Rash", "Breathing issues"],
},
advice: "Do not exceed 4g of paracetamol in 24 hours across all products.",
},
paracetamol: {
useCase: "Pain & Fever",
genericName: "Paracetamol",
brandNames: "Panadol, Tylenol",
drugClass: "Analgesic / Antipyretic",
dosages: ["500mg"],
advice: "Avoid alcohol while taking this medicine.",
},
"paracetamol-tylenol": {
useCase: "Pain & Fever",
genericName: "Acetaminophen",
brandNames: "Tylenol, Panadol",
drugClass: "Analgesic",
dosages: ["500mg", "650mg"],
},
"paracetamol-caffeine": {
useCase: "Headache Relief",
genericName: "Paracetamol + Caffeine",
brandNames: "Panadol Extra",
drugClass: "Analgesic combination",
dosages: ["500mg / 65mg"],
advice: "Contains caffeine — limit other caffeinated drinks.",
},
snip: {
useCase: "Cold & Flu",
genericName: "Paracetamol + Pseudoephedrine + Chlorphenamine",
brandNames: "SNIP",
drugClass: "Decongestant combination",
sideEffects: {
mild: ["Drowsiness", "Dry mouth", "Dizziness"],
severe: ["Rapid heartbeat", "High blood pressure"],
},
advice: "May cause drowsiness. Do not drive until you know how it affects you.",
},
metformin: {
useCase: "Diabetes Care",
genericName: "Metformin hydrochloride",
brandNames: "Glucophage, Glumet",
drugClass: "Biguanide antidiabetic",
dosages: ["500mg", "850mg", "1000mg"],
sideEffects: {
mild: ["Nausea", "Diarrhoea", "Metallic taste"],
severe: ["Lactic acidosis", "Vitamin B12 deficiency"],
},
advice: "Take with meals to reduce stomach upset. Requires a valid prescription.",
},
ciprofloxacin: {
useCase: "Antibiotic",
genericName: "Ciprofloxacin",
brandNames: "Cipro, Ciprobay",
drugClass: "Fluoroquinolone antibiotic",
dosages: ["250mg", "500mg"],
sideEffects: {
mild: ["Nausea", "Headache", "Dizziness"],
severe: ["Tendon rupture", "Nerve damage"],
},
advice: "Finish the full course even if you feel better.",
},
azitro: {
useCase: "Antibiotic",
genericName: "Azithromycin",
brandNames: "Zithromax, Azitro",
drugClass: "Macrolide antibiotic",
dosages: ["250mg", "500mg"],
advice: "Usually taken once daily for 3 days. Complete the course as prescribed.",
},
diclofenac: {
useCase: "Pain & Inflammation",
genericName: "Diclofenac sodium",
brandNames: "Voltaren, Cataflam",
drugClass: "NSAID",
dosages: ["25mg", "50mg", "75mg"],
sideEffects: {
mild: ["Indigestion", "Headache", "Dizziness"],
severe: ["Stomach bleeding", "Kidney issues"],
},
advice: "Take after food. Avoid if you have a history of stomach ulcers.",
},
pantoprazole: {
useCase: "Acid Reflux",
genericName: "Pantoprazole sodium",
brandNames: "Protonix, Pantocid",
drugClass: "Proton pump inhibitor",
dosages: ["20mg", "40mg"],
advice: "Take 30–60 minutes before your first meal of the day.",
},
desloratidine: {
useCase: "Allergy Relief",
genericName: "Desloratadine",
brandNames: "Clarinex, Aerius",
drugClass: "Antihistamine",
dosages: ["5mg"],
advice: "Non-drowsy for most people, but avoid driving until you're sure.",
},
"nat-c-vitamin-c": {
useCase: "Immune Support",
genericName: "Ascorbic acid",
brandNames: "Nat C, Redoxon",
drugClass: "Vitamin supplement",
dosages: ["500mg", "1000mg"],
sideEffects: { mild: ["Stomach upset", "Heartburn"], severe: ["Kidney stones (high doses)"] },
},
gofen: {
useCase: "Pain & Inflammation",
genericName: "Ibuprofen",
brandNames: "Brufen, Advil, Gofen",
drugClass: "NSAID",
dosages: ["200mg", "400mg"],
advice: "Take with food or milk to protect your stomach.",
},
quemox: {
useCase: "Antibiotic",
genericName: "Amoxicillin",
brandNames: "Amoxil, Quemox",
drugClass: "Penicillin antibiotic",
dosages: ["250mg", "500mg"],
advice: "Tell your pharmacist about any penicillin allergy before use.",
},
sildenafil: {
useCase: "Sexual Wellness",
genericName: "Sildenafil citrate",
brandNames: "Viagra, Cialis (tadalafil alt.)",
drugClass: "PDE5 inhibitor",
dosages: ["25mg", "50mg", "100mg"],
advice: "Never combine with nitrate heart medicines. Prescription required.",
},
"ors-sachets": {
useCase: "Rehydration",
genericName: "Oral rehydration salts",
brandNames: "ORS, Hydralyte",
drugClass: "Electrolyte replacement",
advice: "Dissolve one sachet in 200ml of clean water. Use within 24 hours.",
},
"cough-syrup": {
useCase: "Cough Relief",
form: "Syrup",
genericName: "Dextromethorphan / Guaifenesin",
brandNames: "Robitussin, Benylin",
drugClass: "Antitussive / Expectorant",
dosages: ["100ml", "200ml"],
},
"lubricating-eye-drops": {
useCase: "Eye Care",
form: "Drops",
},
"eye-drops-lubricating": {
useCase: "Eye Care",
form: "Drops",
genericName: "Carboxymethylcellulose",
brandNames: "Refresh Tears, Optive",
drugClass: "Ocular lubricant",
},
"blood-pressure-monitor": {
useCase: "Monitoring",
form: "Device",
genericName: "Upper-arm oscillometric monitor",
brandNames: "HealthTech",
drugClass: "Class II medical device",
},
"glucose-meter-kit": {
useCase: "Diabetes Care",
form: "Device",
genericName: "Blood glucose monitoring system",
brandNames: "DiaCare",
drugClass: "Class II medical device",
},
};
const DEFAULT_SIDE_EFFECTS: DrugFacts["sideEffects"] = {
mild: ["Nausea", "Headache", "Mild dizziness"],
severe: ["Allergic reaction", "Difficulty breathing"],
};
const DEFAULT_STORAGE: StorageNote[] = [
{
icon: "thermometer-outline",
title: "Temperature",
body: "Store at room temperature, between 20°C and 25°C.",
},
{
icon: "sunny-outline",
title: "Light & moisture",
body: "Keep in a dry place, away from direct sunlight.",
},
{
icon: "happy-outline",
title: "Children",
body: "Keep out of reach of children to prevent accidental ingestion.",
},
];
const DEFAULT_DIRECTIONS: DrugFacts["directions"] = [
{
title: "Check with your pharmacist",
body: "Confirm the dose is right for your age, weight and other medicines.",
},
{
title: "Take as directed",
body: "Follow the schedule on the label. Do not double up on a missed dose.",
},
{
title: "Take with water",
body: "Swallow whole with a full glass of water unless told otherwise.",
},
{
title: "Track your response",
body: "Stop and contact us if symptoms persist beyond 3 days.",
},
];
const DEVICE_DIRECTIONS: DrugFacts["directions"] = [
{ title: "Unbox and inspect", body: "Check all parts are present and undamaged." },
{ title: "Prepare", body: "Sit still for 5 minutes and rest your arm at heart level." },
{ title: "Measure", body: "Follow the on-screen prompts and stay quiet during the reading." },
{ title: "Log the result", body: "Record readings so your pharmacist can review trends." },
];
/** Deterministic pseudo-stock so the number is stable between renders. */
function stockFor(product: Product): number {
if (!product.inStock) return 0;
const seed = product.id
.split("")
.reduce((total, char) => total + char.charCodeAt(0), 0);
return 8 + (seed % 44);
}
export function getDrugFacts(product: Product): DrugFacts {
const override = OVERRIDES[product.slug] ?? {};
const isDevice = product.category === "devices" || product.category === "first-aid";
return {
useCase: override.useCase ?? CATEGORY_USE_CASE[product.category] ?? "Healthcare",
form: override.form ?? CATEGORY_FORM[product.category] ?? "Unit",
genericName: override.genericName ?? product.name,
brandNames: override.brandNames ?? product.brand,
drugClass: override.drugClass ?? CATEGORY_USE_CASE[product.category] ?? "Healthcare product",
dosages: override.dosages ?? [],
sideEffects:
override.sideEffects ??
(isDevice ? { mild: ["Skin irritation"], severe: [] } : DEFAULT_SIDE_EFFECTS),
storage: override.storage ?? DEFAULT_STORAGE,
directions: override.directions ?? (isDevice ? DEVICE_DIRECTIONS : DEFAULT_DIRECTIONS),
stockCount: override.stockCount ?? stockFor(product),
advice:
override.advice ??
(product.requiresPrescription
? "A valid prescription is required. Our pharmacist will verify it before dispatch."
: "Speak to our pharmacist if you are pregnant, breastfeeding or taking other medicines."),
};
}
/** Star distribution for the review summary, weighted by the product rating. */
export function getReviewBreakdown(product: Product) {
const weights = [0.62, 0.22, 0.09, 0.04, 0.03];
const shift = Math.max(0, Math.round((4.8 - product.rating) * 10)) / 100;
return [5, 4, 3, 2, 1].map((stars, index) => {
const weight = Math.max(0.01, weights[index] - (index === 0 ? shift : -shift / 4));
return { stars, count: Math.max(1, Math.round(product.reviews * weight)) };
});
}