Submit customer identity proofs and show reviewed limits

This commit is contained in:
Stephan D committed 2026-10-15 02:22:28 +02:00
1 parent 7bf8b8087a
commit 1354551ae8
50 files changed
+1777 -67

No files matched your search

@@ -22,6 +22,7 @@ class IdentityProvider extends ChangeNotifier {
Identity? record;
Photo? passport;
Photo? selfie;
IdentityProfile profile = const IdentityProfile();
KycError? error;
PhotoKind? photoError;
bool busy = false;
@@ -31,11 +32,13 @@ class IdentityProvider extends ChangeNotifier {
int step = 0;
bool _disposed = false;
String? _key;
bool get hasDraft => passport != null || selfie != null;
bool _profileTouched = false;
bool get hasDraft => passport != null || selfie != null || _profileTouched;
bool get canSubmit =>
!busy &&
!stale &&
confirmed &&
profile.isComplete &&
passport != null &&
selfie != null &&
(record?.canSubmit ?? false);
@@ -57,6 +60,7 @@ class IdentityProvider extends ChangeNotifier {
final result = await service.fetch();
if (_disposed) return;
record = result;
if (!editing) profile = result.profile;
stale = false;
await onStatusChanged?.call();
if (_disposed) return;
@@ -144,6 +148,7 @@ class IdentityProvider extends ChangeNotifier {
void next() {
if (busy ||
(step == 0 && !profile.isComplete) ||
(step == 0 && passport == null) ||
(step == 1 && selfie == null))
return;
@@ -152,6 +157,15 @@ class IdentityProvider extends ChangeNotifier {
_notify();
}
void updateProfile(IdentityProfile value) {
if (busy || !editing) return;
profile = value;
_profileTouched = true;
confirmed = false;
_key = null;
_notify();
}
void confirm(bool value) {
if (!busy) {
confirmed = value;
@@ -172,6 +186,7 @@ class IdentityProvider extends ChangeNotifier {
final op = _begin(JourneyStep.kycSubmission);
try {
final result = await service.submit(
profile: profile,
passport: passport!,
selfie: selfie!,
idempotencyKey: _key!,
@@ -217,6 +232,8 @@ class IdentityProvider extends ChangeNotifier {
}
void _clear() {
_profileTouched = false;
profile = const IdentityProfile();
passport = null;
selfie = null;
confirmed = false;
@@ -0,0 +1,23 @@
import '../models/identity.dart';
import '../services/contracts.dart';
/// Offers optional verification once per customer in this app session. Identity
/// dependency failures must never prevent an already authenticated basic login.
class IdentityOnboardingProvider {
IdentityOnboardingProvider(this.service);
final IdentityService service;
final _offered = <String>{};
Future<bool> offer(String customer) async {
if (customer.isEmpty || service.isSimulated || !_offered.add(customer))
return false;
try {
final identity = await service.fetch().timeout(
const Duration(seconds: 3),
);
return identity.status == IdentityStatus.unverified ||
identity.status == IdentityStatus.changesRequested;
} catch (_) {
return false;
}
}
}