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

391 lines
13 KiB
TypeScript

import React, { useEffect, useRef, useState } from "react";
import {
View,
Text,
Image,
ScrollView,
Share,
TouchableOpacity,
TextInput,
} from "react-native";
import { Button } from "~/components/ui/button";
import { SafeAreaView } from "react-native-safe-area-context";
import { router, useLocalSearchParams } from "expo-router";
import { ROUTES } from "~/lib/routes";
import { SuccessIcon } from "~/components/ui/icons";
import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile";
import ScreenWrapper from "~/components/ui/ScreenWrapper";
import ModalToast from "~/components/ui/toast";
import { useTranslation } from "react-i18next";
import LottieView from "lottie-react-native";
import { Icons } from "~/assets/icons";
export default function TaskComp() {
const { t } = useTranslation();
const params = useLocalSearchParams<{
message?: string;
amount?: string;
recipientName?: string;
recipientPhoneNumber?: string;
flowType?: string;
}>();
const { wallet } = useAuthWithProfile();
const [toastVisible, setToastVisible] = useState(false);
const [toastTitle, setToastTitle] = useState("");
const [toastDescription, setToastDescription] = useState<string | undefined>(
undefined
);
const [toastVariant, setToastVariant] = useState<
"success" | "error" | "warning" | "info"
>("info");
const toastTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const isEventTicketFlow = params.flowType === "event_ticket";
const [ratingSheetVisible, setRatingSheetVisible] = useState(false);
const [rating, setRating] = useState(0);
const [selectedIssues, setSelectedIssues] = useState<string[]>([]);
const [comments, setComments] = useState("");
const [selectedPurpose, setSelectedPurpose] = useState<string | null>(null);
const [isPurposeDropdownOpen, setIsPurposeDropdownOpen] = useState(false);
const [otherPurpose, setOtherPurpose] = useState("");
const showToast = (
title: string,
description?: string,
variant: "success" | "error" | "warning" | "info" = "info"
) => {
if (toastTimeoutRef.current) {
clearTimeout(toastTimeoutRef.current);
}
setToastTitle(title);
setToastDescription(description);
setToastVariant(variant);
setToastVisible(true);
toastTimeoutRef.current = setTimeout(() => {
setToastVisible(false);
toastTimeoutRef.current = null;
}, 2500);
};
useEffect(() => {
return () => {
if (toastTimeoutRef.current) {
clearTimeout(toastTimeoutRef.current);
}
};
}, []);
const toggleIssue = (key: string) => {
setSelectedIssues((prev) =>
prev.includes(key) ? prev.filter((i) => i !== key) : [...prev, key]
);
};
const handleSendAgain = () => {
const balance = wallet?.balance;
if (balance === undefined) {
showToast(
t("taskcomp.toastErrorTitle"),
t("taskcomp.toastNoBalance"),
"error"
);
return;
}
if (balance < 1000) {
showToast(
t("taskcomp.toastErrorTitle"),
t("taskcomp.toastMinError"),
"error"
);
return;
}
// Navigate to home first, then to send money to prevent going back to success page
router.replace(ROUTES.HOME);
// Use setTimeout to ensure home navigation completes before send money navigation
router.push(ROUTES.SEND_OR_REQUEST_MONEY);
};
const handleSubmitRating = () => {
setRatingSheetVisible(false);
router.replace(ROUTES.HOME);
};
const handleShare = async () => {
try {
const shareMessage = params.message
? t("taskcomp.shareMessageWithParam", { message: params.message })
: t("taskcomp.shareMessageDefault");
const result = await Share.share({
message: shareMessage,
title: t("taskcomp.shareTitle"),
});
if (result.action === Share.sharedAction) {
// Content was shared
console.log("Content shared successfully");
} else if (result.action === Share.dismissedAction) {
// Share dialog was dismissed
console.log("Share dialog dismissed");
}
} catch (error) {
console.error("Error sharing:", error);
showToast(
t("taskcomp.toastErrorTitle"),
t("taskcomp.toastShareError"),
"error"
);
}
};
return (
<ScreenWrapper edges={[]}>
<View className="flex-1 w-full">
<View className="w-full flex-1">
<View className="flex-1 justify-center w-full">
{/* <View className="h-24" /> */}
<View className="flex items-center space-y-10">
<LottieView
source={require("../../../assets/lottie/Success.json")}
autoPlay
loop={false}
style={{ width: 260, height: 260 }}
/>
{/* <View className="h-10" /> */}
{params.amount ? (
<View className="px-5">
<Text className="text-secondary font-dmsans-bold text-3xl">
{params.amount}
</Text>
</View>
) : (
<></>
)}
<View className="h-4" />
<View className="px-5">
<Text className="text-lg font-regular text-gray-400 font-dmsans text-center">
{params.message || t("taskcomp.successDescription")}
</Text>
</View>
</View>
</View>
</View>
{/* Bottom action buttons */}
<View className="w-full px-5 pb-8 pt-4" style={{ gap: 12 }}>
{isEventTicketFlow ? (
<>
<Button
className="bg-primary rounded-full"
onPress={() => router.replace(ROUTES.HOME)}
>
<Text className="font-dmsans text-white">
{t("taskcomp.goHomeButton")}
</Text>
</Button>
<Button
className="bg-secondary rounded-full"
onPress={handleShare}
>
<Text className="font-dmsans text-white">
{t("taskcomp.shareButton")}
</Text>
</Button>
</>
) : (
<>
<Button
className="bg-primary rounded-full"
onPress={handleSendAgain}
>
<Text className="font-dmsans text-white">
{t("taskcomp.sendAgainButton")}
</Text>
</Button>
<Button
className="bg-secondary rounded-full"
onPress={handleShare}
>
<Text className="font-dmsans text-white">
{t("taskcomp.shareButton")}
</Text>
</Button>
<Button
className="bg-white border border-dashed border-[#FBBF77] rounded-full"
onPress={() => setRatingSheetVisible(true)}
>
<Text className="font-dmsans text-black">
{t("taskcomp.goHomeButton")}
</Text>
</Button>
</>
)}
</View>
</View>
{!isEventTicketFlow && ratingSheetVisible && (
<View className="absolute inset-0 justify-end bg-black/40">
<TouchableOpacity
className="flex-1"
activeOpacity={1}
onPress={() => setRatingSheetVisible(false)}
/>
<View className="bg-white rounded-t-3xl px-5 pt-8 pb-6 relative">
<View className="absolute -top-7 self-center w-14 h-14 rounded-full bg-[#105D38] items-center justify-center">
<Image
source={Icons.bill}
style={{
width: 32,
height: 32,
resizeMode: "contain",
tintColor: "#fff",
}}
/>
</View>
<View className="items-center mb-4">
<Text className="text-xl font-dmsans-bold text-primary mt-3">
{t("taskcomp.ratingTitle")}
</Text>
<Text className="text-sm text-gray-500 mt-1 text-center">
{t("taskcomp.ratingSubtitle")}
</Text>
</View>
<View className="mb-4">
<Text className="text-sm font-dmsans-medium text-gray-700 mb-2">
{t("taskcomp.ratingOverallLabel")}
</Text>
<View className="flex-row justify-center gap-3">
{[1, 2, 3, 4, 5].map((star) => (
<TouchableOpacity
key={star}
onPress={() => setRating(star)}
activeOpacity={0.8}
>
<Text
className={`text-3xl font-dmsans ${
star <= rating ? "text-primary" : "text-gray-300"
}`}
>
</Text>
</TouchableOpacity>
))}
</View>
</View>
<View className="mb-4">
<Text className="text-sm font-dmsans-medium text-gray-700 mb-2">
{t("taskcomp.ratingPurposeLabel")}
</Text>
<View>
<TouchableOpacity
activeOpacity={0.8}
onPress={() => setIsPurposeDropdownOpen((prev) => !prev)}
className="border border-gray-300 rounded-2xl px-3 py-2 flex-row items-center justify-between"
>
<Text className="text-sm text-gray-900 font-dmsans">
{selectedPurpose
? t(
{
family: "taskcomp.ratingPurposeFamily",
medical: "taskcomp.ratingPurposeMedical",
loan: "taskcomp.ratingPurposeLoan",
purchase: "taskcomp.ratingPurposePurchase",
other: "taskcomp.ratingPurposeOther",
}[
selectedPurpose as
| "family"
| "medical"
| "loan"
| "purchase"
| "other"
]
)
: t("taskcomp.ratingPurposePlaceholder")}
</Text>
<Text className="text-lg text-gray-400"></Text>
</TouchableOpacity>
{isPurposeDropdownOpen && (
<View className="mt-2 border border-gray-200 rounded-2xl bg-white overflow-hidden">
{[
{
key: "family",
labelKey: "taskcomp.ratingPurposeFamily",
},
{
key: "medical",
labelKey: "taskcomp.ratingPurposeMedical",
},
{ key: "loan", labelKey: "taskcomp.ratingPurposeLoan" },
{
key: "purchase",
labelKey: "taskcomp.ratingPurposePurchase",
},
{ key: "other", labelKey: "taskcomp.ratingPurposeOther" },
].map((option) => (
<TouchableOpacity
key={option.key}
activeOpacity={0.8}
className="px-3 py-2"
onPress={() => {
setSelectedPurpose(option.key);
setIsPurposeDropdownOpen(false);
}}
>
<Text className="text-sm text-gray-800 font-dmsans">
{t(option.labelKey as any)}
</Text>
</TouchableOpacity>
))}
</View>
)}
</View>
</View>
{selectedPurpose === "other" && (
<View className="mb-4">
<Text className="text-sm font-dmsans-medium text-gray-700 mb-2">
{t("taskcomp.ratingOtherLabel")}
</Text>
<View className="border border-gray-300 rounded-2xl px-3 py-2 min-h-[60px]">
<TextInput
value={otherPurpose}
onChangeText={setOtherPurpose}
placeholder={t("taskcomp.ratingOtherPlaceholder")}
placeholderTextColor="#9CA3AF"
multiline
className="text-sm text-gray-900 font-dmsans"
/>
</View>
</View>
)}
<Button
className="bg-primary rounded-full"
onPress={handleSubmitRating}
>
<Text className="font-dmsans text-white">
{t("taskcomp.ratingSubmitButton")}
</Text>
</Button>
</View>
</View>
)}
<ModalToast
visible={toastVisible}
title={toastTitle}
description={toastDescription}
variant={toastVariant}
/>
</ScreenWrapper>
);
}