SMS phone verification
This commit is contained in:
parent
8f49a5f8f0
commit
44287dcfb4
|
|
@ -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 &&
|
else if (state.company.isDisabled &&
|
||||||
state.userCompany.isAdmin)
|
state.userCompany.isAdmin)
|
||||||
if (state.isMenuCollapsed)
|
if (state.isMenuCollapsed)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import 'package:invoiceninja_flutter/constants.dart';
|
||||||
import 'package:invoiceninja_flutter/data/web_client.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_actions.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_state.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/forms/app_form.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/pinput.dart';
|
import 'package:invoiceninja_flutter/ui/app/pinput.dart';
|
||||||
|
|
@ -188,7 +189,12 @@ class _AccountSmsVerificationState extends State<AccountSmsVerification> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserSmsVerification extends StatefulWidget {
|
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
|
@override
|
||||||
State<UserSmsVerification> createState() => _UserSmsVerificationState();
|
State<UserSmsVerification> createState() => _UserSmsVerificationState();
|
||||||
|
|
@ -268,7 +274,7 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
if (navigator.canPop()) {
|
if (navigator.canPop()) {
|
||||||
navigator.pop();
|
navigator.pop(true);
|
||||||
}
|
}
|
||||||
showToast(localization.verifiedPhoneNumber);
|
showToast(localization.verifiedPhoneNumber);
|
||||||
store.dispatch(RefreshData());
|
store.dispatch(RefreshData());
|
||||||
|
|
@ -289,6 +295,8 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final localization = AppLocalization.of(context);
|
final localization = AppLocalization.of(context);
|
||||||
|
final store = StoreProvider.of<AppState>(context);
|
||||||
|
final state = store.state;
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(localization.verifyPhoneNumber),
|
title: Text(localization.verifyPhoneNumber),
|
||||||
|
|
@ -301,7 +309,8 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(localization.codeWasSent),
|
Text(localization.codeWasSentTo
|
||||||
|
.replaceFirst(':number', state.user.phone)),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
AppPinput(
|
AppPinput(
|
||||||
onCompleted: (code) => _code = code,
|
onCompleted: (code) => _code = code,
|
||||||
|
|
@ -317,6 +326,15 @@ class _UserSmsVerificationState extends State<UserSmsVerification> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!_isLoading) ...[
|
if (!_isLoading) ...[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
store.dispatch(ViewSettings(section: kSettingsUserDetails));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
localization.changeNumber.toUpperCase(),
|
||||||
|
),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => _sendCode(),
|
onPressed: () => _sendCode(),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,7 @@ class _UserDetailsState extends State<UserDetails>
|
||||||
.toUpperCase(),
|
.toUpperCase(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
if (state.settingsUIState.isChanged) {
|
if (state.settingsUIState.isChanged) {
|
||||||
showMessageDialog(
|
showMessageDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
@ -406,11 +406,19 @@ class _UserDetailsState extends State<UserDetails>
|
||||||
|
|
||||||
if (!kReleaseMode &&
|
if (!kReleaseMode &&
|
||||||
(state.isHosted && !state.user.phoneVerified)) {
|
(state.isHosted && !state.user.phoneVerified)) {
|
||||||
showDialog<void>(
|
final bool phoneVerified = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) =>
|
builder: (BuildContext context) =>
|
||||||
UserSmsVerification(),
|
UserSmsVerification(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (phoneVerified) {
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) =>
|
||||||
|
_EnableTwoFactor(state: viewModel.state),
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
static final Map<String, Map<String, String>> _localizedValues = {
|
static final Map<String, Map<String, String>> _localizedValues = {
|
||||||
'en': {
|
'en': {
|
||||||
// STARTER: lang key - do not remove comment
|
// STARTER: lang key - do not remove comment
|
||||||
|
'change_number': 'Change Number',
|
||||||
'resend_code': 'Resend Code',
|
'resend_code': 'Resend Code',
|
||||||
'base_type': 'Base Type',
|
'base_type': 'Base Type',
|
||||||
'category_type': 'Category Type',
|
'category_type': 'Category Type',
|
||||||
|
|
@ -118,7 +119,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
'expense_tax_rates': 'Expense Tax Rates',
|
'expense_tax_rates': 'Expense Tax Rates',
|
||||||
'invoice_item_tax_rates': 'Invoice Item Tax Rates',
|
'invoice_item_tax_rates': 'Invoice Item Tax Rates',
|
||||||
'verified_phone_number': 'Successfully verified phone number',
|
'verified_phone_number': 'Successfully verified phone number',
|
||||||
'code_was_sent': 'A code has been sent via SMS',
|
'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',
|
'resend': 'Resend',
|
||||||
'verify': 'Verify',
|
'verify': 'Verify',
|
||||||
'enter_phone_number': 'Please provide a phone number',
|
'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': 'Verify Phone Number',
|
||||||
'verify_phone_number_help':
|
'verify_phone_number_help':
|
||||||
'Please verify your phone number to send emails',
|
'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',
|
'merged_clients': 'Successfully merged clients',
|
||||||
'merge_into': 'Merge Into',
|
'merge_into': 'Merge Into',
|
||||||
'merge': 'Merge',
|
'merge': 'Merge',
|
||||||
|
|
@ -87471,6 +87475,19 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
_localizedValues[localeCode]['resend_code'] ??
|
_localizedValues[localeCode]['resend_code'] ??
|
||||||
_localizedValues['en']['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
|
// STARTER: lang field - do not remove comment
|
||||||
|
|
||||||
String lookup(String key) {
|
String lookup(String key) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue