Yaltopia-Tickets-App/app/verify-payment.tsx
2026-06-05 13:39:37 +03:00

252 lines
8.1 KiB
TypeScript

import React, { useState } from "react";
import {
View,
TextInput,
ActivityIndicator,
KeyboardAvoidingView,
Platform,
Pressable,
useColorScheme,
} from "react-native";
import { useSirouRouter } from "@sirou/react-native";
import { AppRoutes } from "@/lib/routes";
import { Text } from "@/components/ui/text";
import { Button } from "@/components/ui/button";
import { ScreenWrapper } from "@/components/ScreenWrapper";
import { StandardHeader } from "@/components/StandardHeader";
import { useAuthStore } from "@/lib/auth-store";
import { api } from "@/lib/api";
import { toast } from "@/lib/toast-store";
import { getPlaceholderColor } from "@/lib/colors";
import { Search, ChevronDown } from "@/lib/icons";
import { PickerModal, SelectOption } from "@/components/PickerModal";
const providers = [
{ label: "Telebirr", value: "telebirr", needsAccount: false },
{ label: "Dashen", value: "dashen", needsAccount: false },
{ label: "CBE", value: "cbe", needsAccount: true },
{ label: "Abyssinia", value: "abyssinia", needsAccount: true },
{ label: "Other", value: "other", needsAccount: false },
];
function getSuffix(provider: string, accountNumber: string): string {
const clean = accountNumber.replace(/\s+/g, "");
switch (provider) {
case "cbe":
return clean.slice(-8);
case "abyssinia":
return clean.slice(-5);
default:
return "";
}
}
export default function VerifyPaymentScreen() {
const nav = useSirouRouter<AppRoutes>();
const user = useAuthStore((s) => s.user);
const colorScheme = useColorScheme();
const isDark = colorScheme === "dark";
const [reference, setReference] = useState("");
const [accountNumber, setAccountNumber] = useState("");
const [provider, setProvider] = useState("telebirr");
const [loading, setLoading] = useState(false);
const [showProvider, setShowProvider] = useState(false);
const selectedProvider = providers.find((p) => p.value === provider);
const needsAccount = selectedProvider?.needsAccount ?? false;
const handleVerify = async () => {
const trimmed = reference.trim();
if (!trimmed) {
toast.error("Required", "Please enter the transaction reference number");
return;
}
if (needsAccount && !accountNumber.trim()) {
toast.error("Required", "Please enter the account number");
return;
}
setLoading(true);
try {
const response = await api.scan.verifyPaymentReference({
body: {
reference: trimmed,
phoneNumber: user?.phone || "",
suffix: getSuffix(provider, accountNumber),
},
});
if (!response.success) {
toast.error(
"Verification Failed",
response.message || "Could not verify payment",
);
return;
}
const refVerification = response.verifierApi?.referenceVerification;
if (!refVerification) {
toast.error(
"No Data",
response.message || "No verification data returned",
);
return;
}
if (refVerification.ok && refVerification.data?.data) {
nav.go("verify-payment-result", {
data: JSON.stringify(refVerification.data.data),
});
setReference("");
setAccountNumber("");
} else {
const msg =
refVerification.skippedReason ||
refVerification.data?.error ||
"No data available";
toast.warning("Verification Skipped", msg);
}
} catch (err: any) {
toast.error(
"Verification Failed",
err.message || "Could not verify payment reference",
);
} finally {
setLoading(false);
}
};
return (
<ScreenWrapper className="bg-background">
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className="flex-1"
>
<StandardHeader title="Verify Payment" showBack />
<View className="flex-1 px-[16px] pt-8">
<View className="items-center mb-8">
<Text
variant="h3"
className="text-foreground font-sans-bold text-center"
>
Verify Payment Reference
</Text>
<Text variant="muted" className="mt-2 text-center">
Enter the transaction / FT number to verify the payment
</Text>
</View>
<View className="gap-5">
<View className="gap-2">
<Text variant="small" className="font-sans-semibold ml-1">
Provider
</Text>
<Pressable
onPress={() => setShowProvider(true)}
className="flex-row items-center rounded-[6px] px-4 border border-border h-10 bg-card"
>
<Text className="flex-1 text-foreground text-sm font-sans-medium capitalize">
{provider}
</Text>
<ChevronDown
size={16}
color={isDark ? "#94a3b8" : "#64748b"}
strokeWidth={2.5}
/>
</Pressable>
</View>
<View className="gap-2">
<Text variant="small" className="font-sans-semibold ml-1">
Transaction Reference
</Text>
<View className="flex-row items-center rounded-[6px] px-4 border border-border h-10">
<Search size={18} color={isDark ? "#94a3b8" : "#64748b"} />
<TextInput
className="flex-1 ml-3 text-foreground py-0 text-sm"
placeholder="e.g. DECSETAA017743744407991639"
placeholderTextColor={getPlaceholderColor(isDark)}
value={reference}
onChangeText={setReference}
autoCapitalize="characters"
autoCorrect={false}
/>
</View>
</View>
{needsAccount && (
<View className="gap-2">
<Text variant="small" className="font-sans-semibold ml-1">
Account Number
</Text>
<View className="flex-row items-center rounded-[6px] px-4 border border-border h-10">
<TextInput
className="flex-1 text-foreground py-0 text-sm"
placeholder={
provider === "cbe"
? "Last 8 digits of account"
: "Last 5 digits of account"
}
placeholderTextColor={getPlaceholderColor(isDark)}
value={accountNumber}
onChangeText={setAccountNumber}
keyboardType="numeric"
maxLength={provider === "cbe" ? 8 : 5}
/>
</View>
</View>
)}
</View>
<Button
className="h-12 bg-primary rounded-[10px] shadow-lg shadow-primary/30 mt-8"
onPress={handleVerify}
disabled={loading}
>
{loading ? (
<ActivityIndicator color="white" />
) : (
<Text className="text-white font-sans-bold text-base">
Verify Payment
</Text>
)}
</Button>
{/* {needsAccount && accountNumber.length > 0 && (
<View className="mt-4 items-center">
<Text variant="muted" className="text-xs">
Suffix:{" "}
<Text className="text-primary font-sans-bold">
{getSuffix(provider, accountNumber)}
</Text>
</Text>
</View>
)} */}
</View>
</KeyboardAvoidingView>
<PickerModal
visible={showProvider}
onClose={() => setShowProvider(false)}
title="Select Provider"
>
{providers.map((p) => (
<SelectOption
key={p.value}
label={p.label}
value={p.value}
selected={provider === p.value}
onSelect={(v) => {
setProvider(v);
setAccountNumber("");
setShowProvider(false);
}}
/>
))}
</PickerModal>
</ScreenWrapper>
);
}