diff --git a/lib/data/models/invoice_model.dart b/lib/data/models/invoice_model.dart index e0444602e..d2fb76cc3 100644 --- a/lib/data/models/invoice_model.dart +++ b/lib/data/models/invoice_model.dart @@ -1772,6 +1772,8 @@ abstract class InvitationEntity extends Object clientContactId: clientContactId ?? '', vendorContactId: vendorContactId ?? '', createdAt: 0, + emailStatus: '', + emailError: '', key: '', link: '', sentDate: '', @@ -1813,7 +1815,10 @@ abstract class InvitationEntity extends Object String get openedDate; @BuiltValueField(wireName: 'email_status', compare: false) - String? get emailStatus; + String get emailStatus; + + @BuiltValueField(wireName: 'email_error', compare: false) + String get emailError; String get downloadLink => '$link/download?t=${DateTime.now().millisecondsSinceEpoch}'; @@ -1857,7 +1862,9 @@ abstract class InvitationEntity extends Object // ignore: unused_element static void _initializeBuilder(InvitationEntityBuilder builder) => builder ..clientContactId = '' - ..vendorContactId = ''; + ..vendorContactId = '' + ..emailError = '' + ..emailStatus = ''; static Serializer get serializer => _$invitationEntitySerializer; diff --git a/lib/data/models/invoice_model.g.dart b/lib/data/models/invoice_model.g.dart index fd0daea83..8e643f054 100644 --- a/lib/data/models/invoice_model.g.dart +++ b/lib/data/models/invoice_model.g.dart @@ -988,6 +988,12 @@ class _$InvitationEntitySerializer 'opened_date', serializers.serialize(object.openedDate, specifiedType: const FullType(String)), + 'email_status', + serializers.serialize(object.emailStatus, + specifiedType: const FullType(String)), + 'email_error', + serializers.serialize(object.emailError, + specifiedType: const FullType(String)), 'created_at', serializers.serialize(object.createdAt, specifiedType: const FullType(int)), @@ -1001,13 +1007,6 @@ class _$InvitationEntitySerializer serializers.serialize(object.id, specifiedType: const FullType(String)), ]; Object? value; - value = object.emailStatus; - if (value != null) { - result - ..add('email_status') - ..add(serializers.serialize(value, - specifiedType: const FullType(String))); - } value = object.isChanged; if (value != null) { result @@ -1088,7 +1087,11 @@ class _$InvitationEntitySerializer break; case 'email_status': result.emailStatus = serializers.deserialize(value, - specifiedType: const FullType(String)) as String?; + specifiedType: const FullType(String))! as String; + break; + case 'email_error': + result.emailError = serializers.deserialize(value, + specifiedType: const FullType(String))! as String; break; case 'isChanged': result.isChanged = serializers.deserialize(value, @@ -3002,7 +3005,9 @@ class _$InvitationEntity extends InvitationEntity { @override final String openedDate; @override - final String? emailStatus; + final String emailStatus; + @override + final String emailError; @override final bool? isChanged; @override @@ -3034,7 +3039,8 @@ class _$InvitationEntity extends InvitationEntity { required this.sentDate, required this.viewedDate, required this.openedDate, - this.emailStatus, + required this.emailStatus, + required this.emailError, this.isChanged, required this.createdAt, required this.updatedAt, @@ -3057,6 +3063,10 @@ class _$InvitationEntity extends InvitationEntity { viewedDate, r'InvitationEntity', 'viewedDate'); BuiltValueNullFieldError.checkNotNull( openedDate, r'InvitationEntity', 'openedDate'); + BuiltValueNullFieldError.checkNotNull( + emailStatus, r'InvitationEntity', 'emailStatus'); + BuiltValueNullFieldError.checkNotNull( + emailError, r'InvitationEntity', 'emailError'); BuiltValueNullFieldError.checkNotNull( createdAt, r'InvitationEntity', 'createdAt'); BuiltValueNullFieldError.checkNotNull( @@ -3126,6 +3136,7 @@ class _$InvitationEntity extends InvitationEntity { ..add('viewedDate', viewedDate) ..add('openedDate', openedDate) ..add('emailStatus', emailStatus) + ..add('emailError', emailError) ..add('isChanged', isChanged) ..add('createdAt', createdAt) ..add('updatedAt', updatedAt) @@ -3177,6 +3188,10 @@ class InvitationEntityBuilder String? get emailStatus => _$this._emailStatus; set emailStatus(String? emailStatus) => _$this._emailStatus = emailStatus; + String? _emailError; + String? get emailError => _$this._emailError; + set emailError(String? emailError) => _$this._emailError = emailError; + bool? _isChanged; bool? get isChanged => _$this._isChanged; set isChanged(bool? isChanged) => _$this._isChanged = isChanged; @@ -3230,6 +3245,7 @@ class InvitationEntityBuilder _viewedDate = $v.viewedDate; _openedDate = $v.openedDate; _emailStatus = $v.emailStatus; + _emailError = $v.emailError; _isChanged = $v.isChanged; _createdAt = $v.createdAt; _updatedAt = $v.updatedAt; @@ -3275,12 +3291,13 @@ class InvitationEntityBuilder viewedDate, r'InvitationEntity', 'viewedDate'), openedDate: BuiltValueNullFieldError.checkNotNull( openedDate, r'InvitationEntity', 'openedDate'), - emailStatus: emailStatus, + emailStatus: BuiltValueNullFieldError.checkNotNull( + emailStatus, r'InvitationEntity', 'emailStatus'), + emailError: + BuiltValueNullFieldError.checkNotNull(emailError, r'InvitationEntity', 'emailError'), isChanged: isChanged, - createdAt: BuiltValueNullFieldError.checkNotNull( - createdAt, r'InvitationEntity', 'createdAt'), - updatedAt: - BuiltValueNullFieldError.checkNotNull(updatedAt, r'InvitationEntity', 'updatedAt'), + createdAt: BuiltValueNullFieldError.checkNotNull(createdAt, r'InvitationEntity', 'createdAt'), + updatedAt: BuiltValueNullFieldError.checkNotNull(updatedAt, r'InvitationEntity', 'updatedAt'), archivedAt: BuiltValueNullFieldError.checkNotNull(archivedAt, r'InvitationEntity', 'archivedAt'), isDeleted: isDeleted, createdUserId: createdUserId, diff --git a/lib/ui/invoice/view/invoice_view_contacts.dart b/lib/ui/invoice/view/invoice_view_contacts.dart index 8bf4c4db5..7a2eb44ac 100644 --- a/lib/ui/invoice/view/invoice_view_contacts.dart +++ b/lib/ui/invoice/view/invoice_view_contacts.dart @@ -1,5 +1,6 @@ // Flutter imports: import 'package:flutter/material.dart'; +import 'package:invoiceninja_flutter/ui/app/copy_to_clipboard.dart'; // Package imports: import 'package:invoiceninja_flutter/ui/app/portal_links.dart'; @@ -42,7 +43,7 @@ class _InvitationListTile extends StatelessWidget { @override Widget build(BuildContext context) { - final localization = AppLocalization.of(context); + final localization = AppLocalization.of(context)!; final state = viewModel.state!; final client = state.clientState.get(viewModel.invoice!.clientId); final vendor = state.vendorState.get(viewModel.invoice!.vendorId); @@ -78,19 +79,19 @@ class _InvitationListTile extends StatelessWidget { case InvitationEntity.EMAIL_STATUS_DELIVERED: icon = Tooltip( child: Icon(Icons.check_circle), - message: localization!.delivered, + message: localization.delivered, ); break; case InvitationEntity.EMAIL_STATUS_BOUNCED: icon = Tooltip( child: Icon(Icons.error), - message: localization!.bounced, + message: localization.bounced, ); break; case InvitationEntity.EMAIL_STATUS_SPAM: icon = Tooltip( child: Icon(Icons.error), - message: localization!.spam, + message: localization.spam, ); break; } @@ -106,7 +107,7 @@ class _InvitationListTile extends StatelessWidget { Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( - '${localization!.sent}: ' + + '${localization.sent}: ' + formatDate(invitation.sentDate, context, showTime: true), ), ), @@ -114,7 +115,7 @@ class _InvitationListTile extends StatelessWidget { Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( - '${localization!.opened}: ' + + '${localization.opened}: ' + formatDate(invitation.openedDate, context, showTime: true), ), ), @@ -122,11 +123,22 @@ class _InvitationListTile extends StatelessWidget { Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( - '${localization!.viewed}: ' + + '${localization.viewed}: ' + formatDate(invitation.viewedDate, context, showTime: true), ), ), - SizedBox(height: 8), + if (invitation.emailStatus.isNotEmpty) + CopyToClipboard( + value: invitation.emailError, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text( + invitation.emailError, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + ), + SizedBox(height: 16), PortalLinks( viewLink: invitation.silentLink, copyLink: invitation.link,