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";
const ORDER_TYPE_LABELS = {
GIFT: "Crédit offert",
COINS: "Achat de coins",
SONG: "Génération de musique",
};
const STATUS_LABELS = {
PENDING: "En cours",
APPLIED: "Confirmée",
REJECTED: "Refusée",
};
const formatCoins = (amount) => {
if (typeof amount !== "number" || !Number.isFinite(amount)) {
return "0";
}
try {
return new Intl.NumberFormat("fr-FR", {
maximumFractionDigits: 0,
}).format(amount);
} catch (_error) {
return `${amount}`;
}
};
const formatDate = (date) => {
if (!date) {
return "En attente de confirmation";
}
try {
return date.toLocaleString("fr-FR", {
day: "2-digit",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
} catch (_error) {
return date.toString();
}
};
const mapOrderType = (type) => ORDER_TYPE_LABELS[type] || "Opération";
const mapStatus = (status) => STATUS_LABELS[status] || "Inconnue";
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 amountLabel = `${isPositive ? "+" : ""}${formatCoins(amountValue)} ${
amountValue === 1 ? "coin" : "coins"
}`;
const status = item.status || "PENDING";
const details = (() => {
if (item.type === "GIFT" && item.metadata?.reason) {
switch (item.metadata.reason) {
case "WELCOME_BONUS":
return "Crédit de bienvenue";
default:
return item.metadata.reason;
}
}
if (item.type === "SONG" && item.songId) {
return `Musique ${item.songId}`;
}
if (item.type === "COINS" && item.metadata?.paymentId) {
return `Paiement ${item.metadata.paymentId}`;
}
return null;
})();
return (
{mapOrderType(item.type)}
{amountLabel}
{formatDate(item.createdAt)}
{mapStatus(status)}
{details ? {details} : null}
{typeof item.balanceAfter === "number" &&
Number.isFinite(item.balanceAfter) ? (
Solde après opération: {formatCoins(item.balanceAfter)} coins
) : null}
);
}, []);
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)",
},
orderHeader: {
flexDirection: "row",
alignItems: "flex-start",
justifyContent: "space-between",
marginBottom: 8,
gap: 12,
},
orderTitle: {
flex: 1,
fontSize: 16,
fontFamily: FONT_FAMILY.InterSemiBold,
color: Palette.white,
},
orderAmount: {
fontSize: 16,
fontFamily: FONT_FAMILY.InterSemiBold,
},
amountPositive: {
color: Palette.green,
},
amountNegative: {
color: Palette.red,
},
orderMetaRow: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
marginBottom: 6,
gap: 12,
},
orderDate: {
fontSize: 13,
color: Palette.grayMid,
fontFamily: FONT_FAMILY.InterRegular,
},
statusBadge: {
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 999,
},
statusApplied: {
backgroundColor: Palette.transparentGreen,
},
statusPending: {
backgroundColor: Palette.transparentOrange,
},
statusRejected: {
backgroundColor: Palette.transparentRed,
},
statusText: {
fontSize: 12,
fontFamily: FONT_FAMILY.InterMedium,
color: Palette.white,
},
orderDetails: {
marginBottom: 6,
fontSize: 14,
fontFamily: FONT_FAMILY.InterRegular,
color: Palette.white,
},
orderBalance: {
fontSize: 13,
fontFamily: FONT_FAMILY.InterRegular,
color: Palette.grayMid,
},
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;