fix(contacts): validate duplicate phone numbers before adding
This commit is contained in:
@@ -112,7 +112,7 @@ class ContactsScreen extends ConsumerWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
showDialog<void>(
|
showLegacyDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => Dialog(
|
builder: (_) => Dialog(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
@@ -145,7 +145,7 @@ class ContactsScreen extends ConsumerWidget {
|
|||||||
required String contactId,
|
required String contactId,
|
||||||
required int currentCount,
|
required int currentCount,
|
||||||
}) async {
|
}) async {
|
||||||
final confirmed = await showDialog<bool>(
|
final confirmed = await showLegacyDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) => AlertDialog(
|
builder: (dialogContext) => AlertDialog(
|
||||||
title: Text(context.translate(I18n.deleteContactMessage)),
|
title: Text(context.translate(I18n.deleteContactMessage)),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:design_system/design_system.dart';
|
import 'package:design_system/design_system.dart';
|
||||||
import 'package:device_management/src/features/contacts/presentation/providers/contacts_controller.dart';
|
import 'package:device_management/src/features/contacts/presentation/providers/contacts_controller.dart';
|
||||||
|
import 'package:device_management/src/features/contacts/presentation/providers/contacts_provider.dart';
|
||||||
import 'package:device_management/src/features/contacts/presentation/providers/new_contact_form_provider.dart';
|
import 'package:device_management/src/features/contacts/presentation/providers/new_contact_form_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -99,6 +100,16 @@ class _NewContactDialogState extends ConsumerState<NewContactDialog> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final existingContacts =
|
||||||
|
ref.read(contactsProvider(widget.userId)).value ?? [];
|
||||||
|
final isDuplicate = existingContacts.any(
|
||||||
|
(c) => c.phone?.e164 == parsed.e164 || c.rawPhone == parsed.e164,
|
||||||
|
);
|
||||||
|
if (isDuplicate) {
|
||||||
|
formNotifier.setLocalError(I18n.errorContactDuplicate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
formNotifier.clearError();
|
formNotifier.clearError();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
ref.read(contactsControllerProvider.notifier).createContact(
|
ref.read(contactsControllerProvider.notifier).createContact(
|
||||||
|
|||||||
@@ -162,6 +162,16 @@ class _ContactFormSheetWrapperState
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_isEdit) {
|
||||||
|
final isDuplicate = widget.currentContacts.any(
|
||||||
|
(c) => c.phone == parsed.e164,
|
||||||
|
);
|
||||||
|
if (isDuplicate) {
|
||||||
|
formNotifier.setPhoneError(I18n.errorContactDuplicate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final contact = ContactListContactEntity(
|
final contact = ContactListContactEntity(
|
||||||
name: _nameController.text.trim(),
|
name: _nameController.text.trim(),
|
||||||
phone: parsed.e164,
|
phone: parsed.e164,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:legacy_ui/legacy_ui.dart';
|
||||||
import 'package:design_system/design_system.dart';
|
import 'package:design_system/design_system.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -21,8 +22,8 @@ class SosContactsScreen extends ConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final device = ref.watch(selectedDeviceProvider).value;
|
final device = ref.watch(selectedDeviceProvider).value;
|
||||||
final primaryColor = context.sfColors.legacyPrimary;
|
final primaryColor = context.sfColors.legacyPrimary;
|
||||||
final maxContacts = device?.capabilities?.contacts
|
final maxContacts =
|
||||||
?.maxForType('emergency', fallback: 3) ??
|
device?.capabilities?.contacts?.maxForType('emergency', fallback: 3) ??
|
||||||
3;
|
3;
|
||||||
|
|
||||||
ref.listen(sosContactsControllerProvider, (prev, next) async {
|
ref.listen(sosContactsControllerProvider, (prev, next) async {
|
||||||
@@ -128,7 +129,7 @@ class SosContactsScreen extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
context.translate(I18n.sosContacts).toUpperCase(),
|
context.translate(I18n.sosContacts),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: SizeUtils.getByScreen(small: 20, big: 19),
|
fontSize: SizeUtils.getByScreen(small: 20, big: 19),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@@ -163,7 +164,7 @@ class SosContactsScreen extends ConsumerWidget {
|
|||||||
|
|
||||||
Future<bool?> _confirmDelete(BuildContext context, String name) {
|
Future<bool?> _confirmDelete(BuildContext context, String name) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return showDialog<bool>(
|
return showLegacyDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) => AlertDialog(
|
builder: (dialogContext) => AlertDialog(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
@@ -268,8 +269,7 @@ class _ContactList extends StatelessWidget {
|
|||||||
context.translate(I18n.sosDescription),
|
context.translate(I18n.sosDescription),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: SizeUtils.getByScreen(small: 14, big: 15),
|
fontSize: SizeUtils.getByScreen(small: 14, big: 15),
|
||||||
color:
|
color: Theme.of(context).colorScheme.onSurface.withAlpha(178),
|
||||||
Theme.of(context).colorScheme.onSurface.withAlpha(178),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -120,6 +120,14 @@ class _AddSosContactSheetState extends ConsumerState<_AddSosContactSheet> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final isDuplicate = widget.currentContacts.any(
|
||||||
|
(c) => c.phone == parsed.e164,
|
||||||
|
);
|
||||||
|
if (isDuplicate) {
|
||||||
|
formNotifier.setPhoneError(I18n.errorContactDuplicate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await ref.read(sosContactsControllerProvider.notifier).addContact(
|
await ref.read(sosContactsControllerProvider.notifier).addContact(
|
||||||
deviceId: widget.deviceId,
|
deviceId: widget.deviceId,
|
||||||
userId: widget.userId,
|
userId: widget.userId,
|
||||||
|
|||||||
Reference in New Issue
Block a user