State Is Authenticated

This commit is contained in:
efrilm 2025-09-18 12:25:48 +07:00
parent 3c596461c6
commit a5d66c63b7
4 changed files with 522 additions and 453 deletions

View File

@ -1,13 +1,26 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/auth/auth_bloc.dart';
import '../../router/app_router.gr.dart'; import '../../router/app_router.gr.dart';
import 'widgets/bottom_navbar.dart'; import 'widgets/bottom_navbar.dart';
@RoutePage() @RoutePage()
class MainPage extends StatelessWidget { class MainPage extends StatefulWidget {
const MainPage({super.key}); const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
@override
initState() {
super.initState();
context.read<AuthBloc>().add(const AuthEvent.fetchCurrentUser());
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AutoTabsRouter.pageView( return AutoTabsRouter.pageView(

View File

@ -1,5 +1,7 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../../application/auth/auth_bloc.dart';
import '../../../../../router/app_router.gr.dart'; import '../../../../../router/app_router.gr.dart';
import 'feature_card.dart'; import 'feature_card.dart';
@ -8,37 +10,43 @@ class HomeFeatureSection extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return BlocBuilder<AuthBloc, AuthState>(
padding: const EdgeInsets.all(16), builder: (context, state) {
child: Row( return Container(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, padding: const EdgeInsets.all(16),
children: [ child: Row(
HomeFeatureCard( mainAxisAlignment: MainAxisAlignment.spaceEvenly,
icon: Icons.card_giftcard, children: [
title: 'Reward', HomeFeatureCard(
iconColor: const Color(0xFF1976D2), icon: Icons.card_giftcard,
onTap: () => context.router.push(RewardRoute()), title: 'Reward',
iconColor: const Color(0xFF1976D2),
onTap: () => context.router.push(RewardRoute()),
),
HomeFeatureCard(
icon: Icons.casino,
title: 'Undian',
iconColor: const Color(0xFF7B1FA2),
onTap: () => context.router.push(DrawRoute()),
),
HomeFeatureCard(
icon: Icons.store,
title: 'Merchant',
iconColor: const Color(0xFF388E3C),
onTap: () => context.router.push(MerchantRoute()),
),
HomeFeatureCard(
icon: Icons.blur_circular,
title: 'Wheels',
iconColor: const Color(0xFF388E3C),
onTap: () => state.isAuthenticated
? context.router.push(FerrisWheelRoute())
: context.router.push(OnboardingRoute()),
),
],
), ),
HomeFeatureCard( );
icon: Icons.casino, },
title: 'Undian',
iconColor: const Color(0xFF7B1FA2),
onTap: () => context.router.push(DrawRoute()),
),
HomeFeatureCard(
icon: Icons.store,
title: 'Merchant',
iconColor: const Color(0xFF388E3C),
onTap: () => context.router.push(MerchantRoute()),
),
HomeFeatureCard(
icon: Icons.blur_circular,
title: 'Wheels',
iconColor: const Color(0xFF388E3C),
onTap: () => context.router.push(FerrisWheelRoute()),
),
],
),
); );
} }
} }

View File

