refresh token
This commit is contained in:
parent
a58d1040af
commit
59a8d7f661
@ -1,6 +1,9 @@
|
|||||||
import 'package:awesome_dio_interceptor/awesome_dio_interceptor.dart';
|
import 'package:awesome_dio_interceptor/awesome_dio_interceptor.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:enaklo_pos/core/constants/variables.dart';
|
||||||
import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
|
import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
|
||||||
|
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
||||||
|
import 'package:enaklo_pos/data/models/response/auth_response_model.dart';
|
||||||
import 'package:enaklo_pos/presentation/auth/login_page.dart';
|
import 'package:enaklo_pos/presentation/auth/login_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@ -124,13 +127,17 @@ class AuthInterceptorWithRefresh extends Interceptor {
|
|||||||
Future<bool> _tryRefreshToken() async {
|
Future<bool> _tryRefreshToken() async {
|
||||||
try {
|
try {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final refreshToken = prefs.getString('refresh_token');
|
final authData = await AuthLocalDataSource().getAuthData();
|
||||||
|
|
||||||
if (refreshToken == null) return false;
|
final url = '${Variables.baseUrl}/api/v1/auth/refresh';
|
||||||
|
|
||||||
final response = await Dio().post(
|
final response = await Dio().post(
|
||||||
'YOUR_REFRESH_TOKEN_ENDPOINT',
|
url,
|
||||||
data: {'refresh_token': refreshToken},
|
options: Options(
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ${authData.refreshToken}',
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
@ -140,6 +147,11 @@ class AuthInterceptorWithRefresh extends Interceptor {
|
|||||||
await prefs.setString('auth_token', newToken);
|
await prefs.setString('auth_token', newToken);
|
||||||
await prefs.setString('refresh_token', newRefreshToken);
|
await prefs.setString('refresh_token', newRefreshToken);
|
||||||
|
|
||||||
|
AuthResponseModel authResponseModel =
|
||||||
|
AuthResponseModel.fromMap(response.data['data']);
|
||||||
|
|
||||||
|
AuthLocalDataSource().saveAuthData(authResponseModel);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -2,9 +2,11 @@ import 'dart:convert';
|
|||||||
|
|
||||||
class AuthResponseModel {
|
class AuthResponseModel {
|
||||||
final String? token;
|
final String? token;
|
||||||
|
final String? refreshToken;
|
||||||
final User? user;
|
final User? user;
|
||||||
|
|
||||||
AuthResponseModel({
|
AuthResponseModel({
|
||||||
|
this.refreshToken,
|
||||||
this.token,
|
this.token,
|
||||||
this.user,
|
this.user,
|
||||||
});
|
});
|
||||||
@ -17,11 +19,13 @@ class AuthResponseModel {
|
|||||||
factory AuthResponseModel.fromMap(Map<String, dynamic> json) =>
|
factory AuthResponseModel.fromMap(Map<String, dynamic> json) =>
|
||||||
AuthResponseModel(
|
AuthResponseModel(
|
||||||
token: json["token"],
|
token: json["token"],
|
||||||
|
refreshToken: json["refresh_token"],
|
||||||
user: json["user"] == null ? null : User.fromMap(json["user"]),
|
user: json["user"] == null ? null : User.fromMap(json["user"]),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toMap() => {
|
Map<String, dynamic> toMap() => {
|
||||||
"token": token,
|
"token": token,
|
||||||
|
"refresh_token": refreshToken,
|
||||||
"user": user?.toMap(),
|
"user": user?.toMap(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,11 +81,11 @@ class _HomePageState extends State<HomePage> {
|
|||||||
context.read<CurrentOutletBloc>().add(CurrentOutletEvent.currentOutlet());
|
context.read<CurrentOutletBloc>().add(CurrentOutletEvent.currentOutlet());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _refreshData() {
|
// void _refreshData() {
|
||||||
log('🔄 Refreshing local data...');
|
// log('🔄 Refreshing l ocal data...');
|
||||||
context.read<ProductLoaderBloc>().add(const ProductLoaderEvent.refresh());
|
// context.read<ProductLoaderBloc>().add(const ProductLoaderEvent.refresh());
|
||||||
context.read<CategoryLoaderBloc>().add(const CategoryLoaderEvent.refresh());
|
// context.read<CategoryLoaderBloc>().add(const CategoryLoaderEvent.refresh());
|
||||||
}
|
// }
|
||||||
|
|
||||||
void onCategoryTap(int index) {
|
void onCategoryTap(int index) {
|
||||||
searchController.clear();
|
searchController.clear();
|
||||||
@ -130,9 +130,6 @@ class _HomePageState extends State<HomePage> {
|
|||||||
backgroundColor: AppColors.white,
|
backgroundColor: AppColors.white,
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
// Simple local mode indicator
|
|
||||||
_buildLocalIndicator(),
|
|
||||||
|
|
||||||
// Main content
|
// Main content
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -171,44 +168,6 @@ class _HomePageState extends State<HomePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple local mode indicator without sync
|
|
||||||
Widget _buildLocalIndicator() {
|
|
||||||
return Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
|
||||||
color: Colors.blue.shade600,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.storage, color: Colors.white, size: 16),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Mode Lokal - Data tersimpan di perangkat',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Only refresh button
|
|
||||||
InkWell(
|
|
||||||
onTap: _refreshData,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.all(4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white.withOpacity(0.2),
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
),
|
|
||||||
child: Icon(Icons.refresh, color: Colors.white, size: 14),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCategoryLoadingState() {
|
Widget _buildCategoryLoadingState() {
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -303,32 +262,25 @@ class _HomePageState extends State<HomePage> {
|
|||||||
|
|
||||||
// Simple home title
|
// Simple home title
|
||||||
Widget _buildSimpleHomeTitle() {
|
Widget _buildSimpleHomeTitle() {
|
||||||
return Container(
|
return HomeTitle(
|
||||||
padding: EdgeInsets.all(16),
|
controller: searchController,
|
||||||
decoration: BoxDecoration(
|
onChanged: (value) {
|
||||||
color: Colors.white,
|
setState(() {
|
||||||
border: Border(bottom: BorderSide(color: Colors.grey.shade200)),
|
searchQuery = value;
|
||||||
),
|
});
|
||||||
child: HomeTitle(
|
|
||||||
controller: searchController,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
searchQuery = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fast local search
|
// Fast local search
|
||||||
Future.delayed(Duration(milliseconds: 200), () {
|
Future.delayed(Duration(milliseconds: 200), () {
|
||||||
if (value == searchController.text) {
|
if (value == searchController.text) {
|
||||||
log('🔍 Local search: "$value"');
|
log('🔍 Local search: "$value"');
|
||||||
context.read<ProductLoaderBloc>().add(
|
context.read<ProductLoaderBloc>().add(
|
||||||
ProductLoaderEvent.searchProduct(
|
ProductLoaderEvent.searchProduct(
|
||||||
query: value,
|
query: value,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user