319 lines
8.8 KiB
TypeScript
319 lines
8.8 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
ScrollView,
|
|
StyleSheet,
|
|
Pressable,
|
|
FlatList,
|
|
Image,
|
|
RefreshControl,
|
|
} from 'react-native';
|
|
import { LinearGradient } from 'expo-linear-gradient';
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import { StackNavigationProp } from '@react-navigation/stack';
|
|
import { RootStackParamList } from '../navigation/types';
|
|
import { supabase, isSupabaseConfigured } from '../services/supabase';
|
|
import { COLORS, SIZES, FONTS, SHADOWS } from '../constants/theme';
|
|
import { Service, Barber, Promotion } from '../types';
|
|
import { mockServices, mockBarbers, mockPromotions } from '../data/mockData';
|
|
import ServiceCard from '../components/ServiceCard';
|
|
import BarberCard from '../components/BarberCard';
|
|
|
|
const HomeScreen: React.FC = () => {
|
|
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>();
|
|
const [featuredServices, setFeaturedServices] = useState<Service[]>([]);
|
|
const [featuredBarbers, setFeaturedBarbers] = useState<Barber[]>([]);
|
|
const [promotions, setPromotions] = useState<Promotion[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [refreshing, setRefreshing] = useState(false);
|
|
|
|
useEffect(() => {
|
|
loadData();
|
|
}, []);
|
|
|
|
const loadData = async () => {
|
|
try {
|
|
if (!isSupabaseConfigured) {
|
|
// Modo demo - usando dados de exemplo
|
|
setFeaturedServices(mockServices.slice(0, 4));
|
|
setFeaturedBarbers(mockBarbers.filter(b => (b.rating || 0) >= 4.7));
|
|
setPromotions(mockPromotions);
|
|
setLoading(false);
|
|
setRefreshing(false);
|
|
return;
|
|
}
|
|
|
|
const [servicesRes, barbersRes, promotionsRes] = await Promise.all([
|
|
supabase
|
|
.from('services')
|
|
.select('*')
|
|
.eq('is_active', true)
|
|
.limit(5),
|
|
supabase
|
|
.from('barbers')
|
|
.select(`
|
|
*,
|
|
user:users(name, photo)
|
|
`)
|
|
.eq('is_active', true)
|
|
.gte('rating', 4)
|
|
.limit(5),
|
|
supabase
|
|
.from('promotions')
|
|
.select('*')
|
|
.eq('is_active', true)
|
|
.order('created_at', { ascending: false })
|
|
.limit(3),
|
|
]);
|
|
|
|
if (servicesRes.data) setFeaturedServices(servicesRes.data);
|
|
if (barbersRes.data) setFeaturedBarbers(barbersRes.data);
|
|
if (promotionsRes.data) setPromotions(promotionsRes.data);
|
|
} catch (error) {
|
|
console.error('Erro ao carregar dados:', error);
|
|
// Usando dados de exemplo devido a erro
|
|
setFeaturedServices(mockServices.slice(0, 4));
|
|
setFeaturedBarbers(mockBarbers.filter(b => (b.rating || 0) >= 4.7));
|
|
setPromotions(mockPromotions);
|
|
} finally {
|
|
setLoading(false);
|
|
setRefreshing(false);
|
|
}
|
|
};
|
|
|
|
const onRefresh = () => {
|
|
setRefreshing(true);
|
|
loadData();
|
|
};
|
|
|
|
const renderPromotion = ({ item }: { item: Promotion }) => (
|
|
<Pressable
|
|
style={({ pressed }) => [
|
|
styles.promotionCard,
|
|
pressed && styles.promotionCardPressed
|
|
]}
|
|
onPress={() => navigation.navigate('Services')}
|
|
>
|
|
<Image source={{ uri: item.image || 'https://via.placeholder.com/300' }} style={styles.promotionImage} />
|
|
<LinearGradient
|
|
colors={['transparent', 'rgba(0,0,0,0.8)']}
|
|
style={styles.promotionOverlay}
|
|
>
|
|
<Text style={styles.promotionTitle}>{item.title}</Text>
|
|
<Text style={styles.promotionDescription}>{item.description}</Text>
|
|
<Text style={styles.promotionDiscount}>{item.discount_percentage}% OFF</Text>
|
|
</LinearGradient>
|
|
</Pressable>
|
|
);
|
|
|
|
const renderService = ({ item }: { item: Service }) => (
|
|
<ServiceCard
|
|
service={item}
|
|
onPress={() => navigation.navigate('ServiceDetail', { serviceId: item.id })}
|
|
/>
|
|
);
|
|
|
|
const renderBarber = ({ item }: { item: Barber }) => (
|
|
<BarberCard
|
|
barber={item}
|
|
onPress={() => navigation.navigate('BarberDetail', { barberId: item.id })}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<ScrollView
|
|
style={styles.container}
|
|
refreshControl={
|
|
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor={COLORS.primary} />
|
|
}
|
|
>
|
|
{/* Hero Section */}
|
|
<View style={styles.heroSection}>
|
|
<LinearGradient colors={[COLORS.primary, COLORS.accent]} style={styles.heroGradient}>
|
|
<Text style={styles.heroTitle}>Barbearia Premium</Text>
|
|
<Text style={styles.heroSubtitle}>Experimente o luxo do cuidado masculino</Text>
|
|
<Pressable
|
|
style={({ pressed }) => [
|
|
styles.bookNowButton,
|
|
pressed && styles.bookNowButtonPressed
|
|
]}
|
|
onPress={() => navigation.navigate('Booking')}
|
|
>
|
|
<Text style={styles.bookNowText}>Marcar Agora</Text>
|
|
</Pressable>
|
|
</LinearGradient>
|
|
</View>
|
|
|
|
{/* Promotions */}
|
|
{promotions.length > 0 && (
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Ofertas Especiais</Text>
|
|
<FlatList
|
|
data={promotions}
|
|
renderItem={renderPromotion}
|
|
keyExtractor={(item) => item.id}
|
|
horizontal
|
|
showsHorizontalScrollIndicator={false}
|
|
contentContainerStyle={styles.promotionsList}
|
|
/>
|
|
</View>
|
|
)}
|
|
|
|
{/* Featured Services */}
|
|
<View style={styles.section}>
|
|
<View style={styles.sectionHeader}>
|
|
<Text style={styles.sectionTitle}>Serviços em Destaque</Text>
|
|
<Pressable
|
|
style={({ pressed }) => [pressed && styles.pressed]}
|
|
onPress={() => navigation.navigate('Services')}
|
|
>
|
|
<Text style={styles.seeAllText}>Ver Todos</Text>
|
|
</Pressable>
|
|
</View>
|
|
<FlatList
|
|
data={featuredServices}
|
|
renderItem={renderService}
|
|
keyExtractor={(item) => item.id}
|
|
numColumns={2}
|
|
columnWrapperStyle={styles.servicesRow}
|
|
scrollEnabled={false}
|
|
/>
|
|
</View>
|
|
|
|
{/* Featured Barbers */}
|
|
<View style={styles.section}>
|
|
<View style={styles.sectionHeader}>
|
|
<Text style={styles.sectionTitle}>Barbeiros Mais Avaliados</Text>
|
|
<Pressable
|
|
style={({ pressed }) => [pressed && styles.pressed]}
|
|
onPress={() => navigation.navigate('Barbers')}
|
|
>
|
|
<Text style={styles.seeAllText}>Ver Todos</Text>
|
|
</Pressable>
|
|
</View>
|
|
<FlatList
|
|
data={featuredBarbers}
|
|
renderItem={renderBarber}
|
|
keyExtractor={(item) => item.id}
|
|
scrollEnabled={false}
|
|
/>
|
|
</View>
|
|
</ScrollView>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: COLORS.background,
|
|
},
|
|
heroSection: {
|
|
margin: SIZES.margin,
|
|
borderRadius: SIZES.radius,
|
|
overflow: 'hidden',
|
|
...SHADOWS.heavy,
|
|
},
|
|
heroGradient: {
|
|
padding: SIZES.padding * 2,
|
|
alignItems: 'center',
|
|
},
|
|
heroTitle: {
|
|
...FONTS.h1,
|
|
color: COLORS.background,
|
|
textAlign: 'center',
|
|
marginBottom: SIZES.base,
|
|
},
|
|
heroSubtitle: {
|
|
...FONTS.body,
|
|
color: COLORS.background,
|
|
textAlign: 'center',
|
|
marginBottom: SIZES.margin * 2,
|
|
opacity: 0.9,
|
|
},
|
|
bookNowButton: {
|
|
backgroundColor: COLORS.background,
|
|
paddingHorizontal: SIZES.padding * 2,
|
|
paddingVertical: SIZES.padding,
|
|
borderRadius: SIZES.radius,
|
|
cursor: 'pointer',
|
|
},
|
|
bookNowButtonPressed: {
|
|
opacity: 0.8,
|
|
},
|
|
bookNowText: {
|
|
...FONTS.body,
|
|
color: COLORS.primary,
|
|
fontWeight: 'bold',
|
|
},
|
|
section: {
|
|
margin: SIZES.margin,
|
|
},
|
|
sectionHeader: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: SIZES.margin,
|
|
},
|
|
sectionTitle: {
|
|
...FONTS.h2,
|
|
color: COLORS.text,
|
|
},
|
|
seeAllText: {
|
|
...FONTS.body,
|
|
color: COLORS.primary,
|
|
},
|
|
pressed: {
|
|
opacity: 0.7,
|
|
},
|
|
promotionsList: {
|
|
paddingRight: SIZES.padding,
|
|
},
|
|
promotionCard: {
|
|
width: 280,
|
|
height: 160,
|
|
marginRight: SIZES.margin,
|
|
borderRadius: SIZES.radius,
|
|
overflow: 'hidden',
|
|
...SHADOWS.medium,
|
|
cursor: 'pointer',
|
|
},
|
|
promotionCardPressed: {
|
|
opacity: 0.9,
|
|
},
|
|
promotionImage: {
|
|
width: '100%',
|
|
height: '100%',
|
|
resizeMode: 'cover',
|
|
},
|
|
promotionOverlay: {
|
|
position: 'absolute',
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
padding: SIZES.padding,
|
|
justifyContent: 'flex-end',
|
|
},
|
|
promotionTitle: {
|
|
...FONTS.h3,
|
|
color: COLORS.text,
|
|
marginBottom: SIZES.base / 2,
|
|
},
|
|
promotionDescription: {
|
|
...FONTS.caption,
|
|
color: COLORS.text,
|
|
marginBottom: SIZES.base,
|
|
opacity: 0.9,
|
|
},
|
|
promotionDiscount: {
|
|
...FONTS.h3,
|
|
color: COLORS.accent,
|
|
fontWeight: 'bold',
|
|
},
|
|
servicesRow: {
|
|
justifyContent: 'space-between',
|
|
},
|
|
});
|
|
|
|
export default HomeScreen;
|