import React, { useEffect, useRef, useState } from "react"; import { View, Text, Image, ScrollView, ActivityIndicator, TouchableOpacity, Dimensions, } from "react-native"; import ScreenWrapper from "~/components/ui/ScreenWrapper"; import { Button } from "~/components/ui/button"; import { Icons } from "~/assets/icons"; import { Share } from "react-native"; import ModalToast from "~/components/ui/toast"; import { useTranslation } from "react-i18next"; import { router, useLocalSearchParams } from "expo-router"; import BackButton from "~/components/ui/backButton"; import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile"; import { EventService, type EventDto } from "~/lib/services/eventService"; import BottomSheet from "~/components/ui/bottomSheet"; import { ROUTES } from "~/lib/routes"; import { awardPoints } from "~/lib/services/pointsService"; export default function EventDetailScreen() { const { t } = useTranslation(); const params = useLocalSearchParams<{ id?: string }>(); const { user } = useAuthWithProfile(); const [event, setEvent] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [currentImageIndex, setCurrentImageIndex] = useState(0); const [selectedTierId, setSelectedTierId] = useState(null); const [toastVisible, setToastVisible] = useState(false); const [toastTitle, setToastTitle] = useState(""); const [toastDescription, setToastDescription] = useState< string | undefined >(); const [toastVariant, setToastVariant] = useState< "success" | "error" | "warning" | "info" >("info"); const toastTimeoutRef = useRef | null>(null); const screenWidth = Dimensions.get("window").width; const [buySheetVisible, setBuySheetVisible] = useState(false); const [ticketCount, setTicketCount] = useState(1); 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); }; const handleShare = async () => { try { await Share.share({ message: t("eventdetail.shareMessage"), }); try { await awardPoints("share_event"); } catch (error) { console.warn("[EventDetail] Failed to award share event points", error); } } catch (error) { console.log("Error sharing event:", error); showToast( t("eventdetail.toastErrorTitle"), t("eventdetail.toastShareError"), "error" ); } }; useEffect(() => { let cancelled = false; const loadEvent = async () => { if (!user || !params.id) return; setLoading(true); setError(null); try { const token = await user.getIdToken(); const eventData = await EventService.getEventById( token, String(params.id) ); if (!cancelled) { setEvent(eventData); // Debug images and description to verify response console.log("[EventDetail] event images", eventData?.images); console.log( "[EventDetail] event description", eventData?.description ); } } catch (err) { if (!cancelled) { setError("Failed to load event details"); } } finally { if (!cancelled) { setLoading(false); } } }; loadEvent(); return () => { cancelled = true; }; }, [user, params.id]); const fallbackImage = "https://images.pexels.com/photos/1190297/pexels-photo-1190297.jpeg?auto=compress&cs=tinysrgb&w=800"; const images = event?.images && event.images.length > 0 ? event.images : [fallbackImage]; const startDate = event?.startDate ? new Date(event.startDate) : null; const endDate = event?.endDate ? new Date(event.endDate) : null; const formatEventDateRange = (start: Date, end: Date) => { // Format like: Sat, Jan 10, 2026 at 6:00 PM – 1:00 AM (EAT) const datePart = start.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric", year: "numeric", }); const startTime = start.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", }); const endTime = end.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", }); return `${datePart} at ${startTime} – ${endTime} (EAT)`; }; const formattedDate = startDate && endDate ? formatEventDateRange(startDate, endDate) : t("eventdetail.dateTime"); const handleBuy = () => { if (!event || !selectedTierId) { showToast( "Ticket selection required", "Please select a ticket tier first", "error" ); return; } const tier = event.ticketTiers?.find((t: any) => t.id === selectedTierId); if (!tier) { showToast( "Ticket selection required", "Please select a ticket tier first", "error" ); return; } console.log("[EventDetail] Buy pressed", { eventId: event.id, selectedTierId, }); setTicketCount(1); setBuySheetVisible(true); }; const handleConfirmBuy = () => { if (!event || !selectedTierId) { showToast( "Ticket selection required", "Please select a ticket tier first", "error" ); return; } const tier = event.ticketTiers?.find((t: any) => t.id === selectedTierId); if (!tier) { showToast( "Ticket selection required", "Please select a ticket tier first", "error" ); return; } const priceNumber = Number(tier.price || 0); const amountInCents = Math.round(priceNumber * 100 * ticketCount); setBuySheetVisible(false); router.push({ pathname: ROUTES.CHECKOUT, params: { amount: String(amountInCents), type: "event_ticket", ticketTierName: tier.name, ticketTierPrice: priceNumber.toFixed(2), eventName: event.name, eventId: event.id, ticketTierId: tier.id, ticketCount: String(ticketCount), }, }); }; return ( {event?.name ?? t("eventdetail.title")} {loading && ( Loading event details... )} {!loading && error && ( {error} )} {!loading && !error && ( <> {event?.description ?? t("eventdetail.description")} {event?.venue ?? t("eventdetail.location")} {formattedDate} { const { contentOffset, layoutMeasurement } = e.nativeEvent; const index = Math.round( contentOffset.x / layoutMeasurement.width ); setCurrentImageIndex(index); }} > {images.map((img, index) => ( ))} {images.map((_, index) => ( ))} {[0, 1, 2, 3, 4].map((i) => ( ))} {t("eventdetail.peopleComing")} {event?.ticketTiers && event.ticketTiers.length > 0 && ( {event.ticketTiers.map((tier: any) => { const isSelected = tier.id === selectedTierId; return ( setSelectedTierId(tier.id)} > {isSelected && ( )} {tier.name} ${tier.price} ); })} )} )} setBuySheetVisible(false)} maxHeightRatio={0.5} > {event && selectedTierId && ( Confirm tickets {event.name} {(() => { const tier = event.ticketTiers?.find( (t: any) => t.id === selectedTierId ); if (!tier) return null; const priceNumber = Number(tier.price || 0); const total = priceNumber * ticketCount; return ( <> {tier.name} ${priceNumber.toFixed(2)} per ticket Total ${total.toFixed(2)} Ticket count setTicketCount((c) => Math.max(1, c - 1)) } > - {ticketCount} setTicketCount((c) => c + 1)} > + ); })()} )} ); }