Files
efrilmandClaude Opus 5.5 f5e3075205 EnakPoint & EnakCoin wallet, PIN, outlet, order, community, reward
- Wallet EnakPoint & EnakCoin: beranda, riwayat, saldo kedaluwarsa, kode
  bayar, tukar EnakCoin, transfer
- PIN (buat, ganti, lupa), outlet, riwayat order, game spin
- Halaman community, webview, coming soon, dan ikon menu beranda baru
- Redesign Reward Saya: kartu tiket, filter chip, detail kode + QR
- Hapus customer point loader, menu, dan checkout lama
- Base URL ke enaklo-pos-api.altru.id

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:43:22 +07:00

97 lines
2.7 KiB
Dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/wallet/wallet.dart';
import '../../../injection.dart';
import '../../components/toast/flushbar.dart';
import '../../router/app_router.gr.dart';
import '../wallet/wallet_ui.dart';
/// Memastikan customer siap memasukkan PIN (ยง6.1) sebelum aksi yang butuh PIN.
///
/// - Belum punya PIN: buka alur buat PIN, lalu lanjut bila berhasil dibuat.
/// - PIN terkunci: tampilkan jam buka kunci dan tawarkan "Lupa PIN".
///
/// Mengembalikan `true` bila aksi boleh dilanjutkan ke input PIN.
Future<bool> ensurePinReady(BuildContext context) async {
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (_) => const Center(
child: SpinKitFadingCircle(color: AppColor.white, size: 40),
),
);
final result = await getIt<IPinRepository>().getStatus();
if (!context.mounted) return false;
Navigator.of(context, rootNavigator: true).pop();
final failure = result.fold((f) => f, (_) => null);
if (failure != null) {
AppFlushbar.showError(context, walletFailureMessage(failure));
return false;
}
final status = result.getOrElse(() => const PinStatus(hasPin: false));
if (!status.hasPin) {
final created = await context.router.push<bool>(
PinSetupRoute(purpose: PinOtpPurpose.setup),
);
return created == true;
}
if (status.isLocked) {
await showPinLockedDialog(context, status.lockedUntil!);
return false;
}
return true;
}
Future<void> showPinLockedDialog(
BuildContext context,
DateTime lockedUntil,
) async {
final forgot = await showDialog<bool>(
context: context,
builder: (dialogContext) => AlertDialog(
backgroundColor: AppColor.white,
title: Text(
'PIN terkunci',
style: AppStyle.lg.copyWith(fontWeight: FontWeight.w700),
),
content: Text(
'PIN terkunci sampai ${formatWibTime(lockedUntil)}.',
style: AppStyle.md,
),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false),
child: Text(
'Tutup',
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
),
),
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(true),
child: Text(
'Lupa PIN',
style: AppStyle.md.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w700,
),
),
),
],
),
);
if (forgot == true && context.mounted) {
context.router.push(PinSetupRoute(purpose: PinOtpPurpose.reset));
}
}