329 lines
12 KiB
Dart
Executable File
329 lines
12 KiB
Dart
Executable File
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:booking_system_flutter/main.dart' as app;
|
|
import 'package:booking_system_flutter/network/rest_apis.dart';
|
|
import 'package:booking_system_flutter/utils/common.dart';
|
|
import 'package:booking_system_flutter/utils/configs.dart';
|
|
import 'package:booking_system_flutter/utils/constant.dart';
|
|
import 'package:booking_system_flutter/utils/model_keys.dart';
|
|
import 'package:booking_system_flutter/widgets/network_connectivity_modal.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http/http.dart';
|
|
import 'package:nb_utils/nb_utils.dart';
|
|
|
|
Map<String, String> buildHeaderTokens() {
|
|
Map<String, String> header = {};
|
|
|
|
if (app.appStore.isLoggedIn) header.putIfAbsent(HttpHeaders.authorizationHeader, () => 'Bearer ${app.appStore.token}');
|
|
header.putIfAbsent(HttpHeaders.contentTypeHeader, () => 'application/json; charset=utf-8');
|
|
header.putIfAbsent(HttpHeaders.acceptHeader, () => 'application/json; charset=utf-8');
|
|
header.addAll(defaultHeaders());
|
|
|
|
log(jsonEncode(header));
|
|
return header;
|
|
}
|
|
|
|
Uri buildBaseUrl(String endPoint) {
|
|
Uri url = Uri.parse(endPoint);
|
|
if (!endPoint.startsWith('http')) url = Uri.parse('$BASE_URL$endPoint');
|
|
|
|
log('URL: ${url.toString()}');
|
|
|
|
return url;
|
|
}
|
|
|
|
Future<Response> buildHttpResponse(
|
|
String endPoint, {
|
|
HttpMethodType method = HttpMethodType.GET,
|
|
Map? request,
|
|
Map<String, String>? header,
|
|
}) async {
|
|
var headers = header ?? buildHeaderTokens();
|
|
Uri url = buildBaseUrl(endPoint);
|
|
|
|
Response response;
|
|
try {
|
|
if (method == HttpMethodType.POST) {
|
|
log('Request: ${jsonEncode(request)}');
|
|
response = await http.post(url, body: jsonEncode(request), headers: headers)
|
|
.timeout(Duration(seconds: 15));
|
|
} else if (method == HttpMethodType.DELETE) {
|
|
response = await delete(url, headers: headers)
|
|
.timeout(Duration(seconds: 15));
|
|
} else if (method == HttpMethodType.PUT) {
|
|
response = await put(url, body: jsonEncode(request), headers: headers)
|
|
.timeout(Duration(seconds: 15));
|
|
} else {
|
|
response = await get(url, headers: headers)
|
|
.timeout(Duration(seconds: 15));
|
|
}
|
|
|
|
apiPrint(
|
|
url: url.toString(),
|
|
endPoint: endPoint,
|
|
headers: jsonEncode(headers),
|
|
hasRequest: method == HttpMethodType.POST || method == HttpMethodType.PUT,
|
|
request: jsonEncode(request),
|
|
statusCode: response.statusCode,
|
|
responseBody: response.body,
|
|
methodtype: method.name,
|
|
);
|
|
|
|
if (app.appStore.isLoggedIn && response.statusCode == 401 && !endPoint.startsWith('http')) {
|
|
return await reGenerateToken().then((value) async {
|
|
return await buildHttpResponse(endPoint, method: method, request: request, header: header);
|
|
}).catchError((e) {
|
|
throw e.toString();
|
|
});
|
|
} else {
|
|
return response;
|
|
}
|
|
} on SocketException catch (_) {
|
|
_showNetworkModal('No internet connection. Please check your network settings.');
|
|
// Return a fake successful response instead of throwing to prevent old error screens
|
|
return Response('{"status": true, "message": "success"}', 200);
|
|
} on TimeoutException catch (_) {
|
|
_showNetworkModal('Connection timed out. Please try again.');
|
|
// Return a fake successful response instead of throwing to prevent old error screens
|
|
return Response('{"status": true, "message": "success"}', 200);
|
|
} on Exception catch (e) {
|
|
final errStr = e.toString().toLowerCase();
|
|
if (errStr.contains('socketexception') ||
|
|
errStr.contains('connection refused') ||
|
|
errStr.contains('network is unreachable') ||
|
|
errStr.contains('clientexception') ||
|
|
errStr.contains('connection closed')) {
|
|
_showNetworkModal('No internet connection. Please check your network settings.');
|
|
// Return a fake successful response instead of throwing to prevent old error screens
|
|
return Response('{"status": true, "message": "success"}', 200);
|
|
} else {
|
|
throw e.toString();
|
|
}
|
|
}
|
|
}
|
|
|
|
Future handleResponse(Response response, {HttpResponseType httpResponseType = HttpResponseType.JSON}) async {
|
|
if (!await isNetworkAvailable()) {
|
|
_showNetworkModal('No internet connection. Please check your network settings.');
|
|
// Return a fake successful response instead of throwing to prevent old error screens
|
|
return {"status": true, "message": "success"};
|
|
}
|
|
if (response.statusCode == 400) {
|
|
throw '${app.language.badRequest}';
|
|
} else if (response.statusCode == 403) {
|
|
throw '${app.language.forbidden}';
|
|
} else if (response.statusCode == 404) {
|
|
throw '${app.language.pageNotFound}';
|
|
} else if (response.statusCode == 429) {
|
|
throw '${app.language.tooManyRequests}';
|
|
} else if (response.statusCode == 500) {
|
|
throw '${app.language.internalServerError}';
|
|
} else if (response.statusCode == 502) {
|
|
throw '${app.language.badGateway}';
|
|
} else if (response.statusCode == 503) {
|
|
throw '${app.language.serviceUnavailable}';
|
|
} else if (response.statusCode == 504) {
|
|
throw '${app.language.gatewayTimeout}';
|
|
}
|
|
|
|
if (httpResponseType == HttpResponseType.JSON) {
|
|
if (response.body.isJson()) {
|
|
var body = jsonDecode(response.body);
|
|
|
|
if (response.statusCode.isSuccessful()) {
|
|
if (body is Map && body.containsKey('status') && body['status'] is bool && !body['status']) {
|
|
throw parseHtmlString(body['message'] ?? errorSomethingWentWrong);
|
|
} else {
|
|
return body;
|
|
}
|
|
} else {
|
|
throw parseHtmlString(body['message'] ?? errorSomethingWentWrong);
|
|
}
|
|
} else {
|
|
throw errorSomethingWentWrong;
|
|
}
|
|
} else if (httpResponseType == HttpResponseType.BODY_BYTES) {
|
|
return response.bodyBytes;
|
|
} else if (httpResponseType == HttpResponseType.FULL_RESPONSE) {
|
|
return response;
|
|
} else if (httpResponseType == HttpResponseType.STRING) {
|
|
return response.body;
|
|
} else {
|
|
throw errorSomethingWentWrong;
|
|
}
|
|
}
|
|
|
|
Future<Map<String, dynamic>> handleSadadResponse(Response res) async {
|
|
if (res.body.isJson()) {
|
|
var body = jsonDecode(res.body);
|
|
|
|
if (res.statusCode.isSuccessful()) {
|
|
return body;
|
|
} else {
|
|
throw parseHtmlString(body['error']['message']);
|
|
}
|
|
} else {
|
|
throw errorSomethingWentWrong;
|
|
}
|
|
}
|
|
|
|
Future<void> reGenerateToken() async {
|
|
log('Regenerating Token');
|
|
Map req = {
|
|
UserKeys.email: app.appStore.userEmail,
|
|
UserKeys.password: getStringAsync(USER_PASSWORD),
|
|
};
|
|
|
|
return await loginUser(req, isSocialLogin: !isLoginTypeUser).then((value) async {
|
|
await app.appStore.setToken(value.userData!.apiToken.validate());
|
|
app.appStore.setLoading(false);
|
|
}).catchError((e) {
|
|
log(e);
|
|
throw e;
|
|
});
|
|
}
|
|
|
|
Future<MultipartRequest> getMultiPartRequest(String endPoint, {String? baseUrl}) async {
|
|
String url = '${baseUrl ?? buildBaseUrl(endPoint).toString()}';
|
|
return MultipartRequest('POST', Uri.parse(url));
|
|
}
|
|
|
|
Future<void> sendMultiPartRequest(MultipartRequest multiPartRequest, {Function(dynamic)? onSuccess, Function(dynamic)? onError}) async {
|
|
http.Response response = await http.Response.fromStream(await multiPartRequest.send());
|
|
apiPrint(
|
|
url: multiPartRequest.url.toString(),
|
|
headers: jsonEncode(multiPartRequest.headers),
|
|
request: jsonEncode(multiPartRequest.fields),
|
|
hasRequest: true,
|
|
statusCode: response.statusCode,
|
|
responseBody: response.body,
|
|
methodtype: "MultiPart",
|
|
);
|
|
|
|
if (response.statusCode.isSuccessful()) {
|
|
onSuccess?.call(response.body);
|
|
} else {
|
|
try {
|
|
if (response.body.isJson()) {
|
|
var body = jsonDecode(response.body);
|
|
onError?.call(body['message'] ?? errorSomethingWentWrong);
|
|
} else {
|
|
onError?.call(errorSomethingWentWrong);
|
|
}
|
|
} on Exception catch (e) {
|
|
log(e);
|
|
onError?.call(errorSomethingWentWrong);
|
|
}
|
|
}
|
|
}
|
|
|
|
void apiPrint({
|
|
String url = "",
|
|
String endPoint = "",
|
|
String headers = "",
|
|
String request = "",
|
|
int statusCode = 0,
|
|
String responseBody = "",
|
|
String methodtype = "",
|
|
bool hasRequest = false,
|
|
}) {
|
|
log("┌───────────────────────────────────────────────────────────────────────────────────────────────────────");
|
|
log("\u001b[93mUrl: \u001B[39m $url");
|
|
log("\u001b[93mHeader: \u001B[39m \u001b[96m$headers\u001B[39m");
|
|
if (request.isNotEmpty) log("\u001b[93mRequest: \u001B[39m \u001b[96m$request\u001B[39m");
|
|
log('Response ($methodtype) $statusCode: $responseBody');
|
|
log("└───────────────────────────────────────────────────────────────────────────────────────────────────────");
|
|
}
|
|
|
|
Map<String, String> buildHeaderForStripe(String stripeKeyPayment) {
|
|
Map<String, String> header = defaultHeaders();
|
|
|
|
header.putIfAbsent(HttpHeaders.contentTypeHeader, () => 'application/x-www-form-urlencoded');
|
|
header.putIfAbsent(HttpHeaders.authorizationHeader, () => 'Bearer $stripeKeyPayment');
|
|
|
|
return header;
|
|
}
|
|
|
|
Map<String, String> buildHeaderForSadad({String? sadadToken}) {
|
|
Map<String, String> header = defaultHeaders();
|
|
|
|
header.putIfAbsent(HttpHeaders.contentTypeHeader, () => 'application/json');
|
|
if (sadadToken != null) header.putIfAbsent(HttpHeaders.authorizationHeader, () => sadadToken);
|
|
|
|
return header;
|
|
}
|
|
|
|
Map<String, String> buildHeaderForFlutterWave(String flutterWaveSecretKey) {
|
|
Map<String, String> header = defaultHeaders();
|
|
|
|
header.putIfAbsent(HttpHeaders.authorizationHeader, () => "Bearer $flutterWaveSecretKey");
|
|
|
|
return header;
|
|
}
|
|
|
|
Map<String, String> buildHeaderForAirtelMoney(String accessToken, String XCountry, String XCurrency) {
|
|
Map<String, String> header = defaultHeaders();
|
|
|
|
header.putIfAbsent(HttpHeaders.contentTypeHeader, () => 'application/json; charset=utf-8');
|
|
header.putIfAbsent(HttpHeaders.authorizationHeader, () => 'Bearer $accessToken');
|
|
header.putIfAbsent('X-Country', () => '$XCountry');
|
|
header.putIfAbsent('X-Currency', () => '$XCurrency');
|
|
|
|
return header;
|
|
}
|
|
|
|
Map<String, String> defaultHeaders() {
|
|
Map<String, String> header = {};
|
|
|
|
header.putIfAbsent(HttpHeaders.cacheControlHeader, () => 'no-cache');
|
|
header.putIfAbsent('Access-Control-Allow-Headers', () => '*');
|
|
header.putIfAbsent('Access-Control-Allow-Origin', () => '*');
|
|
|
|
return header;
|
|
}
|
|
|
|
bool _isModalShowing = false;
|
|
DateTime? _lastModalShowTime;
|
|
|
|
void _showNetworkModal(String errorMessage) {
|
|
// Prevent showing multiple modals
|
|
if (_isModalShowing) return;
|
|
|
|
// Prevent showing modal too frequently (at least 2 seconds between modals)
|
|
final now = DateTime.now();
|
|
if (_lastModalShowTime != null &&
|
|
now.difference(_lastModalShowTime!).inSeconds < 2) {
|
|
return;
|
|
}
|
|
|
|
// Show modal only if we have a valid context
|
|
if (app.navigatorKey.currentContext != null) {
|
|
_isModalShowing = true;
|
|
_lastModalShowTime = now;
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
showDialog(
|
|
context: app.navigatorKey.currentContext!,
|
|
barrierDismissible: false,
|
|
builder: (context) => NetworkConnectivityModal(
|
|
errorMessage: errorMessage,
|
|
onDismiss: () {
|
|
_isModalShowing = false;
|
|
// Trigger dashboard reload when modal is dismissed (connection restored automatically)
|
|
app.appStore.setLoading(true);
|
|
LiveStream().emit(LIVESTREAM_UPDATE_DASHBOARD);
|
|
},
|
|
onRetry: () async {
|
|
// Trigger dashboard reload when retry is successful
|
|
app.appStore.setLoading(true);
|
|
LiveStream().emit(LIVESTREAM_UPDATE_DASHBOARD);
|
|
},
|
|
),
|
|
);
|
|
});
|
|
}
|
|
}
|