SMS phone verification

This commit is contained in:
Hillel Coren 2022-11-06 17:55:49 +02:00
parent 8f49a5f8f0
commit 44287dcfb4
4 changed files with 91 additions and 6 deletions

View File

@ -421,6 +421,48 @@ class _MenuDrawerState extends State<MenuDrawer> {
},
),
)
else if (state.user.isTwoFactorEnabled &&
!state.user.phoneVerified &&
state.isHosted)
if (state.isMenuCollapsed)
Tooltip(
message:
localization.verifyPhoneNumber2faHelp,
child: ListTile(
contentPadding:
const EdgeInsets.only(left: 12),
leading: IconButton(
onPressed: () {
showDialog<void>(
context: context,
builder: (BuildContext context) =>
UserSmsVerification(
showChangeNumber: true,
),
);
},
icon: Icon(Icons.warning,
color: Colors.orange),
),
),
)
else
Material(
child: ListTile(
tileColor: Colors.orange.shade800,
subtitle: Text(
localization.verifyPhoneNumber2faHelp,
style: TextStyle(color: Colors.white),
),
onTap: () {
showDialog<void>(
context: context,
builder: (BuildContext context) =>
UserSmsVerification(),
);
},
),
)
else if (state.company.isDisabled &&
state.userCompany.isAdmin)
if (state.isMenuCollapsed)

View File

@ -9,6 +9,7 @@ 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/redux/settings/settings_actions.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';
@ -188,7 +189,12 @@ class _AccountSmsVerificationState extends State<AccountSmsVerification> {
}
class UserSmsVerification extends StatefulWidget {
const UserSmsVerification({Key key}) : super(key: key);
const UserSmsVerification({
Key key,
this.showChangeNumber = false,
}) : super(key: key);
final bool showChangeNumber;
@override
State<UserSmsVerification> createState() => _UserSmsVerificationState();
@ -268,7 +274,7 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
_isLoading = false;
});
if (navigator.canPop()) {
navigator.pop();
navigator.pop(true);
}
showToast(localization.verifiedPhoneNumber);
store.dispatch(RefreshData());
@ -289,6 +295,8 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final store = StoreProvider.of<AppState>(context);
final state = store.state;
return AlertDialog(
title: Text(localization.verifyPhoneNumber),
@ -301,7 +309,8 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(localization.codeWasSent),
Text(localization.codeWasSentTo
.replaceFirst(':number', state.user.phone)),
SizedBox(height: 20),
AppPinput(
onCompleted: (code) => _code = code,
@ -317,6 +326,15 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
),
),
if (!_isLoading) ...[
TextButton(
onPressed: () {
store.dispatch(ViewSettings(section: kSettingsUserDetails));
Navigator.of(context).pop();
},
child: Text(
localization.changeNumber.toUpperCase(),
),
),
TextButton(
onPressed: () => _sendCode(),
child: Text(

View File

@ -384,7 +384,7 @@ class _UserDetailsState extends State<UserDetails>
.toUpperCase(),
textAlign: TextAlign.center,
),
onPressed: () {
onPressed: () async {
if (state.settingsUIState.isChanged) {
showMessageDialog(
context: context,
@ -406,11 +406,19 @@ class _UserDetailsState extends State<UserDetails>
if (!kReleaseMode &&
(state.isHosted && !state.user.phoneVerified)) {
showDialog<void>(
final bool phoneVerified = await showDialog<bool>(
context: context,
builder: (BuildContext context) =>
UserSmsVerification(),
);
if (phoneVerified) {
showDialog<void>(
context: context,
builder: (BuildContext context) =>
_EnableTwoFactor(state: viewModel.state),
);
}
} else {
showDialog<void>(
context: context,

View File

@ -16,6 +16,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
'change_number': 'Change Number',
'resend_code': 'Resend Code',
'base_type': 'Base Type',
'category_type': 'Category Type',
@ -119,6 +120,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
'invoice_item_tax_rates': 'Invoice Item Tax Rates',
'verified_phone_number': 'Successfully verified phone number',
'code_was_sent': 'A code has been sent via SMS',
'code_was_sent_to': 'A code has been sent via SMS to :number',
'resend': 'Resend',
'verify': 'Verify',
'enter_phone_number': 'Please provide a phone number',
@ -126,6 +128,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
'verify_phone_number': 'Verify Phone Number',
'verify_phone_number_help':
'Please verify your phone number to send emails',
'verify_phone_number_2fa_help':
'Please verify your phone number for 2FA backup',
'merged_clients': 'Successfully merged clients',
'merge_into': 'Merge Into',
'merge': 'Merge',
@ -87471,6 +87475,19 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]['resend_code'] ??
_localizedValues['en']['resend_code'];
String get verifyPhoneNumber2faHelp =>
_localizedValues[localeCode]['verify_phone_number_2fa_help'] ??
_localizedValues['en']['verify_phone_number_2fa_help'];
String get codeWasSentTo =>
_localizedValues[localeCode]['code_was_sent_to'] ??
_localizedValues['en']['code_was_sent_to'];
String get changeNumber =>
_localizedValues[localeCode]['change_number'] ??
_localizedValues['en']['change_number'];
// STARTER: lang field - do not remove comment
String lookup(String key) {