189 lines
5.5 KiB
Dart
189 lines
5.5 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_redux/flutter_redux.dart';
|
|
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
|
|
import 'package:intl_phone_field/intl_phone_field.dart';
|
|
import 'package:invoiceninja_flutter/constants.dart';
|
|
import 'package:invoiceninja_flutter/data/web_client.dart';
|
|
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
|
import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart';
|
|
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
|
import 'package:invoiceninja_flutter/ui/app/pinput.dart';
|
|
import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
|
|
|
class SmsVerification extends StatefulWidget {
|
|
const SmsVerification();
|
|
|
|
@override
|
|
State<SmsVerification> createState() => _SmsVerificationState();
|
|
}
|
|
|
|
class _SmsVerificationState extends State<SmsVerification> {
|
|
bool _showCode = false;
|
|
bool _isLoading = false;
|
|
String _code = '';
|
|
String _phone = '';
|
|
final _webClient = WebClient();
|
|
|
|
static final GlobalKey<FormState> _formKey =
|
|
GlobalKey<FormState>(debugLabel: '_smsVerification');
|
|
final FocusScopeNode _focusNode = FocusScopeNode();
|
|
|
|
void _sendCode() {
|
|
final bool isValid = _formKey.currentState.validate();
|
|
|
|
if (!isValid) {
|
|
return;
|
|
}
|
|
|
|
final store = StoreProvider.of<AppState>(context);
|
|
final state = store.state;
|
|
final credentials = state.credentials;
|
|
final url = '${credentials.url}/verify';
|
|
|
|
setState(() {
|
|
_isLoading = true;
|
|
});
|
|
|
|
_webClient
|
|
.post(url, credentials.token,
|
|
data: json.encode(
|
|
{'phone': _phone},
|
|
))
|
|
.then((dynamic data) {
|
|
setState(() {
|
|
_isLoading = false;
|
|
_showCode = true;
|
|
});
|
|
}).catchError((dynamic error) {
|
|
setState(() {
|
|
_isLoading = false;
|
|
});
|
|
showErrorDialog(context: context, message: error);
|
|
});
|
|
}
|
|
|
|
void _verifyCode() {
|
|
final bool isValid = _formKey.currentState.validate();
|
|
|
|
if (!isValid) {
|
|
return;
|
|
}
|
|
|
|
final store = StoreProvider.of<AppState>(context);
|
|
final localization = AppLocalization.of(context);
|
|
final credentials = store.state.credentials;
|
|
final url = '${credentials.url}/verify/confirm';
|
|
final navigator = Navigator.of(context);
|
|
|
|
setState(() {
|
|
_isLoading = true;
|
|
});
|
|
|
|
_webClient
|
|
.post(url, credentials.token, data: json.encode({'code': _code}))
|
|
.then((dynamic data) {
|
|
setState(() {
|
|
_isLoading = false;
|
|
});
|
|
if (navigator.canPop()) {
|
|
navigator.pop();
|
|
}
|
|
showToast(localization.verifiedPhoneNumber);
|
|
store.dispatch(RefreshData());
|
|
}).catchError((dynamic error) {
|
|
setState(() {
|
|
_isLoading = false;
|
|
});
|
|
showErrorDialog(context: context, message: error);
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_focusNode.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final localization = AppLocalization.of(context);
|
|
final store = StoreProvider.of<AppState>(context);
|
|
final state = store.state;
|
|
var countryId = state.company.settings.countryId;
|
|
if ((countryId ?? '').isEmpty) {
|
|
countryId = kCountryUnitedStates;
|
|
}
|
|
final country = state.staticState.countryMap[countryId];
|
|
|
|
return AlertDialog(
|
|
title: Text(localization.verifyPhoneNumber),
|
|
content: _isLoading
|
|
? LoadingIndicator(height: 80)
|
|
: AppForm(
|
|
focusNode: _focusNode,
|
|
formKey: _formKey,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
if (_showCode) ...[
|
|
Text(localization.codeWasSent),
|
|
SizedBox(height: 20),
|
|
AppPinput(
|
|
onCompleted: (code) => _code = code,
|
|
),
|
|
] else
|
|
IntlPhoneField(
|
|
autofocus: true,
|
|
inputFormatters: [
|
|
FilteringTextInputFormatter.allow(
|
|
RegExp(r'[0-9]'),
|
|
),
|
|
],
|
|
initialCountryCode: country.iso2.toUpperCase(),
|
|
onChanged: (phone) => _phone = phone.completeNumber,
|
|
validator: (value) => value.number.isEmpty
|
|
? localization.pleaseEnterAValue
|
|
: null,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: Text(
|
|
localization.cancel.toUpperCase(),
|
|
),
|
|
),
|
|
if (_showCode) ...[
|
|
TextButton(
|
|
onPressed: () => _sendCode(),
|
|
child: Text(
|
|
localization.resend.toUpperCase(),
|
|
),
|
|
),
|
|
TextButton(
|
|
onPressed: () => _verifyCode(),
|
|
child: Text(
|
|
localization.verify.toUpperCase(),
|
|
),
|
|
),
|
|
] else ...[
|
|
TextButton(
|
|
onPressed: () => _sendCode(),
|
|
child: Text(
|
|
localization.sendCode.toUpperCase(),
|
|
),
|
|
),
|
|
]
|
|
],
|
|
);
|
|
}
|
|
}
|