@ -1,6 +1,8 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../../application/auth/auth_bloc.dart';
import '../../../../../../common/theme/theme.dart'; import '../../../../../../common/theme/theme.dart';
import '../../../../../router/app_router.gr.dart'; import '../../../../../router/app_router.gr.dart';
@ -9,137 +11,160 @@ class HomePointCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return BlocBuilder<AuthBloc, AuthState>(
onTap: () => context.router.push(PoinRoute()), builder: (context, state) {
child: Container( return GestureDetector(
decoration: BoxDecoration( onTap: () => state.isAuthenticated
color: AppColor.white, ? context.router.push(PoinRoute())
borderRadius: BorderRadius.circular(16), : context.router.push(OnboardingRoute()),
boxShadow: [ child: Container(
BoxShadow( decoration: BoxDecoration(
color: AppColor.textLight.withOpacity(0.15), color: AppColor.white,
spreadRadius: 0, borderRadius: BorderRadius.circular(16),
blurRadius: 20, boxShadow: [
offset: const Offset(0, 8), BoxShadow(
color: AppColor.textLight.withOpacity(0.15),
spreadRadius: 0,
blurRadius: 20,
offset: const Offset(0, 8),
),
],
), ),
], child: Stack(
), children: [
child: Stack( _buildCoinPattern(),
children: [ Padding(
_buildCoinPattern(), padding: const EdgeInsets.all(16),
Padding( child: Column(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [ children: [
Column( Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( !state.isAuthenticated
padding: const EdgeInsets.symmetric( ? Expanded(
horizontal: 16, child: Text(
vertical: 10, 'Hi, Selamat Datang Di Enaklo',
), style: AppStyle.md.copyWith(
decoration: BoxDecoration( color: AppColor.primary,
color: AppColor.primary, fontWeight: FontWeight.w600,
borderRadius: BorderRadius.circular(25), ),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.stars,
color: AppColor.white,
size: 18,
),
SizedBox(width: 8),
Text(
'148 Poin',
style: AppStyle.md.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w600,
), ),
)
: Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
decoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(
25,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.stars,
color: AppColor.white,
size: 18,
),
SizedBox(width: 8),
Text(
'148 Poin',
style: AppStyle.md.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w600,
),
),
],
),
),
const SizedBox(height: 4),
Text(
'Kamu punya 148 poin',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontSize: 11,
),
),
],
),
),
SizedBox(
width: 120,
height: 40,
child: Stack(
children: [
_buildCoin(
right: 0,
top: 0,
size: 24,
color: Colors.amber,
),
_buildCoin(
right: 20,
top: 8,
size: 20,
color: Colors.orange,
),
_buildCoin(
right: 40,
top: 4,
size: 18,
color: Colors.amber,
),
_buildCoin(
right: 60,
top: 12,
size: 16,
color: Colors.orange,
),
_buildCoin(
right: 80,
top: 8,
size: 14,
color: Colors.amber,
), ),
], ],
), ),
), ),
const SizedBox(height: 4), ],
),
const SizedBox(height: 12),
Row(
children: [
Text( Text(
'Kamu punya 148 poin', state.isAuthenticated
? 'Tukarkan poinmu dengan hadiah menarik'
: 'Silahkan login untuk tukarkan poinmu',
style: AppStyle.sm.copyWith( style: AppStyle.sm.copyWith(
color: AppColor.textSecondary, color: AppColor.textPrimary,
fontSize: 11, fontSize: 13,
fontWeight: FontWeight.w500,
), ),
), ),
const Spacer(),
Icon(
Icons.arrow_forward_ios,
color: AppColor.textSecondary,
size: 16,
),
], ],
), ),
const Spacer(),
SizedBox(
width: 120,
height: 40,
child: Stack(
children: [
_buildCoin(
right: 0,
top: 0,
size: 24,
color: Colors.amber,
),
_buildCoin(
right: 20,
top: 8,
size: 20,
color: Colors.orange,
),
_buildCoin(
right: 40,
top: 4,
size: 18,
color: Colors.amber,
),
_buildCoin(
right: 60,
top: 12,
size: 16,
color: Colors.orange,
),
_buildCoin(
right: 80,
top: 8,
size: 14,
color: Colors.amber,
),
],
),
),
], ],
), ),
const SizedBox(height: 12), ),
Row( ],
children: [
Text(
'Tukarkan poinmu dengan hadiah menarik',
style: AppStyle.sm.copyWith(
color: AppColor.textPrimary,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
const Spacer(),
Icon(
Icons.arrow_forward_ios,
color: AppColor.textSecondary,
size: 16,
),
],
),
],
),
), ),
], ),
), );
), },
); );
} }

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../application/auth/auth_bloc.dart';
import '../../../../../application/auth/logout_form/logout_form_bloc.dart'; import '../../../../../application/auth/logout_form/logout_form_bloc.dart';
import '../../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../../injection.dart'; import '../../../../../injection.dart';
@ -20,7 +21,7 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
() => null, () => null,
(either) => either.fold( (either) => either.fold(
(f) => AppFlushbar.showAuthFailureToast(context, f), (f) => AppFlushbar.showAuthFailureToast(context, f),
(_) => context.router.replaceAll([LoginRoute()]), (_) => context.router.replaceAll([OnboardingRoute()]),
), ),
); );
}, },
@ -28,341 +29,363 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
child: Scaffold( child: Scaffold(
backgroundColor: AppColor.background, backgroundColor: AppColor.background,
appBar: AppBar(title: Text('Profil'), automaticallyImplyLeading: false), appBar: AppBar(title: Text('Profil'), automaticallyImplyLeading: false),
body: SingleChildScrollView( body: BlocBuilder<AuthBloc, AuthState>(
child: Column( builder: (context, state) {
children: [ return SingleChildScrollView(
// Profile Header child: Column(
Container( children: [
width: double.infinity, // Profile Header
color: AppColor.white, Container(
padding: const EdgeInsets.all(20), width: double.infinity,
child: Column( color: AppColor.white,
children: [ padding: const EdgeInsets.all(20),
// Profile Avatar & Info child: Column(
GestureDetector( children: [
onTap: () => context.router.push(AccountMyRoute()), // Profile Avatar & Info
child: Container( GestureDetector(
decoration: BoxDecoration( onTap: () => state.isAuthenticated
gradient: LinearGradient( ? context.router.push(AccountMyRoute())
colors: AppColor.primaryGradient, : context.router.push(OnboardingRoute()),
begin: Alignment.topLeft, child: Container(
end: Alignment.bottomRight, decoration: BoxDecoration(
), gradient: LinearGradient(
borderRadius: BorderRadius.circular(16), colors: AppColor.primaryGradient,
), begin: Alignment.topLeft,
child: Stack( end: Alignment.bottomRight,
children: [
// Background Pattern
Positioned(
top: -20,
right: -20,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.1),
),
), ),
borderRadius: BorderRadius.circular(16),
), ),
Positioned( child: Stack(
top: 30, children: [
right: 20, // Background Pattern
child: Container( Positioned(
width: 40, top: -20,
height: 40, right: -20,
decoration: BoxDecoration( child: Container(
shape: BoxShape.circle, width: 80,
color: AppColor.white.withOpacity(0.08), height: 80,
), decoration: BoxDecoration(
), shape: BoxShape.circle,
), color: AppColor.white.withOpacity(0.1),
Positioned( ),
bottom: -10,
left: -10,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.06),
),
),
),
// Decorative Lines
Positioned(
top: 10,
left: -5,
child: Transform.rotate(
angle: 0.5,
child: Container(
width: 30,
height: 2,
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(1),
), ),
), ),
), Positioned(
), top: 30,
Positioned( right: 20,
bottom: 15, child: Container(
right: 10, width: 40,
child: Transform.rotate( height: 40,
angle: -0.5, decoration: BoxDecoration(
child: Container( shape: BoxShape.circle,
width: 25, color: AppColor.white.withOpacity(0.08),
height: 2, ),
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(1),
), ),
), ),
), Positioned(
), bottom: -10,
// Main Content left: -10,
Padding( child: Container(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
// Avatar
Container(
width: 60, width: 60,
height: 60, height: 60,
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColor.white,
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ color: AppColor.white.withOpacity(0.06),
BoxShadow(
color: AppColor.black.withOpacity(
0.1,
),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
), ),
child: Icon(
Icons.person,
size: 30,
color: AppColor.primary,
),
),
const SizedBox(width: 16),
// User Info
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'EFRIL',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.white,
letterSpacing: 0.5,
),
),
const SizedBox(height: 4),
Text(
'+6283873987851',
style: AppStyle.sm.copyWith(
color: AppColor.white.withOpacity(
0.9,
),
),
),
],
),
),
// Arrow Icon
Icon(
Icons.arrow_forward_ios,
color: AppColor.white,
size: 14,
),
],
),
),
],
),
),
),
],
),
),
const SizedBox(height: 8),
// Menu Items
Container(
color: AppColor.white,
child: Column(
children: [
_buildMenuItem(
icon: Icons.location_on_outlined,
title: 'Alamat Tersimpan',
onTap: () => context.router.push(AddressRoute()),
),
_buildMenuItem(
icon: Icons.payment_outlined,
title: 'Pembayaran',
onTap: () => context.router.push(PaymentRoute()),
),
_buildMenuItem(
icon: Icons.help_outline,
title: 'Pusat Bantuan',
onTap: () {},
),
_buildMenuItem(
icon: Icons.settings_outlined,
title: 'Pengaturan',
onTap: () {},
showDivider: false,
),
],
),
),
const SizedBox(height: 8),
// Legal & Privacy Section
Container(
color: AppColor.white,
child: Column(
children: [
_buildMenuItem(
icon: Icons.description_outlined,
title: 'Syarat dan Ketentuan',
onTap: () {},
),
_buildMenuItem(
icon: Icons.privacy_tip_outlined,
title: 'Kebijakan Privasi',
onTap: () {},
showDivider: false,
),
],
),
),
const SizedBox(height: 8),
// Customer Service Section
Container(
color: AppColor.white,
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Butuh Bantuan?',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.textPrimary,
),
),
const SizedBox(height: 8),
Text(
'Customer Service kami siap untuk membantu',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
const SizedBox(height: 16),
// WhatsApp Customer Service
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.backgroundLight,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.borderLight),
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(8),
),
child: Icon(
Icons.chat,
color: AppColor.white,
size: 20,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Enaklo Customer Service (chat only)',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
), ),
), ),
Text( // Decorative Lines
'0812-1111-8456', Positioned(
style: AppStyle.md.copyWith( top: 10,
fontWeight: FontWeight.w600, left: -5,
color: AppColor.success, child: Transform.rotate(
angle: 0.5,
child: Container(
width: 30,
height: 2,
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(1),
),
),
), ),
), ),
Positioned(
bottom: 15,
right: 10,
child: Transform.rotate(
angle: -0.5,
child: Container(
width: 25,
height: 2,
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(1),
),
),
),
),
// Main Content
Padding(
padding: const EdgeInsets.all(16.0),
child: !state.isAuthenticated
? Row(
children: [
Expanded(
child: Text(
'Silahkan Masuk',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.white,
letterSpacing: 0.5,
),
),
),
],
)
: Row(
children: [
// Avatar
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: AppColor.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.black
.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Icon(
Icons.person,
size: 30,
color: AppColor.primary,
),
),
const SizedBox(width: 16),
// User Info
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
state.user.name,
style: AppStyle.lg.copyWith(
fontWeight:
FontWeight.bold,
color: AppColor.white,
letterSpacing: 0.5,
),
),
const SizedBox(height: 4),
Text(
state.user.phoneNumber,
style: AppStyle.sm.copyWith(
color: AppColor.white
.withOpacity(0.9),
),
),
],
),
),
// Arrow Icon
Icon(
Icons.arrow_forward_ios,
color: AppColor.white,
size: 14,
),
],
),
),
], ],
), ),
), ),
Icon( ),
Icons.arrow_forward_ios, ],
color: AppColor.textSecondary, ),
size: 14, ),
const SizedBox(height: 8),
// Menu Items
if (state.isAuthenticated) ...[
Container(
color: AppColor.white,
child: Column(
children: [
_buildMenuItem(
icon: Icons.location_on_outlined,
title: 'Alamat Tersimpan',
onTap: () => context.router.push(AddressRoute()),
),
_buildMenuItem(
icon: Icons.payment_outlined,
title: 'Pembayaran',
onTap: () => context.router.push(PaymentRoute()),
),
_buildMenuItem(
icon: Icons.help_outline,
title: 'Pusat Bantuan',
onTap: () {},
),
_buildMenuItem(
icon: Icons.settings_outlined,
title: 'Pengaturan',
onTap: () {},
showDivider: false,
), ),
], ],
), ),
), ),
const SizedBox(height: 8),
], ],
),
),
const SizedBox(height: 20), // Legal & Privacy Section
Container(
color: AppColor.white,
child: Column(
children: [
_buildMenuItem(
icon: Icons.description_outlined,
title: 'Syarat dan Ketentuan',
onTap: () {},
),
_buildMenuItem(
icon: Icons.privacy_tip_outlined,
title: 'Kebijakan Privasi',
onTap: () {},
showDivider: false,
),
],
),
),
// Footer Section const SizedBox(height: 8),
Container(
color: AppColor.white, // Customer Service Section
padding: const EdgeInsets.all(20), Container(
child: Row( color: AppColor.white,
mainAxisAlignment: MainAxisAlignment.spaceBetween, padding: const EdgeInsets.all(20),
children: [ child: Column(
Text( crossAxisAlignment: CrossAxisAlignment.start,
'Version 4.6.1', children: [
style: AppStyle.sm.copyWith( Text(
color: AppColor.textSecondary, 'Butuh Bantuan?',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.textPrimary,
),
),
const SizedBox(height: 8),
Text(
'Customer Service kami siap untuk membantu',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
const SizedBox(height: 16),
// WhatsApp Customer Service
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.backgroundLight,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.borderLight),
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(8),
),
child: Icon(
Icons.chat,
color: AppColor.white,
size: 20,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Enaklo Customer Service (chat only)',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
Text(
'0812-1111-8456',
style: AppStyle.md.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.success,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
color: AppColor.textSecondary,
size: 14,
),
],
),
),
],
),
),
const SizedBox(height: 20),
// Footer Section
if (state.isAuthenticated)
Container(
color: AppColor.white,
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Version 4.6.1',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
GestureDetector(
onTap: () => _showLogoutDialog(
context,
onLogout: () => context
.read<LogoutFormBloc>()
.add(const LogoutFormEvent.submitted()),
),
child: Text(
'Logout',
style: AppStyle.sm.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
),
),
),
],
), ),
), ),
GestureDetector(
onTap: () => _showLogoutDialog(
context,
onLogout: () => context.read<LogoutFormBloc>().add(
const LogoutFormEvent.submitted(),
),
),
child: Text(
'Logout',
style: AppStyle.sm.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
const SizedBox(height: 100), // Bottom spacing const SizedBox(height: 100), // Bottom spacing
], ],
), ),
);
},
), ),
), ),
); );