Amba-Agent-App/app/(root)/(screens)/donation.tsx
2026-01-16 00:22:35 +03:00

323 lines
12 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 React, { useState } from "react";
import { View, ScrollView, Image, TouchableOpacity } from "react-native";
import { router, useLocalSearchParams } from "expo-router";
import ScreenWrapper from "~/components/ui/ScreenWrapper";
import BackButton from "~/components/ui/backButton";
import { Text } from "~/components/ui/text";
import { Button } from "~/components/ui/button";
import { ROUTES } from "~/lib/routes";
import { Icons } from "~/assets/icons";
import { Check } from "lucide-react-native";
import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile";
import { useTranslation } from "react-i18next";
const campaigns = [
{
id: "1",
title: "Fresh Fruits for Improving Childrens Health",
image: Icons.profileImage,
progress: 0.8,
raised: "$54,090",
timeLeft: "8 Hours left",
},
{
id: "2",
title: "Support Local Farmers Market Initiative",
image: Icons.mainBG,
progress: 0.45,
raised: "$21,400",
timeLeft: "2 Days left",
},
{
id: "3",
title: "School Meal Program for Kids",
image: Icons.qrImage,
progress: 0.62,
raised: "$33,250",
timeLeft: "1 Day left",
},
];
export default function DonationScreen() {
const { t } = useTranslation();
const params = useLocalSearchParams<Record<string, string>>();
const { profile } = useAuthWithProfile();
const amountInCents = Number(params.amount ?? "0");
const baseAmount = isNaN(amountInCents)
? "0.00"
: (amountInCents / 100).toFixed(2);
const [donationType, setDonationType] = useState<"one-time" | "monthly">(
"monthly"
);
const [donationAmount, setDonationAmount] = useState(baseAmount);
const [donateAnonymously, setDonateAnonymously] = useState(false);
const [selectedCampaignId, setSelectedCampaignId] = useState<string | null>(
null
);
const isCampaignSelected = !!selectedCampaignId;
const displayName = donateAnonymously
? t("donation.anonymousLabel")
: profile?.fullName || t("donation.displayNameFallback");
const goToConfirm = (options?: { skipped?: boolean }) => {
const selectedCampaign = campaigns.find((c) => c.id === selectedCampaignId);
router.push({
pathname: ROUTES.TRANSACTION_CONFIRM,
params: {
...params,
donationSkipped: options?.skipped ? "true" : "false",
donationType,
donationAmount,
donateAnonymously: donateAnonymously ? "true" : "false",
donationCampaignId: selectedCampaign?.id ?? "",
donationCampaignTitle: selectedCampaign?.title ?? "",
fromSelectRecipientFlow: "true",
},
});
};
const handleSkip = () => {
goToConfirm({ skipped: true });
};
const handleDonate = () => {
goToConfirm({ skipped: false });
};
return (
<ScreenWrapper edges={[]}>
<BackButton />
<ScrollView
className="flex-1 bg-white"
showsVerticalScrollIndicator={false}
>
<View className="pt-4 pb-8">
<View className="px-5">
<Text className="text-3xl font-dmsans-bold text-gray-900 mb-2">
{t("donation.title")}
</Text>
<Text className="text-base font-dmsans text-gray-500 mb-6">
{t("donation.subtitle")}
</Text>
</View>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
snapToAlignment="center"
decelerationRate="fast"
className="px-5 pr-5 py-5"
contentContainerStyle={{ paddingRight: 20 }}
>
{campaigns.map((campaign) => {
const isSelected = selectedCampaignId === campaign.id;
return (
<TouchableOpacity
key={campaign.id}
activeOpacity={0.9}
onPress={() => setSelectedCampaignId(campaign.id)}
>
<View
className="mr-4 bg-white rounded-2xl"
style={{
width: 320,
height: 280,
shadowColor: "#000",
shadowOpacity: 0.08,
shadowRadius: 20,
shadowOffset: { width: 0, height: 6 },
elevation: 4,
borderWidth: isSelected ? 2 : 0,
borderColor: isSelected
? "rgba(19,83,53,0.5)"
: "transparent",
}}
>
<Image
source={campaign.image}
resizeMode="cover"
style={{ width: "100%", height: 150 }}
/>
{/* Content */}
<View className="p-4 flex-1 justify-between">
<Text
numberOfLines={1}
ellipsizeMode="tail"
className="text-base font-dmsans-medium text-gray-900 mb-3"
>
{campaign.title}
</Text>
{/* Progress bar */}
<View className="w-full h-1.5 rounded-full bg-gray-200 mb-2 overflow-hidden">
<View
style={{ width: `${campaign.progress * 100}%` }}
className="h-full bg-primary"
/>
</View>
<View className="flex-row justify-between items-center mb-2">
<Text className="text-xs font-dmsans text-gray-500">
{t("donation.donationRaisedLabel")}
</Text>
<Text className="text-xs font-dmsans text-gray-500">
{Math.round(campaign.progress * 100)}%
</Text>
</View>
<View className="flex-row justify-between items-center mt-2">
<Text className="text-lg font-dmsans-bold text-gray-900">
{campaign.raised}
</Text>
<Text className="text-xs font-dmsans text-gray-500">
{campaign.timeLeft}
</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
})}
</ScrollView>
<View
className="px-5 mt-6"
style={{ opacity: isCampaignSelected ? 1 : 0.4 }}
pointerEvents={isCampaignSelected ? "auto" : "none"}
>
<View className="bg-gray-100 rounded-xl p-4">
<Text className="text-lg font-dmsans-bold text-gray-900 mb-4 text-center">
{t("donation.chooseAmountTitle")}
</Text>
{/* One-Time / Monthly toggle */}
<View className="flex-row bg-white rounded-full p-1 mb-4">
<TouchableOpacity
className={`flex-1 rounded-full py-2 items-center justify-center ${
donationType === "one-time" ? "bg-primary" : ""
}`}
activeOpacity={0.8}
onPress={() => setDonationType("one-time")}
>
<Text
className={`text-sm font-dmsans-medium ${
donationType === "one-time"
? "text-white"
: "text-gray-600"
}`}
>
{t("donation.donationTypeOneTime")}
</Text>
</TouchableOpacity>
<TouchableOpacity
className={`flex-1 rounded-full py-2 items-center justify-center flex-row gap-1 ${
donationType === "monthly" ? "bg-primary" : ""
}`}
activeOpacity={0.8}
onPress={() => setDonationType("monthly")}
>
<Text
className={`text-sm font-dmsans-medium ${
donationType === "monthly"
? "text-white"
: "text-gray-600"
}`}
>
{t("donation.donationTypeMonthly")}
</Text>
</TouchableOpacity>
</View>
{/* Amount row */}
<View className="flex-row items-center bg-white rounded-full px-4 py-3 mb-3">
<Text className="flex-1 text-2xl font-dmsans-bold text-gray-900">
{donationAmount}
</Text>
</View>
{/* Quick amount chips */}
<View className="flex-row justify-between mb-4">
{["5", "10", "25", "50", "100"].map((value) => {
const isActive = donationAmount === value;
return (
<TouchableOpacity
key={value}
activeOpacity={0.8}
onPress={() => setDonationAmount(value)}
>
<View
className={`px-4 py-2 rounded-full border ${
isActive
? "bg-primary border-primary"
: "bg-white border-gray-200"
}`}
>
<Text
className={`text-sm font-dmsans-medium ${
isActive ? "text-white" : "text-gray-700"
}`}
>
${value}
</Text>
</View>
</TouchableOpacity>
);
})}
</View>
<TouchableOpacity
className="flex-row items-center mb-3"
activeOpacity={0.8}
onPress={() => setDonateAnonymously(!donateAnonymously)}
>
<View
className={`w-5 h-5 rounded-md border items-center justify-center mr-3 ${
donateAnonymously
? "bg-primary border-primary"
: "border-gray-400 bg-white"
}`}
>
{donateAnonymously && <Check size={14} color="#ffffff" />}
</View>
<Text className="text-sm font-dmsans text-gray-700">
{t("donation.donateAnonymouslyLabel")}
</Text>
</TouchableOpacity>
<View className="bg-white rounded-xl px-4 py-3 mb-3">
<Text className="text-base font-dmsans-medium text-gray-900">
{displayName}
</Text>
</View>
</View>
</View>
</View>
</ScrollView>
<View className="px-5 pb-6 pt-2 flex-row gap-3 bg-white">
<View className="flex-1">
<Button className="bg-gray-100 rounded-full" onPress={handleSkip}>
<Text className="text-gray-700 font-dmsans-medium text-base text-center">
{t("donation.skipButton")}
</Text>
</Button>
</View>
<View className="flex-1">
<Button className="bg-primary rounded-full" onPress={handleDonate}>
<Text className="text-white font-dmsans-medium text-base text-center">
{t("donation.donateButton")}
</Text>
</Button>
</View>
</View>
</ScreenWrapper>
);
}