- professional_profile_view: gradient header card with avatar overlay, sectioned cards (service modality, address, rate, payment chips, schedule), animated payment method chips, full-width save button with loading state - sidebar: teal-dark background in pro mode vs navy in user mode, animated mode indicator pill, muted toggle button in pro mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
275 lines
11 KiB
Dart
275 lines
11 KiB
Dart
import 'package:prosapp_web_app/models/pro_state.dart';
|
|
import 'package:prosapp_web_app/providers/auth_provider.dart';
|
|
import 'package:prosapp_web_app/providers/professional_provider.dart';
|
|
import 'package:prosapp_web_app/providers/services_provider.dart';
|
|
import 'package:prosapp_web_app/providers/sidemenu_provider.dart';
|
|
import 'package:prosapp_web_app/router/router.dart';
|
|
import 'package:prosapp_web_app/services/navigation_service.dart';
|
|
import 'package:prosapp_web_app/services/notifications_service.dart';
|
|
import 'package:prosapp_web_app/ui/shared/widgets/menu_item.dart';
|
|
import 'package:prosapp_web_app/ui/shared/widgets/text_separator.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:prosapp_web_app/ui/shared/widgets/logo.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
class Sidebar extends StatelessWidget {
|
|
const Sidebar({super.key});
|
|
|
|
void navigateTo(String routeName) {
|
|
NavigationService.replaceTo(routeName);
|
|
SideMenuProvider.closeMenu();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final sideMenuProvider = Provider.of<SideMenuProvider>(context);
|
|
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
|
final professionalProvider = Provider.of<ProfessionalProvider>(context);
|
|
|
|
return Container(
|
|
width: 220,
|
|
height: double.infinity,
|
|
decoration: buildBoxDecoration(professionalProvider.isProModeActive),
|
|
child: ListView(
|
|
physics: const ClampingScrollPhysics(),
|
|
children: [
|
|
const Logo(),
|
|
const SizedBox(height: 8),
|
|
|
|
// Mode indicator pill
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
|
child: AnimatedContainer(
|
|
duration: const Duration(milliseconds: 300),
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
|
decoration: BoxDecoration(
|
|
color: professionalProvider.isProModeActive
|
|
? const Color(0xFF16A34A).withOpacity(0.18)
|
|
: const Color(0xFF42A4EF).withOpacity(0.14),
|
|
border: Border.all(
|
|
color: professionalProvider.isProModeActive
|
|
? const Color(0xFF22C55E).withOpacity(0.5)
|
|
: const Color(0xFF42A4EF).withOpacity(0.4),
|
|
width: 1,
|
|
),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(
|
|
professionalProvider.isProModeActive
|
|
? Icons.work_outline
|
|
: Icons.person_outline,
|
|
size: 13,
|
|
color: professionalProvider.isProModeActive
|
|
? const Color(0xFF4ADE80)
|
|
: const Color(0xFF7DD3FC),
|
|
),
|
|
const SizedBox(width: 6),
|
|
Text(
|
|
professionalProvider.isProModeActive
|
|
? 'Modo Profesional'
|
|
: 'Modo Usuario',
|
|
style: TextStyle(
|
|
fontSize: 11,
|
|
fontWeight: FontWeight.w600,
|
|
color: professionalProvider.isProModeActive
|
|
? const Color(0xFF4ADE80)
|
|
: const Color(0xFF7DD3FC),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
|
|
if (professionalProvider.isProModeActive) ...[
|
|
const TextSeparator(text: 'Profesional'),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.profileRoute ||
|
|
sideMenuProvider.currentPage == Flurorouter.professionalProfileRoute,
|
|
text: 'Perfil',
|
|
icon: Icons.person_outlined,
|
|
onPressed: () {
|
|
if (professionalProvider.isProModeActive) {
|
|
navigateTo(Flurorouter.professionalProfileRoute);
|
|
} else {
|
|
navigateTo(Flurorouter.profileRoute);
|
|
}
|
|
},
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.professionalServicesRequestsRoute,
|
|
text: 'Mis solicitudes',
|
|
icon: Icons.room_service_outlined,
|
|
onPressed: () {
|
|
Provider.of<ServicesProvider>(context, listen: false).clearServices();
|
|
navigateTo(Flurorouter.professionalServicesRequestsRoute);
|
|
},
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.professionalServicesRoute,
|
|
text: 'Mis servicios',
|
|
icon: Icons.list_alt_outlined,
|
|
onPressed: () {
|
|
Provider.of<ServicesProvider>(context, listen: false).clearServices();
|
|
navigateTo(Flurorouter.professionalServicesRoute);
|
|
},
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.professionalServicesHistoryRoute,
|
|
text: 'Historial',
|
|
icon: Icons.restore_outlined,
|
|
onPressed: () {
|
|
Provider.of<ServicesProvider>(context, listen: false).clearServices();
|
|
navigateTo(Flurorouter.professionalServicesHistoryRoute);
|
|
},
|
|
),
|
|
MenuItem(
|
|
text: 'Calendario',
|
|
icon: Icons.calendar_month_outlined,
|
|
onPressed: () => navigateTo(Flurorouter.professionalCalendarRoute),
|
|
),
|
|
] else ...[
|
|
const TextSeparator(text: 'Usuario'),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.profileRoute,
|
|
text: 'Perfil',
|
|
icon: Icons.person_outlined,
|
|
onPressed: () => navigateTo(Flurorouter.profileRoute),
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.dashboardRoute,
|
|
text: 'Solicitar',
|
|
icon: Icons.room_service_outlined,
|
|
onPressed: () => navigateTo(Flurorouter.dashboardRoute),
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.userServicesRoute,
|
|
text: 'Mis servicios',
|
|
icon: Icons.list_alt_outlined,
|
|
onPressed: () {
|
|
Provider.of<ServicesProvider>(context, listen: false).clearServices();
|
|
navigateTo(Flurorouter.userServicesRoute);
|
|
},
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.userServicesHistoryRoute,
|
|
text: 'Historial',
|
|
icon: Icons.restore_outlined,
|
|
onPressed: () {
|
|
Provider.of<ServicesProvider>(context, listen: false).clearServices();
|
|
navigateTo(Flurorouter.userServicesHistoryRoute);
|
|
},
|
|
),
|
|
MenuItem(
|
|
isActive: sideMenuProvider.currentPage == Flurorouter.supportRoute,
|
|
text: 'Soporte',
|
|
icon: Icons.support_agent_outlined,
|
|
onPressed: () => navigateTo(Flurorouter.supportRoute),
|
|
),
|
|
],
|
|
|
|
const SizedBox(height: 16),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.click,
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
if (authProvider.user?.name == null ||
|
|
authProvider.user?.name == '') {
|
|
NotificationsService.showSnackBarError('Primero completa tu perfil');
|
|
navigateTo(Flurorouter.profileRoute);
|
|
return;
|
|
}
|
|
if (authProvider.user?.proState == ProState.active) {
|
|
professionalProvider.toggleProMode();
|
|
if (professionalProvider.isProModeActive) {
|
|
navigateTo(Flurorouter.professionalServicesRequestsRoute);
|
|
} else {
|
|
navigateTo(Flurorouter.dashboardRoute);
|
|
}
|
|
} else {
|
|
navigateTo(Flurorouter.requestProfessionalRoute);
|
|
}
|
|
},
|
|
child: AnimatedContainer(
|
|
duration: const Duration(milliseconds: 300),
|
|
padding: const EdgeInsets.symmetric(vertical: 11),
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: professionalProvider.isProModeActive
|
|
? [const Color(0xFF374151), const Color(0xFF1F2937)]
|
|
: [const Color(0xFF42A4EF), const Color(0xFF1565C0)],
|
|
),
|
|
borderRadius: BorderRadius.circular(10),
|
|
border: professionalProvider.isProModeActive
|
|
? Border.all(
|
|
color: Colors.white.withOpacity(0.1), width: 1)
|
|
: null,
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
professionalProvider.isProModeActive
|
|
? Icons.person_outlined
|
|
: Icons.work_outline,
|
|
color: professionalProvider.isProModeActive
|
|
? Colors.white70
|
|
: Colors.white,
|
|
size: 16,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
professionalProvider.isProModeActive
|
|
? 'Ir a modo Usuario'
|
|
: 'Ir a modo Profesional',
|
|
style: TextStyle(
|
|
color: professionalProvider.isProModeActive
|
|
? Colors.white70
|
|
: Colors.white,
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
const TextSeparator(text: 'Sesion'),
|
|
MenuItem(
|
|
text: 'Cerrar sesion',
|
|
icon: Icons.exit_to_app_outlined,
|
|
onPressed: () => authProvider.logout(),
|
|
),
|
|
const SizedBox(height: 20),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
BoxDecoration buildBoxDecoration(bool isProMode) => BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: isProMode
|
|
? const [Color(0xFF0A1F18), Color(0xFF061510)]
|
|
: const [Color(0xFF0D1B3E), Color(0xFF0A1628)],
|
|
),
|
|
boxShadow: const [
|
|
BoxShadow(
|
|
color: Colors.black38,
|
|
blurRadius: 12,
|
|
offset: Offset(2, 0),
|
|
),
|
|
],
|
|
);
|
|
}
|