Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tela de Detalhe

Crie src/EventDetailScreen.tsx:

Arquivo: mobile/src/EventDetailScreen.tsx
import { useState, useEffect } from "react";
import { View, Text, StyleSheet, ActivityIndicator } from "react-native";
import { RouteProp, useRoute } from "@react-navigation/native";
import { Event } from "./types";
import { API_BASE_URL } from "./config";
import { RootStackParamList } from "./navigation";

type DetailRoute = RouteProp<RootStackParamList, "EventDetail">;

export default function EventDetailScreen() {
  const route = useRoute<DetailRoute>();
  const { eventId } = route.params;

  const [event, setEvent] = useState<Event | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetch(`${API_BASE_URL}/api/events`)
      .then((res) => {
        if (!res.ok) throw new Error(`Erro ${res.status}`);
        return res.json();
      })
      .then((data: Event[]) => {
        const found = data.find((ev) => ev.id === eventId);
        if (!found) throw new Error("Evento não encontrado");
        setEvent(found);
      })
      .catch((err) => setError(err.message))
      .finally(() => setLoading(false));
  }, [eventId]);

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#3182ce" />
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.error}>{error}</Text>
      </View>
    );
  }

  if (!event) return null;

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{event.title}</Text>
      <Text style={styles.date}>
        {new Date(event.date).toLocaleString("pt-BR", {
          dateStyle: "full",
          timeStyle: "short",
        })}
      </Text>
      <Text style={styles.description}>{event.description}</Text>
      <Text style={styles.location}>📍 {event.location}</Text>
      <Text style={styles.info}>
        Capacidade: {event.capacity} pessoas
      </Text>
      <Text style={styles.info}>
        Organizado por {event.organizer_name}
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  center: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  container: {
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: "700",
    marginBottom: 8,
  },
  date: {
    color: "#718096",
    fontSize: 15,
    marginBottom: 16,
  },
  description: {
    fontSize: 16,
    lineHeight: 24,
    marginBottom: 16,
  },
  location: {
    fontSize: 15,
    marginBottom: 8,
  },
  info: {
    fontSize: 15,
    color: "#4a5568",
    marginBottom: 4,
  },
  error: {
    color: "#e53e3e",
    fontSize: 16,
  },
});

Código 8-7: Tela de detalhe do evento.

O useRoute extrai os parâmetros da rota — nesse caso, o eventId. O resto do padrão (fetch, loading, error) é o mesmo do EventList. A diferença é visual: a tela de detalhe usa fontes maiores e mais espaçamento, já que dispõe da tela inteira em vez de dividir espaço com outros cards.

O botão “voltar” aparece automaticamente. O stack navigator coloca uma seta no canto superior esquerdo de qualquer tela que não seja a primeira da pilha. No Android, o botão de voltar do sistema (gesto de swipe ou botão virtual) também funciona sem nenhum código adicional.