From deb51bbedb0b78cd03ef5bde19a375644e74af01 Mon Sep 17 00:00:00 2001 From: 230417 <230417@epvc.pt> Date: Tue, 16 Jun 2026 16:59:10 +0100 Subject: [PATCH] feat: redesign client profile layout and update booking redirect --- src/pages/Booking.tsx | 2 +- src/pages/Profile.tsx | 484 ++++++++++++++++++++++++++++-------------- 2 files changed, 331 insertions(+), 155 deletions(-) diff --git a/src/pages/Booking.tsx b/src/pages/Booking.tsx index eee1484..55425b1 100644 --- a/src/pages/Booking.tsx +++ b/src/pages/Booking.tsx @@ -64,7 +64,7 @@ export default function Booking() { }); if (appt) { Alert.alert('Sucesso', 'O seu agendamento foi confirmado.'); - navigation.navigate('ProfileTab' as never); + navigation.navigate('ExploreTab' as never); } }; diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx index e833143..739f536 100644 --- a/src/pages/Profile.tsx +++ b/src/pages/Profile.tsx @@ -199,168 +199,181 @@ export default function Profile() { )} - {/* Dynamic Tab Bar */} - - - {(isBarber ? [ - ['agenda_pessoal', 'Agenda Global'], - ['reviews', 'Avaliações'], - ['estatisticas', 'Resumo'], - ] : [ - ['agenda', 'Minha Agenda'], - ['favoritos', 'Favoritos'], - ['pedidos', 'Compras'], - ]).map(([id, label]) => ( - setActiveTab(id)} - style={[styles.tabItem, activeTab === id && styles.tabActive]} - activeOpacity={0.8} - > - {label} - - ))} - - + {/* Dynamic Tab Bar (Only for Barber) */} + {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} + + ))} + + + )} {/* Tab Content Area */} - {/* CLIENTE TABS */} - {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 ( - - - {/* tear-off style calendar block */} - - - {day} - {month} - - - - {shop?.name || 'Barbearia'} - - - {dateParts[1]} • {currency(appt.total)} - - - - - - {statusLabel[appt.status]} - - + {/* CLIENTE VERTICAL LAYOUT */} + {!isBarber && ( + + + {/* Minha Agenda Section */} + + + + 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(); - {canReview && ( - - )} - - ); - }) - ) : ( - - - Sem marcações agendadas. - - )} - - )} - - {activeTab === 'favoritos' && ( - - {favoriteShops.length > 0 ? ( - favoriteShops.map((s) => ( - navigation.navigate('ShopDetails', { shopId: s.id })} - activeOpacity={0.9} - > - - - {s.name.charAt(0).toUpperCase()} - - - {s.name} - - - - {s.address && s.address !== 'Endereço a definir' ? s.address : 'Morada por definir'} - - - - - - {(s.rating || 0).toFixed(1)} - - - - )) - ) : ( - - - Ainda não tens favoritos. - - )} - - )} - - {activeTab === 'pedidos' && ( - - {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) - + return ( + + + + {month} + {day} + + + + {shop?.name || 'Barbearia'} + + + {dateParts[1]} • {currency(appt.total)} + + + + + {statusLabel[appt.status]} + - - {currency(order.total)} + + {canReview && ( + + )} + + ); + }) + ) : ( + + + - - - {statusLabel[order.status]} - - - ); - }) - ) : ( - - - Ainda não tens compras. + Sem marcações agendadas. + + + )} - )} + + + {/* Favoritos Section */} + + + + Espaços 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'} + + + + + + {(s.rating || 0).toFixed(1)} + + + + )) + ) : ( + + + + + Ainda não tens favoritos. + + )} + + + + {/* Compras Section */} + + + + 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]} + + + + + ); + }) + ) : ( + + + + + Ainda não tens compras efetuadas. + + )} + + )} @@ -1086,6 +1099,169 @@ const styles = StyleSheet.create({ borderTopColor: 'rgba(15,118,110,0.08)', alignItems: 'center', }, + /* ── Premium Client Layout Styles ── */ + clientSectionHeader: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + marginBottom: 16, + paddingHorizontal: 4, + }, + clientSectionTitle: { + color: colors.text, + fontSize: 18, + fontWeight: '900', + letterSpacing: -0.3, + }, + agendaCardPremium: { + padding: 16, + backgroundColor: colors.surface, + borderRadius: radius.lg, + borderWidth: 1, + borderColor: 'rgba(15,118,110,0.06)', + gap: 16, + ...shadows.soft, + }, + calendarBlockPremium: { + width: 60, + height: 60, + backgroundColor: colors.primarySoft, + borderRadius: radius.md, + alignItems: 'center', + justifyContent: 'center', + borderWidth: 1, + borderColor: 'rgba(15,118,110,0.1)', + }, + dateMonthPremium: { + color: colors.primaryDark, + fontSize: 11, + fontWeight: '800', + textTransform: 'uppercase', + }, + dateDayPremium: { + color: colors.primary, + fontSize: 22, + fontWeight: '900', + marginTop: -2, + }, + agendaShopPremium: { + color: colors.text, + fontSize: 16, + fontWeight: '800', + }, + agendaTimePremium: { + color: colors.textMuted, + fontSize: 13, + fontWeight: '600', + }, + statusTagPremium: { + paddingHorizontal: 10, + paddingVertical: 4, + borderRadius: radius.pill, + alignSelf: 'flex-start', + }, + statusTextPremium: { + fontSize: 10, + fontWeight: '800', + textTransform: 'uppercase', + }, + emptyBlockPremium: { + alignItems: 'center', + justifyContent: 'center', + paddingVertical: 32, + backgroundColor: colors.surface, + borderRadius: radius.lg, + borderWidth: 1, + borderColor: 'rgba(15,118,110,0.04)', + gap: 12, + }, + emptyIconCircle: { + width: 56, + height: 56, + borderRadius: 28, + backgroundColor: colors.background, + alignItems: 'center', + justifyContent: 'center', + }, + emptyTxtPremium: { + color: colors.textMuted, + fontWeight: '600', + fontSize: 14, + marginBottom: 4, + }, + shopCardPremium: { + flexDirection: 'row', + alignItems: 'center', + padding: 12, + backgroundColor: colors.surface, + borderRadius: radius.lg, + borderWidth: 1, + borderColor: 'rgba(15,118,110,0.06)', + gap: 12, + }, + shopImageMini: { + width: 50, + height: 50, + borderRadius: radius.md, + backgroundColor: colors.surfaceMuted, + }, + shopCardBodyPremium: { + flex: 1, + justifyContent: 'center', + }, + shopNamePremium: { + color: colors.text, + fontSize: 15, + fontWeight: '800', + marginBottom: 2, + }, + shopAddrPremium: { + color: colors.textMuted, + fontSize: 12, + fontWeight: '500', + flex: 1, + }, + shopRatingBadgePremium: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: colors.accentSoft, + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: radius.pill, + gap: 4, + }, + shopRatingTextPremium: { + color: '#7a4310', + fontSize: 12, + fontWeight: '900', + }, + orderCardPremium: { + padding: 16, + backgroundColor: colors.surface, + borderRadius: radius.lg, + borderWidth: 1, + borderColor: 'rgba(15,118,110,0.06)', + }, + orderTopPremium: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'flex-start', + }, + orderShopPremium: { + color: colors.text, + fontSize: 15, + fontWeight: '800', + }, + orderMetaPremium: { + color: colors.textMuted, + fontSize: 13, + fontWeight: '500', + }, + orderTotalPremium: { + color: colors.primary, + fontSize: 16, + fontWeight: '900', + }, logoutButtonPremium: { flexDirection: 'row', alignItems: 'center',