1
0
forked from baron/baron-sso
Files
baron-sso/userfront/lib/features/auth/presentation/approve_qr_screen.dart
2026-01-28 08:28:25 +09:00

123 lines
3.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:descope/descope.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/services/auth_proxy_service.dart';
class ApproveQrScreen extends StatefulWidget {
final String? pendingRef;
const ApproveQrScreen({super.key, this.pendingRef});
@override
State<ApproveQrScreen> createState() => _ApproveQrScreenState();
}
class _ApproveQrScreenState extends State<ApproveQrScreen> {
bool _isLoading = false;
String? _message;
bool _success = false;
Future<void> _handleApprove() async {
if (widget.pendingRef == null) return;
final session = Descope.sessionManager.session;
if (session == null || session.refreshToken.isExpired) {
setState(() => _message = "Please log in on your phone first.");
context.go('/signin'); // Redirect to login
return;
}
setState(() {
_isLoading = true;
_message = null;
});
// jwt 유효성 확인
try {
await AuthProxyService.approveQrLogin(
widget.pendingRef!,
session.sessionToken.jwt,
);
setState(() {
_success = true;
_message = "Login Approved! Your browser should now be logged in.";
});
// Automatically go to dashboard after a short delay
Future.delayed(const Duration(seconds: 1), () {
if (mounted) context.go('/');
});
} catch (e) {
setState(() => _message = "Error: $e");
} finally {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
final isLoggedIn = Descope.sessionManager.session?.refreshToken.isExpired == false;
return Scaffold(
appBar: AppBar(title: const Text("QR Login Approval")),
body: Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.phonelink_lock, size: 80, color: Colors.blue),
const SizedBox(height: 24),
const Text(
"Web Login Request",
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
Text(
"A computer is trying to log in using this QR code.",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey.shade600),
),
const SizedBox(height: 40),
if (_message != null)
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(
_message!,
style: TextStyle(color: _success ? Colors.green : Colors.red, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
if (!_success)
FilledButton.icon(
onPressed: _isLoading || !isLoggedIn ? null : _handleApprove,
icon: const Icon(Icons.check_circle),
label: const Text("Approve Login"),
style: FilledButton.styleFrom(
minimumSize: const Size.fromHeight(60),
backgroundColor: Colors.blue,
),
),
if (!isLoggedIn && !_success)
Padding(
padding: const EdgeInsets.only(top: 16),
child: TextButton(
onPressed: () => context.go('/signin'),
child: const Text("Login on this device first"),
),
),
if (_success)
FilledButton(
onPressed: () => context.go('/'),
child: const Text("Go to My Dashboard"),
),
],
),
),
),
);
}
}