← back to Beverlyhillsvideos App

components/FavoritesModal.tsx

207 lines

import React from 'react';
import {
  Modal,
  View,
  Text,
  TouchableOpacity,
  FlatList,
  StyleSheet,
  SafeAreaView,
  Linking,
} from 'react-native';
import { Colors } from '@/constants/Colors';
import { MapLocation } from '@/types';

interface Props {
  visible: boolean;
  onClose: () => void;
  locations: MapLocation[];
  favorites: Set<string>;
  onToggleFavorite: (name: string) => void;
}

export default function FavoritesModal({
  visible,
  onClose,
  locations,
  favorites,
  onToggleFavorite,
}: Props) {
  const favorited = locations.filter((loc) => favorites.has(loc.name));

  return (
    <Modal
      visible={visible}
      animationType="slide"
      presentationStyle="pageSheet"
      onRequestClose={onClose}
    >
      <SafeAreaView style={styles.safeArea}>
        <View style={styles.header}>
          <Text style={styles.heading}>Favorites</Text>
          <TouchableOpacity onPress={onClose} style={styles.doneBtn} hitSlop={8}>
            <Text style={styles.doneText}>Done</Text>
          </TouchableOpacity>
        </View>

        {favorited.length === 0 ? (
          <View style={styles.empty}>
            <Text style={styles.emptyIcon}>heart</Text>
            <Text style={styles.emptyTitle}>No favorites yet</Text>
            <Text style={styles.emptyBody}>
              Tap the heart on any restaurant to save it here.
            </Text>
          </View>
        ) : (
          <FlatList
            data={favorited}
            keyExtractor={(item) => item.name}
            contentContainerStyle={styles.list}
            ItemSeparatorComponent={() => <View style={styles.separator} />}
            renderItem={({ item }) => (
              <View style={styles.row}>
                <View style={styles.rowInfo}>
                  <Text style={styles.rowName}>{item.name}</Text>
                  <Text style={styles.rowCategory}>{item.category}</Text>
                  <Text style={styles.rowAddress} numberOfLines={1}>
                    {item.address}
                  </Text>
                </View>
                <View style={styles.rowActions}>
                  {item.phone ? (
                    <TouchableOpacity
                      style={styles.actionBtn}
                      onPress={() => Linking.openURL(`tel:${item.phone}`)}
                    >
                      <Text style={styles.actionText}>Call</Text>
                    </TouchableOpacity>
                  ) : null}
                  <TouchableOpacity
                    style={styles.heartBtn}
                    onPress={() => onToggleFavorite(item.name)}
                    hitSlop={6}
                  >
                    <Text style={styles.heart}>heart_filled</Text>
                  </TouchableOpacity>
                </View>
              </View>
            )}
          />
        )}
      </SafeAreaView>
    </Modal>
  );
}

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: Colors.cream,
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 20,
    paddingVertical: 14,
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: Colors.border,
    backgroundColor: Colors.cream,
  },
  heading: {
    flex: 1,
    fontSize: 20,
    fontWeight: '700',
    color: Colors.ink,
    letterSpacing: 0.2,
  },
  doneBtn: {
    paddingVertical: 4,
  },
  doneText: {
    color: Colors.green,
    fontSize: 16,
    fontWeight: '600',
  },
  empty: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    padding: 40,
  },
  emptyIcon: {
    fontSize: 40,
    color: Colors.gold,
    marginBottom: 12,
  },
  emptyTitle: {
    fontSize: 20,
    fontWeight: '600',
    color: Colors.ink,
    marginBottom: 8,
  },
  emptyBody: {
    fontSize: 15,
    color: Colors.textSecondary,
    textAlign: 'center',
    lineHeight: 22,
  },
  list: {
    paddingVertical: 8,
  },
  separator: {
    height: StyleSheet.hairlineWidth,
    backgroundColor: Colors.border,
    marginLeft: 20,
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 20,
    paddingVertical: 14,
    backgroundColor: Colors.cream,
  },
  rowInfo: {
    flex: 1,
    marginRight: 12,
  },
  rowName: {
    fontSize: 16,
    fontWeight: '600',
    color: Colors.ink,
    marginBottom: 2,
  },
  rowCategory: {
    fontSize: 13,
    color: Colors.gold,
    marginBottom: 2,
    fontWeight: '500',
  },
  rowAddress: {
    fontSize: 12,
    color: Colors.textSecondary,
  },
  rowActions: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 10,
  },
  actionBtn: {
    backgroundColor: Colors.green,
    paddingVertical: 6,
    paddingHorizontal: 14,
    borderRadius: 6,
  },
  actionText: {
    color: '#fff',
    fontSize: 13,
    fontWeight: '600',
  },
  heartBtn: {
    padding: 4,
  },
  heart: {
    fontSize: 20,
    color: Colors.gold,
  },
});