Files
velocity-pay-flutter/lib/screens/onboarding/verify/verify_controller.dart

160 lines
4.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:qpay/abstracts/AbstractController.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/screens/onboarding/onboarding_controller.dart';
class VerifyModel {
String? code;
bool isLoading = false;
String? errorMessage;
String? status = 'failed';
}
class VerifyController extends AbstractController {
late OnboardingController onboardingController;
final Http http = Http();
BuildContext context;
VerifyModel model = VerifyModel();
VerifyController(this.context) {
onboardingController = Provider.of<OnboardingController>(
context,
listen: false,
);
}
void updateCode(String code) {
model.code = code;
notifyListeners();
}
/// Extracts a human-readable error message from any exception thrown during
/// an HTTP call. Supports:
/// * [DioException] the response body, request body, and a top-level
/// `message` field are inspected.
/// * Dart [Exception] / [Error] whose stringified form is a JSON object
/// (e.g. `{state: failed, status: manual, body: {...}, message: ...}`).
/// * Any other throwable falls back to its `toString()`.
String _extractErrorMessage(Object error) {
try {
if (error is DioException) {
final data = error.response?.data;
if (data is Map) {
final message = data['message'];
if (message is String && message.isNotEmpty) return message;
}
if (data is String && data.isNotEmpty) {
final parsed = _tryParseJson(data);
if (parsed is Map) {
final message = parsed['message'];
if (message is String && message.isNotEmpty) return message;
}
return data;
}
if (error.type == DioExceptionType.connectionTimeout ||
error.type == DioExceptionType.receiveTimeout ||
error.type == DioExceptionType.sendTimeout) {
return 'The request timed out. Please check your connection and try again.';
}
if (error.type == DioExceptionType.connectionError) {
return 'No internet connection. Please check your network and try again.';
}
return error.message ?? 'Network error. Please try again.';
}
final raw = error.toString();
// The server sometimes throws a stringified JSON object as an exception.
final parsed = _tryParseJson(raw);
if (parsed is Map) {
final message = parsed['message'];
if (message is String && message.isNotEmpty) return message;
}
return raw;
} catch (_) {
return 'An unexpected error occurred. Please try again.';
}
}
dynamic _tryParseJson(String input) {
try {
return jsonDecode(input);
} catch (_) {
return null;
}
}
Future<ApiResponse<Map<String, dynamic>>> verifyOtp() async {
Map user = {
"username": onboardingController.model.email,
"otpCode": model.code,
"otpType": "REGISTRATION",
"workflowId": onboardingController.model.workflowId,
};
try {
model.isLoading = true;
model.errorMessage = null;
notifyListeners();
Map response = await http.post('/auth/verify', user);
model.status = response['state'];
model.isLoading = false;
notifyListeners();
if (response['state'] == 'failed') {
final message =
response['message']?.toString() ?? "Verification failed";
model.errorMessage = message;
return ApiResponse.failure(message);
}
return ApiResponse.success(Map<String, dynamic>.from(response));
} catch (e) {
logger.e(e);
final message = _extractErrorMessage(e);
model.errorMessage = message;
model.isLoading = false;
notifyListeners();
return ApiResponse.failure(message);
}
}
Future<ApiResponse<Map<String, dynamic>>> resendOtp() async {
Map user = {
"username": onboardingController.model.email,
"phone": onboardingController.model.phone,
"workflowId": onboardingController.model.workflowId,
};
try {
model.isLoading = true;
model.errorMessage = null;
notifyListeners();
Map response = await http.post('/auth/resend', user);
model.status = response['state'];
model.isLoading = false;
notifyListeners();
if (response['state'] == 'failed') {
final message = response['message']?.toString() ?? "Resend failed";
model.errorMessage = message;
return ApiResponse.failure(message);
}
return ApiResponse.success(Map<String, dynamic>.from(response));
} catch (e) {
logger.e(e);
final message = _extractErrorMessage(e);
model.errorMessage = message;
model.isLoading = false;
notifyListeners();
return ApiResponse.failure(message);
}
}
}