263 lines
8.7 KiB
TypeScript
263 lines
8.7 KiB
TypeScript
import React, { useMemo, useState } from "react";
|
|
import { View, Text, TouchableOpacity, ScrollView } from "react-native";
|
|
import { useLocalSearchParams, router } from "expo-router";
|
|
import { useRecipientsStore } from "~/lib/stores";
|
|
import ScreenWrapper from "~/components/ui/ScreenWrapper";
|
|
import BackButton from "~/components/ui/backButton";
|
|
import { Button } from "~/components/ui/button";
|
|
import { ROUTES } from "~/lib/routes";
|
|
import {
|
|
LucideUser,
|
|
LucideCreditCard,
|
|
LucideCalendarClock,
|
|
LucideChevronRight,
|
|
} from "lucide-react-native";
|
|
|
|
function getInitials(name: string) {
|
|
return name
|
|
.split(" ")
|
|
.map((word) => word.charAt(0).toUpperCase())
|
|
.slice(0, 2)
|
|
.join("");
|
|
}
|
|
|
|
export default function RecipDetail() {
|
|
const { recipientId } = useLocalSearchParams<{ recipientId?: string }>();
|
|
const { recipients } = useRecipientsStore();
|
|
|
|
const recipient = useMemo(
|
|
() => recipients.find((r) => r.id === recipientId),
|
|
[recipients, recipientId]
|
|
);
|
|
|
|
const initials = recipient ? getInitials(recipient.fullName) : "?";
|
|
const lowerName = recipient?.fullName.toLowerCase() ?? "";
|
|
const isBusiness =
|
|
lowerName.includes("ltd") ||
|
|
lowerName.includes("plc") ||
|
|
lowerName.includes("inc") ||
|
|
lowerName.includes("company");
|
|
const clientType = isBusiness ? "Business" : "Individual";
|
|
|
|
// Dummy accounts for UI-only
|
|
const accounts = useMemo(
|
|
() => [
|
|
{
|
|
id: "acc-1",
|
|
bank: "Bank of Abyssinia",
|
|
number: "***1234",
|
|
primary: true,
|
|
},
|
|
{
|
|
id: "acc-2",
|
|
bank: "Dashen Bank",
|
|
number: "***5678",
|
|
primary: false,
|
|
},
|
|
],
|
|
[]
|
|
);
|
|
|
|
// Dummy schedules for UI-only
|
|
const schedules = useMemo(
|
|
() => [
|
|
{ id: "sch-1", label: "Every Monday · 10:00" },
|
|
{ id: "sch-2", label: "Monthly, 1st · 09:00" },
|
|
],
|
|
[]
|
|
);
|
|
|
|
const [showManageSchedules, setShowManageSchedules] = useState(false);
|
|
|
|
const handlePayNow = () => {
|
|
if (!recipient) return;
|
|
router.push({
|
|
pathname: ROUTES.SEND_OR_REQUEST_MONEY,
|
|
params: { recipientId: recipient.id, recipientName: recipient.fullName },
|
|
});
|
|
};
|
|
|
|
const handleViewTransactions = () => {
|
|
if (!recipient) return;
|
|
router.push({
|
|
pathname: ROUTES.HISTORY,
|
|
params: { recipientId: recipient.id, recipientName: recipient.fullName },
|
|
});
|
|
};
|
|
|
|
if (!recipient) {
|
|
return (
|
|
<ScreenWrapper edges={[]}>
|
|
<View className="flex-1 items-center justify-center px-6">
|
|
<Text className="text-lg font-dmsans text-gray-500 text-center">
|
|
Recipient not found.
|
|
</Text>
|
|
<Button className="mt-4" onPress={() => router.back()}>
|
|
<Text className="text-white font-dmsans">Go back</Text>
|
|
</Button>
|
|
</View>
|
|
</ScreenWrapper>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<ScreenWrapper edges={[]}>
|
|
<View className="flex-1 w-full">
|
|
<ScrollView
|
|
className="flex-1 w-full"
|
|
contentContainerStyle={{ paddingBottom: 32 }}
|
|
>
|
|
<View className="">
|
|
<BackButton />
|
|
</View>
|
|
|
|
{/* Header */}
|
|
<View className="px-5 pt-6 flex flex-row items-center">
|
|
<View className="w-14 h-14 rounded-full bg-primary items-center justify-center mr-3">
|
|
<Text className="text-white font-dmsans-bold text-xl">
|
|
{initials}
|
|
</Text>
|
|
</View>
|
|
<View className="flex-1">
|
|
<Text
|
|
className="text-lg font-dmsans-bold text-primary"
|
|
numberOfLines={1}
|
|
>
|
|
{recipient.fullName}
|
|
</Text>
|
|
<View className="mt-1 flex-row items-center">
|
|
<View className="px-2 py-[2px] rounded-md bg-[#FFB668] mr-2">
|
|
<Text className="text-[11px] font-dmsans-medium text-white">
|
|
{clientType}
|
|
</Text>
|
|
</View>
|
|
<Text
|
|
className="text-xs font-dmsans text-gray-500"
|
|
numberOfLines={1}
|
|
>
|
|
{recipient.phoneNumber}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Accounts Section */}
|
|
<View className="px-5 pt-8">
|
|
<Text className="text-base font-dmsans-bold text-primary mb-3">
|
|
Linked Accounts
|
|
</Text>
|
|
{accounts.map((acc) => (
|
|
<View
|
|
key={acc.id}
|
|
className="flex-row items-center justify-between bg-white rounded-md px-4 py-3 mb-2 border border-[#E5E7EB]"
|
|
>
|
|
<View className="flex-row items-center">
|
|
<View className="w-8 h-8 rounded-full bg-emerald-50 items-center justify-center mr-3">
|
|
<LucideCreditCard color="#10B981" size={16} />
|
|
</View>
|
|
<View>
|
|
<Text className="text-sm font-dmsans-medium text-gray-900">
|
|
{acc.bank}
|
|
</Text>
|
|
<Text className="text-xs font-dmsans text-gray-500 mt-[2px]">
|
|
{acc.number}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
{acc.primary && (
|
|
<Text className="text-[11px] font-dmsans-medium text-emerald-600">
|
|
Primary
|
|
</Text>
|
|
)}
|
|
</View>
|
|
))}
|
|
|
|
<TouchableOpacity
|
|
className="mt-3 flex-row items-center justify-center py-3 rounded-md border border-dashed border-primary"
|
|
onPress={() => {}}
|
|
>
|
|
<Text className="text-sm font-dmsans-medium text-primary">
|
|
Add Account
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Schedules Section */}
|
|
<View className="px-5 pt-8">
|
|
<Text className="text-base font-dmsans-bold text-primary mb-3">
|
|
Payment Schedules
|
|
</Text>
|
|
{schedules.map((sch) => (
|
|
<View
|
|
key={sch.id}
|
|
className="flex-row items-center justify-between bg-white rounded-md px-4 py-3 mb-2 border border-[#E5E7EB]"
|
|
>
|
|
<View className="flex-row items-center">
|
|
<View className="w-8 h-8 rounded-full bg-amber-50 items-center justify-center mr-3">
|
|
<LucideCalendarClock color="#F59E0B" size={16} />
|
|
</View>
|
|
<Text className="text-sm font-dmsans-medium text-gray-900">
|
|
{sch.label}
|
|
</Text>
|
|
</View>
|
|
<LucideChevronRight color="#9CA3AF" size={16} />
|
|
</View>
|
|
))}
|
|
|
|
<TouchableOpacity
|
|
className="mt-3 flex-row items-center justify-center py-3 rounded-md border border-primary bg-primary/5"
|
|
onPress={() => setShowManageSchedules(true)}
|
|
>
|
|
<Text className="text-sm font-dmsans-medium text-primary">
|
|
Manage Schedules
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</ScrollView>
|
|
|
|
{/* Actions */}
|
|
<View className="px-5 pb-7 flex-row gap-3">
|
|
<Button
|
|
className="flex-1 bg-primary rounded-3xl"
|
|
onPress={handlePayNow}
|
|
>
|
|
<Text className="text-white font-dmsans-medium text-base">
|
|
Pay Now
|
|
</Text>
|
|
</Button>
|
|
<Button
|
|
className="flex-1 bg-white border border-[#E5E7EB] rounded-3xl"
|
|
onPress={handleViewTransactions}
|
|
>
|
|
<Text className="text-primary font-dmsans-medium text-base">
|
|
View Transactions
|
|
</Text>
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Simple placeholder bottom sheet for Manage Schedules */}
|
|
{showManageSchedules && (
|
|
<View className="absolute inset-x-0 bottom-0 bg-white rounded-t-3xl px-5 pt-4 pb-6 border-t border-[#E5E7EB]">
|
|
<View className="items-center mb-3">
|
|
<View className="w-10 h-1.5 rounded-full bg-gray-300" />
|
|
</View>
|
|
<Text className="text-base font-dmsans-bold text-primary mb-3">
|
|
Manage Schedules (UI only)
|
|
</Text>
|
|
<Text className="text-xs font-dmsans text-gray-500 mb-4">
|
|
This is a placeholder UI. Editing schedules will be wired to backend
|
|
in a later phase.
|
|
</Text>
|
|
<Button
|
|
className="bg-primary rounded-2xl"
|
|
onPress={() => setShowManageSchedules(false)}
|
|
>
|
|
<Text className="text-white font-dmsans-medium">Close</Text>
|
|
</Button>
|
|
</View>
|
|
)}
|
|
</ScreenWrapper>
|
|
);
|
|
}
|