From 20e950e442b2df633936b5f075d301d85c0cfb47 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 25 Sep 2024 23:57:58 -0500 Subject: [PATCH] Add preliminary login form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems maybe webview isn’t needed? This only works for user/password for now, the whole thing is a mess, but it’s starting to work… --- waydowntown_app/lib/tools/auth_form.dart | 123 ++++++++++++++++++ .../lib/widgets/session_widget.dart | 46 ++++--- 2 files changed, 151 insertions(+), 18 deletions(-) create mode 100644 waydowntown_app/lib/tools/auth_form.dart diff --git a/waydowntown_app/lib/tools/auth_form.dart b/waydowntown_app/lib/tools/auth_form.dart new file mode 100644 index 00000000..2e2cdc3f --- /dev/null +++ b/waydowntown_app/lib/tools/auth_form.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class AuthFormWidget extends StatefulWidget { + final Dio dio; + final String apiBaseUrl; + final Function onAuthSuccess; + + const AuthFormWidget({ + Key? key, + required this.dio, + required this.apiBaseUrl, + required this.onAuthSuccess, + }) : super(key: key); + + @override + _AuthFormWidgetState createState() => _AuthFormWidgetState(); +} + +class _AuthFormWidgetState extends State { + final _formKey = GlobalKey(); + final _emailController = TextEditingController(); + final _passwordController = TextEditingController(); + bool _isLoading = false; + + Future _submitForm() async { + if (_formKey.currentState!.validate()) { + setState(() { + _isLoading = true; + }); + + try { + final response = await widget.dio.post( + '${widget.apiBaseUrl}/powapi/session', + options: Options(headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }), + data: { + 'user': { + 'email': _emailController.text, + 'password': _passwordController.text, + }, + }, + ); + + if (response.statusCode == 200) { + final accessToken = response.data['data']['access_token']; + final renewalToken = response.data['data']['renewal_token']; + + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('access_token', accessToken); + await prefs.setString('renewal_token', renewalToken); + + widget.onAuthSuccess(); + } else { + // Handle error (e.g., show error message) + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Authentication failed')), + ); + } + } catch (error) { + print('Error during authentication: $error'); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('An error occurred')), + ); + } finally { + setState(() { + _isLoading = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + controller: _emailController, + decoration: const InputDecoration(labelText: 'Email'), + keyboardType: TextInputType.emailAddress, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your email'; + } + return null; + }, + ), + TextFormField( + controller: _passwordController, + decoration: const InputDecoration(labelText: 'Password'), + obscureText: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + return null; + }, + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: _isLoading ? null : _submitForm, + child: _isLoading + ? const CircularProgressIndicator() + : const Text('Log in'), + ), + ], + ), + ); + } + + @override + void dispose() { + _emailController.dispose(); + _passwordController.dispose(); + super.dispose(); + } +} diff --git a/waydowntown_app/lib/widgets/session_widget.dart b/waydowntown_app/lib/widgets/session_widget.dart index 3aaca080..2933951a 100644 --- a/waydowntown_app/lib/widgets/session_widget.dart +++ b/waydowntown_app/lib/widgets/session_widget.dart @@ -1,7 +1,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:waydowntown/tools/auth_webview.dart'; +import 'package:waydowntown/tools/auth_form.dart'; class SessionWidget extends StatefulWidget { final Dio dio; @@ -24,18 +24,22 @@ class _SessionWidgetState extends State { } Future _checkSession() async { + final otherDio = Dio(); + setState(() { _isLoading = true; }); final prefs = await SharedPreferences.getInstance(); - final cookieString = prefs.getString('auth_cookie'); + final authToken = prefs.getString('access_token'); - if (cookieString != null) { + if (authToken != null) { try { - final response = await widget.dio.get( - '/fixme/session', - options: Options(headers: {'Cookie': cookieString}), + final response = await otherDio.get( + '${widget.apiBaseUrl}/fixme/session', + options: Options(headers: { + 'Authorization': authToken, + }), ); if (response.statusCode == 200) { @@ -58,21 +62,27 @@ class _SessionWidgetState extends State { Future _logout() async { final prefs = await SharedPreferences.getInstance(); - await prefs.remove('auth_cookie'); + await prefs.remove('access_token'); _checkSession(); } - void _openAuthWebView() async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AuthWebView( - apiBaseUrl: widget.apiBaseUrl, - dio: widget.dio, - ), - ), + void _openAuthForm() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Log in'), + content: AuthFormWidget( + dio: widget.dio, + apiBaseUrl: widget.apiBaseUrl, + onAuthSuccess: () { + Navigator.of(context).pop(); + _checkSession(); + }, + ), + ); + }, ); - _checkSession(); } @override @@ -98,7 +108,7 @@ class _SessionWidgetState extends State { } return ElevatedButton( - onPressed: _openAuthWebView, + onPressed: _openAuthForm, child: const Text('Log in'), ); }