Add payment/notification prefs, assisted pharmacist codes, Rx status journey, and mock payment intents so demo flows match the storefront brief. Co-authored-by: Cursor <cursoragent@cursor.com>
600 lines
22 KiB
TypeScript
600 lines
22 KiB
TypeScript
import { router } from "expo-router";
|
||
import { useEffect, useMemo, useState } from "react";
|
||
import { Alert, Linking, Pressable, ScrollView, View } from "react-native";
|
||
import { useTranslation } from "react-i18next";
|
||
import {
|
||
AssistedOrderExplainer,
|
||
EntitlementSplitCard,
|
||
LoyaltyRedeemRow,
|
||
PaymentMethodList,
|
||
paymentLabel,
|
||
RxCartGate,
|
||
} from "@/components/checkout";
|
||
import { Button } from "@/components/ui/Button";
|
||
import { Card, InfoRow } from "@/components/ui/Card";
|
||
import { Chip, Segmented } from "@/components/ui/Chip";
|
||
import { Field } from "@/components/ui/Field";
|
||
import { AppHeader } from "@/components/ui/Header";
|
||
import { Screen } from "@/components/ui/Screen";
|
||
import { StickyBar } from "@/components/ui/StickyBar";
|
||
import { Text } from "@/components/ui/Text";
|
||
import { initiatePayment } from "@/lib/api/client";
|
||
import {
|
||
DELIVERY_FEE,
|
||
generatePickupCode,
|
||
orderSubtotalTotal,
|
||
voucherDiscount,
|
||
} from "@/lib/commerce";
|
||
import { branches } from "@/lib/data/branches";
|
||
import { routes } from "@/lib/routes";
|
||
import { useAddressStore } from "@/lib/stores/addressStore";
|
||
import { useAuthStore } from "@/lib/stores/authStore";
|
||
import { useCartStore } from "@/lib/stores/cartStore";
|
||
import { useFamilyStore } from "@/lib/stores/familyStore";
|
||
import { useLocationStore, type PaymentMethod } from "@/lib/stores/locationStore";
|
||
import { useNotificationStore } from "@/lib/stores/notificationStore";
|
||
import { useOrdersStore } from "@/lib/stores/ordersStore";
|
||
import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
|
||
import { useProfileModeStore } from "@/lib/stores/profileModeStore";
|
||
import { colors, gutter } from "@/lib/theme";
|
||
import { formatETB, WHATSAPP_NUMBER } from "@/lib/utils";
|
||
|
||
export default function CheckoutScreen() {
|
||
const { t } = useTranslation();
|
||
const items = useCartStore((s) => s.items);
|
||
const clear = useCartStore((s) => s.clear);
|
||
const subtotal = useCartStore((s) => s.subtotal());
|
||
const cartVoucher = useCartStore((s) => s.voucherCode);
|
||
const setCartVoucher = useCartStore((s) => s.setVoucher);
|
||
const fulfillment = useLocationStore((s) => s.fulfillment);
|
||
const setFulfillment = useLocationStore((s) => s.setFulfillment);
|
||
const branchId = useLocationStore((s) => s.branchId);
|
||
const setBranchId = useLocationStore((s) => s.setBranchId);
|
||
const areaLabel = useLocationStore((s) => s.areaLabel);
|
||
const setAreaLabel = useLocationStore((s) => s.setAreaLabel);
|
||
const payment = useLocationStore((s) => s.paymentPreference);
|
||
const setPayment = useLocationStore((s) => s.setPaymentPreference);
|
||
const allowedPayments = useLocationStore((s) => s.allowedPayments);
|
||
const addresses = useAddressStore((s) => s.addresses);
|
||
const defaultAddress = useAddressStore((s) => s.defaultAddress());
|
||
const addOrder = useOrdersStore((s) => s.addOrder);
|
||
const pushNotification = useNotificationStore((s) => s.push);
|
||
const addPoints = useAuthStore((s) => s.addPoints);
|
||
const redeemPoints = useAuthStore((s) => s.redeemPoints);
|
||
const user = useAuthStore((s) => s.user);
|
||
const setActiveVoucher = useAuthStore((s) => s.setActiveVoucher);
|
||
const quoteSplit = useProfileModeStore((s) => s.quoteSplit);
|
||
const consumeAllowance = useProfileModeStore((s) => s.consumeAllowance);
|
||
const mode = useProfileModeStore((s) => s.mode);
|
||
const membership = useProfileModeStore((s) => s.activeMembership());
|
||
const familyMembers = useFamilyStore((s) => s.members);
|
||
const activeMemberId = useFamilyStore((s) => s.activeMemberId);
|
||
const setActiveMember = useFamilyStore((s) => s.setActiveMember);
|
||
const prescriptions = usePrescriptionStore((s) => s.prescriptions);
|
||
const isGuest = !!user?.isGuest;
|
||
|
||
const [name, setName] = useState(user?.name && !user.isGuest ? user.name : "");
|
||
const [phone, setPhone] = useState(user?.phone ?? "");
|
||
const [notes, setNotes] = useState("");
|
||
const [addressId, setAddressId] = useState(defaultAddress?.id ?? "");
|
||
const [voucher, setVoucher] = useState(cartVoucher || user?.activeVoucher || "");
|
||
const [forMemberId, setForMemberId] = useState<string | null>(activeMemberId);
|
||
const [anyBranch, setAnyBranch] = useState(isGuest);
|
||
const [paying, setPaying] = useState(false);
|
||
const [assistedMode, setAssistedMode] = useState(isGuest);
|
||
|
||
useEffect(() => {
|
||
if (!isGuest) return;
|
||
if (fulfillment !== "pickup") setFulfillment("pickup");
|
||
setAnyBranch(true);
|
||
setAssistedMode(true);
|
||
if (payment !== "pay_at_branch") setPayment("pay_at_branch");
|
||
}, [isGuest, fulfillment, payment, setFulfillment, setPayment]);
|
||
|
||
const selectedAddress = useMemo(
|
||
() => addresses.find((a) => a.id === addressId) ?? defaultAddress,
|
||
[addresses, addressId, defaultAddress]
|
||
);
|
||
|
||
const effectiveFulfillment = isGuest || assistedMode ? "pickup" : fulfillment;
|
||
const useAnyBranchPickup =
|
||
effectiveFulfillment === "pickup" && (anyBranch || isGuest || assistedMode);
|
||
|
||
const allowed = useMemo((): PaymentMethod[] => {
|
||
if (assistedMode || isGuest) return ["pay_at_branch"];
|
||
return allowedPayments();
|
||
}, [assistedMode, isGuest, allowedPayments, fulfillment]);
|
||
|
||
const rxItems = items.filter((i) => i.requiresPrescription);
|
||
const hasBlockingRx =
|
||
rxItems.length > 0 &&
|
||
!prescriptions.some((p) =>
|
||
["submitted", "under_review", "approved", "filled", "queried"].includes(p.status)
|
||
);
|
||
|
||
const deliveryFee =
|
||
effectiveFulfillment === "delivery" && items.length ? DELIVERY_FEE : 0;
|
||
const discount = voucherDiscount(subtotal, voucher);
|
||
const afterDiscount = Math.max(0, subtotal - discount);
|
||
const split =
|
||
mode === "corporate" && !isGuest
|
||
? quoteSplit(afterDiscount)
|
||
: { covered: 0, selfPay: afterDiscount };
|
||
const totalDue = orderSubtotalTotal({
|
||
subtotal: split.selfPay,
|
||
deliveryFee,
|
||
discount: 0,
|
||
});
|
||
|
||
const placeOrder = async (opts: { assisted: boolean }) => {
|
||
if (!items.length || paying) return;
|
||
if (!name.trim() || phone.trim().length < 9) {
|
||
Alert.alert("Contact details", "Enter your name and a valid phone number.");
|
||
return;
|
||
}
|
||
if (hasBlockingRx && !opts.assisted) {
|
||
Alert.alert(
|
||
"Prescription needed",
|
||
"Upload a prescription for Rx items before paying online."
|
||
);
|
||
return;
|
||
}
|
||
if (!opts.assisted && !allowed.includes(payment)) {
|
||
Alert.alert("Payment", "Select a valid payment method.");
|
||
return;
|
||
}
|
||
if (effectiveFulfillment === "pickup" && !useAnyBranchPickup && !branchId) {
|
||
Alert.alert("Pickup", "Select a branch, or choose any-branch quick code.");
|
||
return;
|
||
}
|
||
if (effectiveFulfillment === "delivery" && !selectedAddress && !areaLabel.trim()) {
|
||
Alert.alert("Delivery", "Choose a saved address or enter an area.");
|
||
return;
|
||
}
|
||
|
||
const branch = branches.find((b) => b.id === branchId);
|
||
const addressLine = selectedAddress
|
||
? `${selectedAddress.street}${selectedAddress.landmark ? ` · ${selectedAddress.landmark}` : ""}`
|
||
: undefined;
|
||
const forMember = familyMembers.find((m) => m.id === forMemberId);
|
||
const assisted = opts.assisted || isGuest;
|
||
const payMethod: PaymentMethod = assisted ? "pay_at_branch" : payment;
|
||
|
||
const orderNotes = [
|
||
notes.trim(),
|
||
forMember ? `For family: ${forMember.name} (${forMember.relationship})` : "",
|
||
assisted
|
||
? "Pharmacist assisted order code — enter in admin to fulfill"
|
||
: useAnyBranchPickup
|
||
? "Quick code — redeemable at any Gishen branch"
|
||
: "",
|
||
]
|
||
.filter(Boolean)
|
||
.join(" · ");
|
||
|
||
const pickupCode =
|
||
assisted || effectiveFulfillment === "pickup" ? generatePickupCode() : null;
|
||
const fee = effectiveFulfillment === "pickup" ? 0 : deliveryFee;
|
||
|
||
setPaying(true);
|
||
try {
|
||
if (!assisted && payMethod !== "pay_at_branch" && payMethod !== "cod") {
|
||
const intent = await initiatePayment({
|
||
provider: payMethod,
|
||
amountEtb: afterDiscount + fee,
|
||
orderId: `pending_${Date.now()}`,
|
||
});
|
||
if (intent.status === "requires_action" && intent.checkoutUrl) {
|
||
await Linking.openURL(intent.checkoutUrl).catch(() => undefined);
|
||
}
|
||
}
|
||
|
||
const order = addOrder({
|
||
items,
|
||
subtotal,
|
||
deliveryFee: fee,
|
||
discount,
|
||
voucherCode: discount ? voucher.trim().toUpperCase() : null,
|
||
total: afterDiscount + fee,
|
||
fulfillment: effectiveFulfillment,
|
||
branchId: useAnyBranchPickup ? null : branchId,
|
||
areaLabel: useAnyBranchPickup
|
||
? "Any Gishen branch"
|
||
: effectiveFulfillment === "pickup"
|
||
? branch?.name ?? areaLabel
|
||
: selectedAddress?.area ?? areaLabel,
|
||
addressId:
|
||
effectiveFulfillment === "delivery" ? selectedAddress?.id ?? null : null,
|
||
addressLine: useAnyBranchPickup ? undefined : addressLine,
|
||
paymentMethod: payMethod,
|
||
corporateCovered: split.covered,
|
||
selfPay: split.selfPay + fee,
|
||
customerName: name.trim(),
|
||
customerPhone: phone.trim(),
|
||
notes: orderNotes,
|
||
riderAssigned: false,
|
||
pickupCode,
|
||
anyBranch: useAnyBranchPickup || assisted,
|
||
isGuestOrder: assisted,
|
||
status: assisted
|
||
? "requested"
|
||
: payMethod === "pay_at_branch" || payMethod === "cod" || payMethod === "bank"
|
||
? "confirmed"
|
||
: "confirmed",
|
||
});
|
||
|
||
if (forMemberId) setActiveMember(forMemberId);
|
||
if (!assisted && split.covered > 0) consumeAllowance(split.covered);
|
||
if (!assisted && !isGuest) {
|
||
addPoints(Math.max(1, Math.floor(afterDiscount / 10)), "Order reward");
|
||
}
|
||
if (discount) {
|
||
setActiveVoucher(null);
|
||
setCartVoucher(null);
|
||
}
|
||
clear();
|
||
|
||
pushNotification({
|
||
kind: "order",
|
||
title: assisted
|
||
? `Pharmacist code ${pickupCode}`
|
||
: pickupCode
|
||
? `Pickup code ${pickupCode}`
|
||
: "Order placed",
|
||
body: assisted
|
||
? `Share ${pickupCode} so a pharmacist can create your order in admin.`
|
||
: pickupCode
|
||
? useAnyBranchPickup
|
||
? `Show ${pickupCode} at any Gishen branch counter.`
|
||
: `Show ${pickupCode} at ${branch?.name ?? "your branch"}.`
|
||
: `Your ${order.fulfillment} order is confirmed.`,
|
||
href: assisted && pickupCode ? routes.orderCode(order.id) : routes.orderDetail(order.id),
|
||
});
|
||
|
||
if (assisted && pickupCode) {
|
||
router.replace(routes.orderCode(order.id) as never);
|
||
return;
|
||
}
|
||
router.replace(routes.checkoutSuccess(order.id) as never);
|
||
} catch (e) {
|
||
Alert.alert("Payment failed", e instanceof Error ? e.message : "Try again.");
|
||
} finally {
|
||
setPaying(false);
|
||
}
|
||
};
|
||
|
||
const whatsapp = () => {
|
||
const lines = items
|
||
.map((i) => `• ${i.name} x${i.quantity} — ${i.price * i.quantity} ETB`)
|
||
.join("%0A");
|
||
const msg = `Gishen order%0AName: ${name}%0APhone: ${phone}%0A${lines}%0ATotal: ${totalDue} ETB%0A${fulfillment}%0A${notes}`;
|
||
Linking.openURL(`https://wa.me/${WHATSAPP_NUMBER}?text=${msg}`);
|
||
};
|
||
|
||
if (!items.length) {
|
||
return (
|
||
<Screen>
|
||
<AppHeader title={t("common.checkout")} />
|
||
<View style={{ padding: gutter }}>
|
||
<Text variant="body" color={colors.muted}>
|
||
Your cart is empty. Add products before checking out.
|
||
</Text>
|
||
<Button
|
||
title="Browse shop"
|
||
style={{ marginTop: 16 }}
|
||
onPress={() => router.replace(routes.shop)}
|
||
/>
|
||
</View>
|
||
</Screen>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<Screen>
|
||
<AppHeader title={t("common.checkout")} subtitle="Confirm delivery and payment" />
|
||
<ScrollView
|
||
contentContainerStyle={{
|
||
paddingHorizontal: gutter,
|
||
paddingBottom: 160,
|
||
gap: 14,
|
||
}}
|
||
>
|
||
<RxCartGate rxItemNames={rxItems.map((i) => i.name)} />
|
||
|
||
<Card elevated={false}>
|
||
<Text variant="h3" style={{ marginBottom: 10 }}>
|
||
Contact
|
||
</Text>
|
||
{familyMembers.length ? (
|
||
<View style={{ marginBottom: 12 }}>
|
||
<Text variant="label" color={colors.muted} style={{ marginBottom: 8 }}>
|
||
Ordering for
|
||
</Text>
|
||
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8 }}>
|
||
<Chip
|
||
label="Myself"
|
||
selected={!forMemberId}
|
||
onPress={() => setForMemberId(null)}
|
||
size="sm"
|
||
/>
|
||
{familyMembers.map((m) => (
|
||
<Chip
|
||
key={m.id}
|
||
label={m.name}
|
||
selected={forMemberId === m.id}
|
||
onPress={() => setForMemberId(m.id)}
|
||
size="sm"
|
||
/>
|
||
))}
|
||
</View>
|
||
</View>
|
||
) : null}
|
||
<View style={{ gap: 12 }}>
|
||
<Field label="Full name" value={name} onChangeText={setName} icon="person-outline" />
|
||
<Field
|
||
label="Phone"
|
||
value={phone}
|
||
onChangeText={setPhone}
|
||
keyboardType="phone-pad"
|
||
icon="call-outline"
|
||
/>
|
||
<Field
|
||
label="Order notes"
|
||
value={notes}
|
||
onChangeText={setNotes}
|
||
icon="create-outline"
|
||
placeholder="Gate code, call on arrival…"
|
||
/>
|
||
</View>
|
||
</Card>
|
||
|
||
<Card elevated={false}>
|
||
<Text variant="h3" style={{ marginBottom: 10 }}>
|
||
Fulfillment
|
||
</Text>
|
||
{isGuest || assistedMode ? (
|
||
<AssistedOrderExplainer
|
||
title={isGuest ? "Pharmacist order code" : "Assisted order code"}
|
||
body={
|
||
isGuest
|
||
? "You’ll get a GSH-XXXX code. A pharmacist enters it in admin to create your order — pay at the branch."
|
||
: "Freeze this basket as a GSH-XXXX code for a pharmacist to place offline / at the counter."
|
||
}
|
||
/>
|
||
) : null}
|
||
{!isGuest ? (
|
||
<View style={{ marginBottom: 12 }}>
|
||
<Chip
|
||
label={assistedMode ? "Assisted code mode on" : "Get pharmacist code instead"}
|
||
selected={assistedMode}
|
||
onPress={() => {
|
||
const next = !assistedMode;
|
||
setAssistedMode(next);
|
||
if (next) {
|
||
setFulfillment("pickup");
|
||
setAnyBranch(true);
|
||
setPayment("pay_at_branch");
|
||
}
|
||
}}
|
||
/>
|
||
</View>
|
||
) : null}
|
||
<Segmented
|
||
value={effectiveFulfillment}
|
||
onChange={(v) => {
|
||
if ((isGuest || assistedMode) && v === "delivery") {
|
||
Alert.alert(
|
||
"Assisted checkout",
|
||
"Pharmacist codes are pickup-only. Turn off assisted mode for delivery."
|
||
);
|
||
return;
|
||
}
|
||
setFulfillment(v);
|
||
if (v === "delivery") setAnyBranch(false);
|
||
}}
|
||
options={[
|
||
{ value: "delivery", label: t("common.delivery") },
|
||
{ value: "pickup", label: t("common.pickup") },
|
||
]}
|
||
/>
|
||
|
||
{effectiveFulfillment === "delivery" ? (
|
||
<View style={{ marginTop: 14, gap: 8 }}>
|
||
<View style={{ flexDirection: "row", justifyContent: "space-between" }}>
|
||
<Text variant="label" color={colors.muted}>
|
||
Saved addresses
|
||
</Text>
|
||
<Pressable onPress={() => router.push(routes.addresses)}>
|
||
<Text variant="label" color={colors.brandText}>
|
||
Manage
|
||
</Text>
|
||
</Pressable>
|
||
</View>
|
||
{addresses.map((a) => (
|
||
<Pressable
|
||
key={a.id}
|
||
onPress={() => {
|
||
setAddressId(a.id);
|
||
setAreaLabel(a.area);
|
||
}}
|
||
style={{
|
||
padding: 12,
|
||
borderRadius: 14,
|
||
borderWidth: 1.5,
|
||
borderColor: addressId === a.id ? colors.brand : colors.line,
|
||
backgroundColor: addressId === a.id ? colors.brandWash : colors.surface,
|
||
}}
|
||
>
|
||
<Text variant="h3">
|
||
{a.label}
|
||
{a.isDefault ? " · Default" : ""}
|
||
</Text>
|
||
<Text variant="caption" color={colors.subtle} style={{ marginTop: 4 }}>
|
||
{a.street}
|
||
</Text>
|
||
<Text variant="caption" color={colors.subtle}>
|
||
{a.area}
|
||
</Text>
|
||
</Pressable>
|
||
))}
|
||
<Field
|
||
label="Or type area"
|
||
value={areaLabel}
|
||
onChangeText={setAreaLabel}
|
||
icon="location-outline"
|
||
/>
|
||
</View>
|
||
) : (
|
||
<View style={{ marginTop: 14, gap: 8 }}>
|
||
<Pressable
|
||
onPress={() => {
|
||
setAnyBranch(true);
|
||
setBranchId(null);
|
||
setPayment("pay_at_branch");
|
||
}}
|
||
style={{
|
||
padding: 12,
|
||
borderRadius: 14,
|
||
borderWidth: 1.5,
|
||
borderColor: anyBranch ? colors.brand : colors.line,
|
||
backgroundColor: anyBranch ? colors.brandWash : colors.surface,
|
||
}}
|
||
>
|
||
<Text variant="h3">Any branch · quick code</Text>
|
||
<Text variant="caption" color={colors.subtle} style={{ marginTop: 4 }}>
|
||
Collect at Bole, CMC, Jemo, or any other branch
|
||
</Text>
|
||
</Pressable>
|
||
{branches.map((b) => (
|
||
<Pressable
|
||
key={b.id}
|
||
onPress={() => {
|
||
setAnyBranch(false);
|
||
setBranchId(b.id);
|
||
}}
|
||
style={{
|
||
padding: 12,
|
||
borderRadius: 14,
|
||
borderWidth: 1.5,
|
||
borderColor:
|
||
!anyBranch && branchId === b.id ? colors.brand : colors.line,
|
||
backgroundColor:
|
||
!anyBranch && branchId === b.id
|
||
? colors.brandWash
|
||
: colors.surface,
|
||
}}
|
||
>
|
||
<Text variant="h3">{b.name}</Text>
|
||
<Text variant="caption" color={colors.subtle} style={{ marginTop: 2 }}>
|
||
{b.area} · {b.hours}
|
||
</Text>
|
||
</Pressable>
|
||
))}
|
||
</View>
|
||
)}
|
||
</Card>
|
||
|
||
{!assistedMode && !isGuest ? (
|
||
<PaymentMethodList
|
||
methods={allowed}
|
||
selected={payment}
|
||
onSelect={setPayment}
|
||
title={t("common.payment")}
|
||
footnote={
|
||
effectiveFulfillment === "delivery"
|
||
? "Pay at branch is only available for pickup"
|
||
: undefined
|
||
}
|
||
/>
|
||
) : null}
|
||
|
||
{!isGuest ? (
|
||
<LoyaltyRedeemRow
|
||
points={user?.points ?? 0}
|
||
activeVoucher={user?.activeVoucher}
|
||
voucher={voucher}
|
||
discount={discount}
|
||
onChangeVoucher={setVoucher}
|
||
onApplyDemo={() => setVoucher("GISHEN10")}
|
||
onApplyLoyalty={() => user?.activeVoucher && setVoucher(user.activeVoucher!)}
|
||
canRedeem={(user?.points ?? 0) >= 100 && !user?.isGuest}
|
||
onRedeemPoints={() => {
|
||
if (redeemPoints(100)) {
|
||
setVoucher("GISHEN10");
|
||
setCartVoucher("GISHEN10");
|
||
Alert.alert("Redeemed", "GISHEN10 applied to this checkout.");
|
||
} else {
|
||
Alert.alert("Not enough points", "You need at least 100 points.");
|
||
}
|
||
}}
|
||
/>
|
||
) : null}
|
||
|
||
{mode === "corporate" && membership && !isGuest && !assistedMode ? (
|
||
<EntitlementSplitCard
|
||
orgName={membership.orgName}
|
||
planName={membership.planName}
|
||
remainingAllowance={membership.remainingAllowance}
|
||
covered={split.covered}
|
||
selfPay={split.selfPay + deliveryFee}
|
||
/>
|
||
) : null}
|
||
|
||
<Card elevated={false}>
|
||
<InfoRow label="Items" value={`${items.length}`} />
|
||
<InfoRow label="Subtotal" value={formatETB(subtotal)} />
|
||
{discount > 0 ? (
|
||
<InfoRow
|
||
label="Discount"
|
||
value={`- ${formatETB(discount)}`}
|
||
valueColor={colors.brandText}
|
||
/>
|
||
) : null}
|
||
<InfoRow
|
||
label={effectiveFulfillment === "delivery" ? "Delivery" : "Pickup"}
|
||
value={deliveryFee ? formatETB(deliveryFee) : "Free"}
|
||
/>
|
||
<InfoRow
|
||
label={t("common.total")}
|
||
value={formatETB(afterDiscount + deliveryFee)}
|
||
emphasis
|
||
last
|
||
/>
|
||
</Card>
|
||
|
||
<Button title="Order via WhatsApp" variant="outline" icon="logo-whatsapp" onPress={whatsapp} />
|
||
</ScrollView>
|
||
|
||
<StickyBar>
|
||
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
||
<View style={{ flex: 1 }}>
|
||
<Text variant="caption" color={colors.subtle}>
|
||
{assistedMode || isGuest ? "Assisted total" : "Total due"}
|
||
</Text>
|
||
<Text variant="priceLg">{formatETB(afterDiscount + deliveryFee)}</Text>
|
||
{!assistedMode && !isGuest ? (
|
||
<Text variant="micro" color={colors.subtle}>
|
||
{paymentLabel(payment)}
|
||
</Text>
|
||
) : null}
|
||
</View>
|
||
<Button
|
||
title={
|
||
paying
|
||
? "Processing…"
|
||
: isGuest || assistedMode
|
||
? "Get pharmacist code"
|
||
: t("common.payNow")
|
||
}
|
||
fullWidth={false}
|
||
style={{ minWidth: 148 }}
|
||
loading={paying}
|
||
disabled={paying || (hasBlockingRx && !assistedMode && !isGuest)}
|
||
onPress={() => placeOrder({ assisted: isGuest || assistedMode })}
|
||
/>
|
||
</View>
|
||
</StickyBar>
|
||
</Screen>
|
||
);
|
||
}
|