diff --git a/src/context/AppContext.tsx b/src/context/AppContext.tsx index b05cc34..f9ecdf1 100644 --- a/src/context/AppContext.tsx +++ b/src/context/AppContext.tsx @@ -95,10 +95,33 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { .from('profiles') .select('shop_id, role, name, fcm_token, shop_name') .eq('id', authUser.id) - .single(); + .maybeSingle(); - const role = (prof?.role as any) || authUser.user_metadata?.role || 'cliente'; - const shopId = prof?.shop_id || (role === 'barbearia' ? authUser.id : undefined); + if (profErr) { + console.warn('Erro ao carregar perfil:', profErr.message); + } + + const metadataRole = authUser.user_metadata?.role; + const profileRole = prof?.role; + const hasBarberMetadata = metadataRole === 'barbearia'; + const hasBarberProfile = profileRole === 'barbearia'; + const hasShopAssociation = Boolean(prof?.shop_id); + + const { data: ownedShop } = await supabase + .from('shops') + .select('id') + .or(`id.eq.${authUser.id},owner_id.eq.${authUser.id}`) + .maybeSingle(); + + const role: User['role'] = + hasBarberProfile || hasBarberMetadata || hasShopAssociation || ownedShop + ? 'barbearia' + : 'cliente'; + + const shopId = + prof?.shop_id || + ownedShop?.id || + (role === 'barbearia' ? authUser.id : undefined); const nextUser: User = { id: authUser.id, @@ -110,6 +133,13 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { fcmToken: prof?.fcm_token || undefined, }; + if (role === 'barbearia' && shopId && profileRole !== 'barbearia') { + await supabase + .from('profiles') + .update({ role: 'barbearia', shop_id: shopId }) + .eq('id', authUser.id); + } + // If it's a barber and the shop record doesn't exist, create it (matching web logic) if (role === 'barbearia' && shopId) { const { data: existingShop } = await supabase.from('shops').select('id').eq('id', shopId).single(); diff --git a/src/pages/Explore.tsx b/src/pages/Explore.tsx index 0060910..34d5cc2 100644 --- a/src/pages/Explore.tsx +++ b/src/pages/Explore.tsx @@ -16,14 +16,6 @@ export default function Explore() { const [query, setQuery] = useState(''); const [filter, setFilter] = useState<'todas' | 'top' | 'servicos'>('todas'); - const categories = useMemo(() => [ - { id: 'corte', label: 'Cortes', icon: 'cut-outline' as const, query: 'corte' }, - { id: 'barba', label: 'Barba', icon: 'sparkles-outline' as const, query: 'barba' }, - { id: 'lavagem', label: 'Lavagem', icon: 'water-outline' as const, query: 'lavar' }, - { id: 'tratamento', label: 'Tratamentos', icon: 'leaf-outline' as const, query: 'tratamento' }, - { id: 'rapido', label: 'Expresso', icon: 'flash-outline' as const, query: 'rápido' }, - ], []); - const filtered = useMemo(() => { const normalized = query.trim().toLowerCase(); return [...shops] @@ -44,12 +36,12 @@ export default function Explore() { const featuredShops = filtered.slice(0, 3); - const handleCategoryPress = (catQuery: string) => { - if (query.toLowerCase() === catQuery.toLowerCase()) { - setQuery(''); - } else { - setQuery(catQuery); + const goToProfile = () => { + if (!user) { + navigation.navigate('Login'); + return; } + navigation.getParent()?.navigate('ProfileTab' as never); }; return ( @@ -67,13 +59,7 @@ export default function Explore() { { - if (user) { - navigation.navigate('ProfileTab' as any); - } else { - navigation.navigate('Login' as any); - } - }} + onPress={goToProfile} > @@ -120,58 +106,6 @@ export default function Explore() { - {/* Categories Quick Grid (hidden for now) */} - {false && ( - - Categorias Populares - - {categories.map((cat) => { - const isSelected = query.toLowerCase() === cat.query.toLowerCase(); - return ( - handleCategoryPress(cat.query)} - activeOpacity={0.75} - > - - - - {cat.label} - - ); - })} - - - )} - - {/* Promo Hero Banner (hidden for now) */} - {false && ( - - - - CAMPANHA - - Estilo Premium com 15% OFF - Agenda a tua primeira marcação online hoje e garante o teu desconto. - handleCategoryPress('corte')} - > - Ver Cortes ⚡ - - - - - - - )} - {!shopsReady ? ( diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx index 37b5e4e..f810e52 100644 --- a/src/pages/Profile.tsx +++ b/src/pages/Profile.tsx @@ -48,11 +48,6 @@ export default function Profile() { } = useApp(); const [activeTab, setActiveTab] = useState(user?.role === 'barbearia' ? 'agenda_pessoal' : 'agenda'); - useEffect(() => { - if (user) { - setActiveTab(user.role === 'barbearia' ? 'agenda_pessoal' : 'agenda'); - } - }, [user?.role]); const [reviewedAppointments, setReviewedAppointments] = useState>(new Set()); const [reviewTarget, setReviewTarget] = useState<{ appointmentId: string; shopId: string; shopName: string } | null>(null); const [rating, setRating] = useState(0); @@ -207,200 +202,170 @@ export default function Profile() { {/* Dynamic Tab Bar */} - {isBarber ? ( - [ - ['agenda_pessoal', 'Agenda Global'], - ['reviews', 'Avaliações'], - ['estatisticas', 'Resumo'], - ].map(([id, label]) => ( - setActiveTab(id)} - style={[styles.tabItem, activeTab === id && styles.tabActive]} - activeOpacity={0.8} - > - {label} - - )) - ) : ( - [ - ['agenda', 'Marcações'], - ['favoritos', 'Favoritos'], - ['compras', 'Compras'], - ].map(([id, label]) => ( - setActiveTab(id)} - style={[styles.tabItem, activeTab === id && styles.tabActive]} - activeOpacity={0.8} - > - {label} - - )) - )} + {(isBarber + ? [ + ['agenda_pessoal', 'Agenda Global'], + ['reviews', 'Avaliações'], + ['estatisticas', 'Resumo'], + ] + : [ + ['agenda', 'Marcações'], + ['favoritos', 'Favoritos'], + ['compras', 'Compras'], + ] + ).map(([id, label]) => ( + setActiveTab(id)} + style={[styles.tabItem, activeTab === id && styles.tabActive]} + activeOpacity={0.8} + > + {label} + + ))} {/* Tab Content Area */} - {/* CLIENTE TABS */} - {!isBarber && ( - - {activeTab === 'agenda' && ( - - - - As Minhas Marcações - - - {myAppointments.length > 0 ? ( - myAppointments.map((appt) => { - const shop = shops.find((s) => s.id === appt.shopId); - const canReview = appt.status === 'concluido' && !reviewedAppointments.has(appt.id); - const dateParts = appt.date.split(' '); - const day = dateParts[0].split('-')[2]; - const month = new Date(dateParts[0]).toLocaleString('pt-PT', { month: 'short' }).toUpperCase(); + {/* CLIENTE: Marcações */} + {!isBarber && activeTab === 'agenda' && ( + + {myAppointments.length > 0 ? ( + myAppointments.map((appt) => { + const shop = shops.find((s) => s.id === appt.shopId); + const canReview = appt.status === 'concluido' && !reviewedAppointments.has(appt.id); + const dateParts = appt.date.split(' '); + const day = dateParts[0].split('-')[2]; + const month = new Date(dateParts[0]).toLocaleString('pt-PT', { month: 'short' }).toUpperCase(); + + return ( + + + + {month} + {day} + - return ( - - - - {month} - {day} - - - - {shop?.name || 'Barbearia'} - - - {dateParts[1]} • {currency(appt.total)} - - - - - {statusLabel[appt.status]} - - - - {canReview && ( - - )} - - ); - }) - ) : ( - - - + + {shop?.name || 'Barbearia'} + + + {dateParts[1]} • {currency(appt.total)} + + + + + {statusLabel[appt.status]} - Sem marcações agendadas. - - )} - - - )} - - {activeTab === 'favoritos' && ( - - - - Espaços Favoritos - - - {favoriteShops.length > 0 ? ( - favoriteShops.map((s) => ( - navigation.navigate('ShopDetails', { shopId: s.id })} - activeOpacity={0.9} + + {canReview && ( + + )} + + ); + }) + ) : ( + + + + Sem marcações agendadas. + )} + + )} - {activeTab === 'compras' && ( - - - - As Minhas Compras - - - {myOrders.length > 0 ? ( - myOrders.map((order) => { - const shop = shops.find((s) => s.id === order.shopId); - return ( - - - - {shop?.name || 'Barbearia'} - - - - {new Date(order.createdAt).toLocaleDateString('pt-PT')} • {order.items.length} item(s) - - - - - {currency(order.total)} - - {statusLabel[order.status]} - - - - - ); - }) - ) : ( - - - + {/* CLIENTE: Favoritos */} + {!isBarber && activeTab === 'favoritos' && ( + + {favoriteShops.length > 0 ? ( + favoriteShops.map((s) => ( + navigation.navigate('ShopDetails', { shopId: s.id })} + activeOpacity={0.9} + > + + + + {s.name} + + + + {s.address && s.address !== 'Endereço a definir' ? s.address : 'Morada por definir'} + - Ainda não tens compras efetuadas. - )} + + + {(s.rating || 0).toFixed(1)} + + + + )) + ) : ( + + + + Ainda não tens favoritos. + + )} + + )} + + {/* CLIENTE: Compras */} + {!isBarber && activeTab === 'compras' && ( + + {myOrders.length > 0 ? ( + myOrders.map((order) => { + const shop = shops.find((s) => s.id === order.shopId); + return ( + + + + {shop?.name || 'Barbearia'} + + + + {new Date(order.createdAt).toLocaleDateString('pt-PT')} • {order.items.length} item(s) + + + + + {currency(order.total)} + + {statusLabel[order.status]} + + + + + ); + }) + ) : ( + + + + + Ainda não tens compras efetuadas. )} )} {/* BARBER TABS */} - {activeTab === 'agenda_pessoal' && ( + {isBarber && activeTab === 'agenda_pessoal' && ( @@ -449,7 +414,7 @@ export default function Profile() { )} - {activeTab === 'reviews' && ( + {isBarber && activeTab === 'reviews' && ( {shopReviews.length > 0 ? ( shopReviews.map((r) => ( @@ -479,7 +444,7 @@ export default function Profile() { )} - {activeTab === 'estatisticas' && ( + {isBarber && activeTab === 'estatisticas' && ( diff --git a/src/pages/ShopDetails.tsx b/src/pages/ShopDetails.tsx index 0f1d368..daf5578 100644 --- a/src/pages/ShopDetails.tsx +++ b/src/pages/ShopDetails.tsx @@ -70,7 +70,7 @@ export default function ShopDetails() { Alert.alert('Sucesso', 'Produto adicionado ao carrinho.'); }; - const schedule = (shop.schedule || defaultSchedule).filter((s: any) => !s.isException); + const schedule = (shop.schedule || defaultSchedule).filter(s => !s.isException); const currentDayIndex = new Date().getDay() === 0 ? 6 : new Date().getDay() - 1; const isFav = isFavorite(shop.id);