138 lines
4.4 KiB
TypeScript
138 lines
4.4 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import { View, Text, ScrollView, Image } from "react-native";
|
|
import ScreenWrapper from "~/components/ui/ScreenWrapper";
|
|
import BackButton from "~/components/ui/backButton";
|
|
import { Button } from "~/components/ui/button";
|
|
import { Icons } from "~/assets/icons";
|
|
import { useTranslation } from "react-i18next";
|
|
import {
|
|
getPointsState,
|
|
type PointsActivityEntry,
|
|
} from "~/lib/services/pointsService";
|
|
|
|
export default function PointsActivityScreen() {
|
|
const { t } = useTranslation();
|
|
const [activities, setActivities] = useState<PointsActivityEntry[]>([]);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
(async () => {
|
|
try {
|
|
const state = await getPointsState();
|
|
if (!cancelled) {
|
|
setActivities(state.activities);
|
|
}
|
|
} catch (error) {
|
|
if (__DEV__) {
|
|
console.warn("[PointsActivity] Failed to load points state", error);
|
|
}
|
|
}
|
|
})();
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, []);
|
|
const renderPointsPill = (points: number) => {
|
|
const isPositive = points >= 0;
|
|
const backgroundColor = isPositive ? "#0F7B4A" : "#EF4444";
|
|
const sign = isPositive ? "+" : "-";
|
|
const absPoints = Math.abs(points);
|
|
|
|
return (
|
|
<View
|
|
className="rounded-[2px] w-[90px] h-[28px] flex-row items-center justify-center"
|
|
style={{ backgroundColor }}
|
|
>
|
|
<Text className="text-xs font-dmsans text-white">
|
|
{t("pointsactivity.pointsPill", { sign, points: absPoints })}
|
|
</Text>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<ScreenWrapper edges={["bottom"]}>
|
|
<BackButton />
|
|
|
|
<ScrollView contentContainerStyle={{ paddingBottom: 32 }}>
|
|
<View className="px-5 pt-6 space-y-6">
|
|
<Text className="text-xl font-dmsans-bold text-black">
|
|
{t("pointsactivity.title")}
|
|
</Text>
|
|
|
|
<View className="space-y-3 pt-6">
|
|
{activities.map((item) => {
|
|
const date = new Date(item.timestamp);
|
|
const formattedDate = `${date.toLocaleDateString()} • ${date.toLocaleTimeString(
|
|
[],
|
|
{
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
}
|
|
)}`;
|
|
|
|
let titleKey: string;
|
|
switch (item.type) {
|
|
case "contact_sync":
|
|
titleKey = "Contact Sync";
|
|
break;
|
|
case "send_money":
|
|
titleKey = "Send Money";
|
|
break;
|
|
case "login":
|
|
titleKey = "Login";
|
|
break;
|
|
case "purchase_ticket":
|
|
titleKey = "Purchase Ticket";
|
|
break;
|
|
case "add_recipient":
|
|
titleKey = "Add Recipient";
|
|
break;
|
|
case "share_event":
|
|
titleKey = "Share Event";
|
|
break;
|
|
case "make_request":
|
|
titleKey = "Make Request";
|
|
break;
|
|
case "referral_link":
|
|
titleKey = "Referral Link";
|
|
break;
|
|
default:
|
|
titleKey = item.type;
|
|
}
|
|
|
|
return (
|
|
<View
|
|
key={item.id}
|
|
className="flex-row items-center mb-4 justify-between bg-[#E9FFF4] rounded-[6px] px-4 py-3"
|
|
>
|
|
<View className="flex-row items-center flex-1">
|
|
<View className="w-10 h-10 rounded-[6px] bg-[#FFF7E6] items-center justify-center mr-3">
|
|
<Image
|
|
source={Icons.coinIcon}
|
|
style={{ width: 20, height: 20 }}
|
|
resizeMode="contain"
|
|
/>
|
|
</View>
|
|
<View className="flex-1">
|
|
<Text className="text-sm font-dmsans text-[#FB923C]">
|
|
{titleKey}
|
|
</Text>
|
|
<Text className="text-xs font-dmsans text-[#064E3B] mt-1">
|
|
{formattedDate}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{renderPointsPill(item.points)}
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
</ScreenWrapper>
|
|
);
|
|
}
|