feat: logout behavior
This commit is contained in:
parent
801698262b
commit
438c95746f
|
@ -1,9 +1,12 @@
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:rijig_mobile/features/auth/presentation/viewmodel/login_vmod.dart';
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/login_vmod.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/logout_vmod.dart';
|
||||||
import 'package:rijig_mobile/features/auth/presentation/viewmodel/otp_vmod.dart';
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/otp_vmod.dart';
|
||||||
import 'package:rijig_mobile/features/auth/repositories/login_repository.dart';
|
import 'package:rijig_mobile/features/auth/repositories/login_repository.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/repositories/logout_repository.dart';
|
||||||
import 'package:rijig_mobile/features/auth/repositories/otp_repository.dart';
|
import 'package:rijig_mobile/features/auth/repositories/otp_repository.dart';
|
||||||
import 'package:rijig_mobile/features/auth/service/login_service.dart';
|
import 'package:rijig_mobile/features/auth/service/login_service.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/service/logout_service.dart';
|
||||||
import 'package:rijig_mobile/features/auth/service/otp_service.dart';
|
import 'package:rijig_mobile/features/auth/service/otp_service.dart';
|
||||||
|
|
||||||
final sl = GetIt.instance;
|
final sl = GetIt.instance;
|
||||||
|
@ -11,4 +14,5 @@ final sl = GetIt.instance;
|
||||||
void init() {
|
void init() {
|
||||||
sl.registerFactory(() => LoginViewModel(LoginService(LoginRepository())));
|
sl.registerFactory(() => LoginViewModel(LoginService(LoginRepository())));
|
||||||
sl.registerFactory(() => OtpViewModel(OtpService(OtpRepository())));
|
sl.registerFactory(() => OtpViewModel(OtpService(OtpRepository())));
|
||||||
|
sl.registerFactory(() => LogoutViewModel(LogoutService(LogoutRepository())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
|
||||||
// =====================color schema=====================
|
// =====================color schema=====================
|
||||||
Color whiteColor = Color(0xffF0F1EA);
|
Color whiteColor = Color(0xffFBFBFB);
|
||||||
Color blackNavyColor = Color(0xff101010);
|
Color blackNavyColor = Color(0xff101010);
|
||||||
Color primaryColor = Color(0xff018558);
|
Color primaryColor = Color(0xff018558);
|
||||||
Color secondaryColor = Color(0xffBDE902);
|
Color secondaryColor = Color(0xffBDE902);
|
||||||
|
|
|
@ -75,7 +75,7 @@ class _NavigationPageState extends State<NavigationPage> {
|
||||||
padding: PaddingCustom().paddingHorizontal(2),
|
padding: PaddingCustom().paddingHorizontal(2),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
height: 67,
|
height: 67,
|
||||||
color: Colors.white,
|
color: primaryColor,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
notchMargin: 3.0,
|
notchMargin: 3.0,
|
||||||
child: BottomNavigationBar(
|
child: BottomNavigationBar(
|
||||||
|
@ -84,33 +84,33 @@ class _NavigationPageState extends State<NavigationPage> {
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
showSelectedLabels: true,
|
showSelectedLabels: true,
|
||||||
showUnselectedLabels: true,
|
showUnselectedLabels: true,
|
||||||
selectedItemColor: Colors.blue,
|
selectedItemColor: secondaryColor,
|
||||||
unselectedItemColor: Colors.grey,
|
unselectedItemColor: whiteColor,
|
||||||
currentIndex: _selectedIndex,
|
currentIndex: _selectedIndex,
|
||||||
onTap: _onItemTapped,
|
onTap: _onItemTapped,
|
||||||
items: [
|
items: [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Iconsax.home_1, color: Colors.grey),
|
icon: Icon(Iconsax.home_2),
|
||||||
activeIcon: Icon(Iconsax.home_1, color: Colors.blue),
|
activeIcon: Icon(Iconsax.home_2, size: 28),
|
||||||
label: 'Beranda',
|
label: 'Beranda',
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Iconsax.home, color: Colors.grey),
|
icon: Icon(Iconsax.note_favorite),
|
||||||
activeIcon: Icon(Iconsax.home, color: Colors.blue),
|
activeIcon: Icon(Iconsax.note_favorite, size: 28),
|
||||||
label: 'Pesan',
|
label: 'Aktivitas',
|
||||||
),
|
),
|
||||||
const BottomNavigationBarItem(
|
const BottomNavigationBarItem(
|
||||||
icon: SizedBox.shrink(),
|
icon: SizedBox.shrink(),
|
||||||
label: '',
|
label: '',
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Iconsax.document, color: Colors.grey),
|
icon: Icon(Iconsax.shopping_cart),
|
||||||
activeIcon: Icon(Iconsax.document, color: Colors.blue),
|
activeIcon: Icon(Iconsax.shopping_cart, size: 28),
|
||||||
label: 'Tutorial',
|
label: 'Keranjang',
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Iconsax.home, color: Colors.grey),
|
icon: Icon(Iconsax.user),
|
||||||
activeIcon: Icon(Iconsax.home, color: Colors.blue),
|
activeIcon: Icon(Iconsax.user, size: 28),
|
||||||
label: 'Profil',
|
label: 'Profil',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -129,7 +129,7 @@ class _NavigationPageState extends State<NavigationPage> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
router.push("/requestpickup");
|
router.push("/requestpickup");
|
||||||
},
|
},
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: primaryColor,
|
||||||
shape: const CircleBorder(
|
shape: const CircleBorder(
|
||||||
side: BorderSide(color: Colors.white, width: 4),
|
side: BorderSide(color: Colors.white, width: 4),
|
||||||
),
|
),
|
||||||
|
@ -142,8 +142,8 @@ class _NavigationPageState extends State<NavigationPage> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
Icon(Iconsax.home, color: primaryColor, size: 30),
|
Icon(Iconsax.archive_2, color: whiteColor, size: 30),
|
||||||
Text("data", style: TextStyle(color: blackNavyColor)),
|
Text("mulai", style: TextStyle(color: whiteColor)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class LogoutResponse {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
LogoutResponse({required this.message});
|
||||||
|
|
||||||
|
factory LogoutResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
return LogoutResponse(message: json['meta']['message']);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/service/logout_service.dart';
|
||||||
|
|
||||||
|
class LogoutViewModel extends ChangeNotifier {
|
||||||
|
final LogoutService _logoutService;
|
||||||
|
|
||||||
|
LogoutViewModel(this._logoutService);
|
||||||
|
|
||||||
|
bool isLoading = false;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
Future<void> logout() async {
|
||||||
|
isLoading = true;
|
||||||
|
errorMessage = null;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _logoutService.logout();
|
||||||
|
} catch (e) {
|
||||||
|
errorMessage = "Error: ${e.toString()}";
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:rijig_mobile/core/api/api_services.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/model/logout_model.dart';
|
||||||
|
|
||||||
|
class LogoutRepository {
|
||||||
|
final Https _https = Https();
|
||||||
|
|
||||||
|
Future<LogoutResponse> logout() async {
|
||||||
|
final response = await _https.post('/authmasyarakat/logout');
|
||||||
|
return LogoutResponse.fromJson(response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:rijig_mobile/core/storage/secure_storage.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/repositories/logout_repository.dart';
|
||||||
|
|
||||||
|
class LogoutService {
|
||||||
|
final LogoutRepository _logoutRepository;
|
||||||
|
final _storage = SecureStorage();
|
||||||
|
|
||||||
|
LogoutService(this._logoutRepository);
|
||||||
|
|
||||||
|
Future<void> clearSession() async {
|
||||||
|
await _storage.deleteSecureData('token');
|
||||||
|
await _storage.deleteSecureData('user_id');
|
||||||
|
await _storage.deleteSecureData('user_role');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> logout() async {
|
||||||
|
try {
|
||||||
|
await _logoutRepository.logout();
|
||||||
|
await clearSession();
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Logout failed: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:iconsax_flutter/iconsax_flutter.dart';
|
import 'package:iconsax_flutter/iconsax_flutter.dart';
|
||||||
|
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||||
|
|
||||||
class HomeHeader extends StatelessWidget {
|
class HomeHeader extends StatelessWidget {
|
||||||
const HomeHeader({super.key});
|
const HomeHeader({super.key});
|
||||||
|
@ -12,33 +13,23 @@ class HomeHeader extends StatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Rijig", style: TextStyle(fontSize: 24)),
|
Text("Rijig", style: Tulisan.heading(color: primaryColor)),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Icon(Iconsax.notification),
|
Icon(Iconsax.notification),
|
||||||
Gap(10),
|
Gap(10),
|
||||||
Icon(Iconsax.message),
|
Icon(Iconsax.message_2),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
// IconBtnWithCounter(
|
|
||||||
// svgSrc: "assets/icons/Cart Icon.svg",
|
|
||||||
// press: () => Navigator.pushNamed(context, CartScreen.routeName),
|
|
||||||
// ),
|
|
||||||
// const SizedBox(width: 8),
|
|
||||||
// IconBtnWithCounter(
|
|
||||||
// svgSrc: "assets/icons/Bell.svg",
|
|
||||||
// numOfitem: 3,
|
|
||||||
// press: () {},
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||||
import 'package:rijig_mobile/features/home/components/categories.dart';
|
import 'package:rijig_mobile/features/home/components/categories.dart';
|
||||||
import 'package:rijig_mobile/features/home/components/discount_banner.dart';
|
import 'package:rijig_mobile/features/home/components/discount_banner.dart';
|
||||||
import 'package:rijig_mobile/features/home/components/home_header.dart';
|
import 'package:rijig_mobile/features/home/components/home_header.dart';
|
||||||
|
@ -15,7 +16,8 @@ class HomeScreen extends StatefulWidget {
|
||||||
class _HomeScreenState extends State<HomeScreen> {
|
class _HomeScreenState extends State<HomeScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: whiteColor,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16),
|
padding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:rijig_mobile/core/router.dart';
|
import 'package:rijig_mobile/core/router.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/logout_vmod.dart';
|
||||||
|
import 'package:rijig_mobile/widget/buttoncard.dart';
|
||||||
|
|
||||||
class ProfilScreen extends StatefulWidget {
|
class ProfilScreen extends StatefulWidget {
|
||||||
const ProfilScreen({super.key});
|
const ProfilScreen({super.key});
|
||||||
|
@ -14,21 +16,45 @@ class _ProfilScreenState extends State<ProfilScreen> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final titleofscreen = "Profil";
|
final titleofscreen = "Profil";
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
body: Consumer<LogoutViewModel>(
|
||||||
|
builder: (context, viewModel, child) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text("ini adalah halaman $titleofscreen"),
|
Text("Are you sure you want to logout?"),
|
||||||
TextButton(
|
SizedBox(height: 20),
|
||||||
onPressed: () async {
|
CardButtonOne(
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
textButton: viewModel.isLoading ? 'Logging out...' : 'Logout',
|
||||||
await prefs.remove('isLoggedIn');
|
fontSized: 16,
|
||||||
router.go('/login');
|
colorText: Colors.white,
|
||||||
|
borderRadius: 10,
|
||||||
|
horizontal: double.infinity,
|
||||||
|
vertical: 50,
|
||||||
|
onTap: () async {
|
||||||
|
await viewModel.logout();
|
||||||
|
|
||||||
|
if (viewModel.errorMessage == null) {
|
||||||
|
router.go("/login");
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(viewModel.errorMessage!)),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Text("keluar"),
|
loadingTrue: viewModel.isLoading,
|
||||||
|
usingRow: false,
|
||||||
|
),
|
||||||
|
if (viewModel.errorMessage != null)
|
||||||
|
Text(
|
||||||
|
viewModel.errorMessage!,
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
|
||||||
import 'package:rijig_mobile/core/container/injection_container.dart';
|
import 'package:rijig_mobile/core/container/injection_container.dart';
|
||||||
import 'package:rijig_mobile/core/router.dart';
|
import 'package:rijig_mobile/core/router.dart';
|
||||||
import 'package:rijig_mobile/features/auth/presentation/viewmodel/login_vmod.dart';
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/login_vmod.dart';
|
||||||
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/logout_vmod.dart';
|
||||||
import 'package:rijig_mobile/features/auth/presentation/viewmodel/otp_vmod.dart';
|
import 'package:rijig_mobile/features/auth/presentation/viewmodel/otp_vmod.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
|
@ -29,6 +30,7 @@ class MyApp extends StatelessWidget {
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (_) => sl<LoginViewModel>()),
|
ChangeNotifierProvider(create: (_) => sl<LoginViewModel>()),
|
||||||
ChangeNotifierProvider(create: (_) => sl<OtpViewModel>()),
|
ChangeNotifierProvider(create: (_) => sl<OtpViewModel>()),
|
||||||
|
ChangeNotifierProvider(create: (_) => sl<LogoutViewModel>()),
|
||||||
],
|
],
|
||||||
child: ScreenUtilInit(
|
child: ScreenUtilInit(
|
||||||
designSize: const Size(375, 812),
|
designSize: const Size(375, 812),
|
||||||
|
|
|
@ -19,7 +19,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
router.pop();
|
router.pop();
|
||||||
},
|
},
|
||||||
icon: Icon(Iconsax.arrow_left_3_copy, color: whiteColor, size: 26),
|
icon: Icon(Iconsax.arrow_circle_left, color: whiteColor, size: 26),
|
||||||
),
|
),
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: primaryColor,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class InformationCard extends StatelessWidget {
|
||||||
|
const InformationCard({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
height: 120,
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF1F1F1F),
|
||||||
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
|
),
|
||||||
|
child: const Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Membership',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18.0,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'594',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 27.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'US\$496',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 27.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Total members',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white70,
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Per month',
|
||||||
|
style: TextStyle(color: Colors.white70, fontSize: 17.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,3 +41,4 @@ flutter:
|
||||||
assets:
|
assets:
|
||||||
- server/.env.dev
|
- server/.env.dev
|
||||||
- assets/image/
|
- assets/image/
|
||||||
|
- assets/icon/
|
||||||
|
|
Loading…
Reference in New Issue