import React, { useCallback, useEffect, useMemo, useState } from "react"; import { ActivityIndicator, FlatList, StyleSheet, Text, View, } from "react-native"; import firebase from "../../config/firebase"; import { background } from "../../assets"; import Page from "../../layouts/Page"; import { useUser } from "../../providers/UserDataProvider"; import { gutters, Palette } from "../../styles"; import { FONT_FAMILY } from "../../styles/Fonts"; import CreditAmount from "../../components/CreditAmount"; const ORDER_TYPE_LABELS = { GIFT: "Crédit offert", COINS: "Achat de coins", SONG: "Génération de musique", SUBSCRIPTION: "Abonnement", }; const formatDateParts = (date) => { if (!date) { return { dateLabel: "En attente de confirmation", timeLabel: "", }; } try { const dateLabel = date.toLocaleDateString("fr-FR", { day: "2-digit", month: "short", year: "numeric", }); const timeLabel = date.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit", }); return { dateLabel, timeLabel }; } catch (_error) { return { dateLabel: date.toString(), timeLabel: "", }; } }; const mapOrderType = (type) => ORDER_TYPE_LABELS[type] || "Opération"; const shortenIdentifier = (value, visible = 6) => { if (typeof value !== "string") return null; if (value.length <= visible + 2) return value; return `${value.slice(0, visible)}…`; }; const OrderHistory = () => { const { currentUID } = useUser() || {}; const [orders, setOrders] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (!currentUID) { setOrders([]); setLoading(false); return; } setLoading(true); setError(null); const unsubscribe = firebase .firestore() .collection("orders") .where("userId", "==", currentUID) .orderBy("createdAt", "desc") .onSnapshot( (snapshot) => { const nextOrders = snapshot.docs.map((doc) => { const rawData = doc.data() || {}; const createdAt = typeof rawData.createdAt?.toDate === "function" ? rawData.createdAt.toDate() : null; return { id: doc.id, ...rawData, createdAt, }; }); setOrders(nextOrders); setLoading(false); }, (firestoreError) => { console.warn( "[OrderHistory] Unable to load orders", firestoreError?.message || firestoreError, ); setError( firestoreError?.message || "Impossible de récupérer l'historique des commandes.", ); setLoading(false); }, ); return () => { if (typeof unsubscribe === "function") { unsubscribe(); } }; }, [currentUID]); const renderOrder = useCallback(({ item }) => { const amountValue = typeof item.amount === "number" && Number.isFinite(item.amount) ? item.amount : 0; const isPositive = amountValue > 0; const amountTextStyle = [ styles.orderAmount, isPositive ? styles.amountPositive : styles.amountNegative, ]; const { dateLabel } = formatDateParts(item.createdAt); let reasonLabel = mapOrderType(item.type); if (item.type === "GIFT") { const reason = item.metadata?.reason; if (reason === "WELCOME_BONUS") { reasonLabel = "Crédit de bienvenue"; } else if (typeof reason === "string" && reason.trim()) { reasonLabel = reason.trim(); } } else if (item.type === "SONG") { reasonLabel = "Génération de musique"; } else if (item.type === "COINS") { if (item.metadata?.coinPackKey) { const shortenedPack = shortenIdentifier( item.metadata.coinPackKey, 10, ); reasonLabel = `Pack ${shortenedPack || item.metadata.coinPackKey}`; } else if ( typeof item.metadata?.source === "string" && item.metadata.source.trim() ) { const source = item.metadata.source.trim(); reasonLabel = source === "STRIPE_CHECKOUT" ? "Recharge Stripe" : source; } else { reasonLabel = "Rechargement de coins"; } } else if (item.type === "SUBSCRIPTION") { const rawPeriod = typeof item.metadata?.billingPeriod === "string" ? item.metadata.billingPeriod.toLowerCase() : null; reasonLabel = rawPeriod === "annual" ? "Abonnement annuel" : rawPeriod === "monthly" ? "Abonnement mensuel" : "Abonnement"; } return ( {reasonLabel} {dateLabel} ); }, []); const keyExtractor = useCallback((item) => item.id, []); const listEmptyComponent = useMemo(() => { if (loading) { return null; } if (!currentUID) { return ( Connecte-toi pour consulter l'historique de tes commandes. ); } if (error) { return {error}; } return ( Aucune opération de coins pour le moment. ); }, [loading, currentUID, error]); return ( {loading ? ( ) : ( } ListEmptyComponent={listEmptyComponent} /> )} ); }; const styles = StyleSheet.create({ container: { flex: 1, paddingHorizontal: gutters, paddingTop: gutters, }, loaderContainer: { flex: 1, alignItems: "center", justifyContent: "center", }, listContent: { paddingBottom: gutters * 2, }, emptyListContent: { flexGrow: 1, justifyContent: "center", }, orderCard: { padding: 16, borderRadius: 16, backgroundColor: Palette.ultraLightWhite, borderWidth: 1, borderColor: "rgba(255, 255, 255, 0.08)", gap: 6, }, orderAmount: { fontSize: 16, fontFamily: FONT_FAMILY.InterSemiBold, }, amountPositive: { color: Palette.green, }, amountNegative: { color: Palette.red, }, orderReason: { fontSize: 14, fontFamily: FONT_FAMILY.InterRegular, color: Palette.white, }, orderTimestamp: { fontSize: 12, color: Palette.grayMid, fontFamily: FONT_FAMILY.InterMedium, }, emptyText: { textAlign: "center", color: Palette.grayMid, fontSize: 15, fontFamily: FONT_FAMILY.InterRegular, }, errorText: { textAlign: "center", color: Palette.red, fontSize: 15, fontFamily: FONT_FAMILY.InterRegular, }, }); export default OrderHistory;