Update Saqel Platform: 2026-09-08 13:43:36
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../services/directorate_api_service.dart';
|
||||
|
||||
class AdminAuthScreen extends StatefulWidget {
|
||||
final VoidCallback onAuthenticated;
|
||||
|
||||
const AdminAuthScreen({super.key, required this.onAuthenticated});
|
||||
|
||||
@override
|
||||
State<AdminAuthScreen> createState() => _AdminAuthScreenState();
|
||||
}
|
||||
|
||||
class _AdminAuthScreenState extends State<AdminAuthScreen> {
|
||||
final _phone = TextEditingController();
|
||||
final _otp = TextEditingController();
|
||||
String _role = 'school_admin';
|
||||
bool _otpSent = false;
|
||||
bool _busy = false;
|
||||
String? _error;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_phone.dispose();
|
||||
_otp.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _submit() async {
|
||||
setState(() {
|
||||
_busy = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
if (!_otpSent) {
|
||||
await DirectorateApiService.requestOtp(phoneNumber: _phone.text.trim(), role: _role);
|
||||
if (mounted) setState(() => _otpSent = true);
|
||||
} else {
|
||||
await DirectorateApiService.verifyOtp(
|
||||
phoneNumber: _phone.text.trim(),
|
||||
otp: _otp.text.trim(),
|
||||
role: _role,
|
||||
);
|
||||
widget.onAuthenticated();
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setState(() => _error = e.toString().replaceFirst('Bad state: ', ''));
|
||||
} finally {
|
||||
if (mounted) setState(() => _busy = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 430),
|
||||
child: Card(
|
||||
margin: const EdgeInsets.all(24),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(28),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Text('دخول الإدارة', style: TextStyle(fontSize: 28, fontWeight: FontWeight.w800)),
|
||||
const SizedBox(height: 8),
|
||||
const Text('الدخول متاح فقط للحسابات المخوّلة مسبقاً على خادم صَقِل.'),
|
||||
const SizedBox(height: 22),
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: _role,
|
||||
decoration: const InputDecoration(labelText: 'الصلاحية'),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 'school_admin', child: Text('مدير مدرسة')),
|
||||
DropdownMenuItem(value: 'supervisor', child: Text('مشرف')),
|
||||
DropdownMenuItem(value: 'directorate_admin', child: Text('مدير مديرية')),
|
||||
],
|
||||
onChanged: _otpSent ? null : (value) => setState(() => _role = value!),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
TextField(
|
||||
controller: _phone,
|
||||
enabled: !_otpSent,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: const InputDecoration(labelText: 'رقم الهاتف', hintText: '079XXXXXXX'),
|
||||
),
|
||||
if (_otpSent) ...[
|
||||
const SizedBox(height: 14),
|
||||
TextField(
|
||||
controller: _otp,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(labelText: 'رمز التحقق'),
|
||||
),
|
||||
],
|
||||
if (_error != null) ...[
|
||||
const SizedBox(height: 14),
|
||||
Text(_error!, style: const TextStyle(color: Colors.redAccent)),
|
||||
],
|
||||
const SizedBox(height: 22),
|
||||
FilledButton(
|
||||
onPressed: _busy ? null : _submit,
|
||||
child: Text(_busy ? 'جارٍ التحقق…' : (_otpSent ? 'دخول' : 'إرسال الرمز')),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user