velmart-picker/lib/features/auth/auth_screen.dart
Fibe Agent 5ba2691eac feat: initial Velmart Picker Flutter app
- All 5 batch steps: Picking, Sorting, Clarification, Slots, Handoff
- go_router navigation with step indicator
- graphql_flutter client wired up (endpoint via env var)
- Mock data layer swappable with real GraphQL service
- Item types: normal, cold, frozen, alcohol, clarify
- Storage slot assignment (cell/freezer/fridge)
2026-04-23 21:43:07 +00:00

120 lines
4.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../core/theme/app_theme.dart';
class AuthScreen extends StatefulWidget {
const AuthScreen({super.key});
@override
State<AuthScreen> createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
final _phoneController = TextEditingController();
final _otpController = TextEditingController();
bool _otpSent = false;
bool _loading = false;
Future<void> _sendOtp() async {
if (_phoneController.text.length < 10) return;
setState(() => _loading = true);
// TODO: call PickerQueries.requestOtp via GraphQL
await Future.delayed(const Duration(seconds: 1));
setState(() {
_loading = false;
_otpSent = true;
});
}
Future<void> _verifyOtp() async {
if (_otpController.text.length < 4) return;
setState(() => _loading = true);
// TODO: call PickerQueries.verifyOtp via GraphQL
await Future.delayed(const Duration(seconds: 1));
final prefs = await SharedPreferences.getInstance();
await prefs.setString('auth_token', 'mock_token_123');
if (mounted) context.go('/orders');
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.primary,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 40),
const Text(
'Велмарт',
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.white),
),
const Text(
'Комплектовщик',
style: TextStyle(fontSize: 18, color: Colors.white70),
),
const SizedBox(height: 48),
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Авторизація', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 24),
TextField(
controller: _phoneController,
keyboardType: TextInputType.phone,
enabled: !_otpSent,
decoration: const InputDecoration(
labelText: 'Номер телефону',
prefixText: '+380 ',
hintText: '67 123 4567',
),
),
if (_otpSent) ...[
const SizedBox(height: 16),
TextField(
controller: _otpController,
keyboardType: TextInputType.number,
maxLength: 6,
decoration: const InputDecoration(
labelText: 'Код підтвердження',
hintText: '000000',
counterText: '',
),
),
const SizedBox(height: 8),
TextButton(
onPressed: () => setState(() => _otpSent = false),
child: const Text('Змінити номер'),
),
],
const SizedBox(height: 24),
ElevatedButton(
onPressed: _loading ? null : (_otpSent ? _verifyOtp : _sendOtp),
child: _loading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2),
)
: Text(_otpSent ? 'Підтвердити' : 'Отримати код'),
),
],
),
),
],
),
),
),
);
}
}