Skip to content
Merged
1 change: 1 addition & 0 deletions assets/languages/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@
"supportTicketCreated": "Ticket erstellt",
"supportTransactionIssue": "Transaktionsproblem",
"supportTypeMessage": "Beschreiben Sie Ihr Anliegen",
"swissPaymentTextInvalid": "Nur in der Schweiz gültige Buchstaben und Zeichen sind erlaubt",
"tapHereToView": "Hier tippen, um anzuzeigen",
"taxReport": "Steuerbericht",
"taxReportDescription": "Hier können Sie Ihren Steuerbericht für ein spezifisches Datum generieren.",
Expand Down
1 change: 1 addition & 0 deletions assets/languages/strings_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@
"supportTicketCreated": "Ticket created",
"supportTransactionIssue": "Transaction issue",
"supportTypeMessage": "Describe your issue",
"swissPaymentTextInvalid": "Only letters and characters valid in Switzerland are allowed",
"tapHereToView": "Tap here to view",
"taxReport": "Tax report",
"taxReportDescription": "Here you can generate your tax report for a specific date.",
Expand Down
5 changes: 1 addition & 4 deletions lib/packages/service/dfx/models/user/dto/user_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class UserKycDto {
}

// Mirror of `UserCapabilitiesDto` on the API. Authoritative per-action
// gating — the app renders Edit / Support affordances from these flags
// edit gating — the app renders Edit affordances from these flags
// instead of inferring them from KYC step status. Defaults are
// conservative (everything `false`) so pre-PR backends do not silently
// expose actions the API isn't yet ready to handle.
Expand All @@ -52,14 +52,12 @@ class UserCapabilitiesDto {
final bool canEditMail;
final bool canEditPhone;
final bool canEditAddress;
final bool supportAvailable;

const UserCapabilitiesDto({
this.canEditName = false,
this.canEditMail = false,
this.canEditPhone = false,
this.canEditAddress = false,
this.supportAvailable = false,
});

factory UserCapabilitiesDto.fromJson(Map<String, dynamic> json) {
Expand All @@ -68,7 +66,6 @@ class UserCapabilitiesDto {
canEditMail: json['canEditMail'] as bool? ?? false,
canEditPhone: json['canEditPhone'] as bool? ?? false,
canEditAddress: json['canEditAddress'] as bool? ?? false,
supportAvailable: json['supportAvailable'] as bool? ?? false,
);
}
}
30 changes: 30 additions & 0 deletions lib/packages/utils/swiss_payment_text.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// Validator for user-supplied name and address fields that mirror the
/// SIX SIG IG QR-Bill v2.3 permitted character set — printable ASCII plus
/// the Latin diacritics required for the four Swiss national languages.
///
/// Kept byte-for-byte aligned with the API-side
/// `Config.formats.swissPaymentText` regex
/// (`api/src/config/config.ts`) so client-side validation matches what the
/// backend's `@IsSwissPaymentText()` decorator accepts. Without this,
/// non-Latin input would only fail server-side with a generic 400.
library;

final RegExp _swissPaymentText = RegExp(
r'^[\x20-\x7E'
'ÀÁÂÄÇÈÉÊË'
'ÌÍÎÏÑÒÓÔÖ'
'ÙÚÛÜÝß'
'àáâäçèéêë'
'ìíîïñòóôö'
'ùúûüý'
r'\n]*$',
unicode: true,
);

/// Returns `true` if [value] contains only characters permitted in Swiss
/// payment systems. Empty/null values are considered valid (callers should
/// chain a non-empty check separately).
bool isSwissPaymentText(String? value) {
if (value == null || value.isEmpty) return true;
return _swissPaymentText.hasMatch(value);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:realunit_wallet/generated/i18n.dart';
import 'package:realunit_wallet/packages/service/dfx/models/country/country.dart';
import 'package:realunit_wallet/packages/utils/swiss_payment_text.dart';
import 'package:realunit_wallet/widgets/buttons/app_filled_button.dart';
import 'package:realunit_wallet/widgets/form/country_field.dart';
import 'package:realunit_wallet/widgets/form/labeled_text_field.dart';
Expand Down Expand Up @@ -51,6 +52,7 @@ class KycRegistrationAddressStep extends StatelessWidget {
textCapitalization: TextCapitalization.words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -63,6 +65,7 @@ class KycRegistrationAddressStep extends StatelessWidget {
keyboardType: TextInputType.streetAddress,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -82,6 +85,7 @@ class KycRegistrationAddressStep extends StatelessWidget {
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -96,6 +100,7 @@ class KycRegistrationAddressStep extends StatelessWidget {
textCapitalization: TextCapitalization.words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:realunit_wallet/generated/i18n.dart';
import 'package:realunit_wallet/packages/service/dfx/models/country/country.dart';
import 'package:realunit_wallet/packages/service/dfx/models/registration/registration_user_type.dart';
import 'package:realunit_wallet/packages/utils/swiss_payment_text.dart';
import 'package:realunit_wallet/screens/kyc/steps/registration/cubits/registration_step/kyc_registration_step_cubit.dart';
import 'package:realunit_wallet/widgets/buttons/app_filled_button.dart';
import 'package:realunit_wallet/widgets/form/birthday_field.dart';
Expand Down Expand Up @@ -69,6 +70,7 @@ class KycRegistrationPersonalStep extends StatelessWidget {
textCapitalization: TextCapitalization.words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -82,6 +84,7 @@ class KycRegistrationPersonalStep extends StatelessWidget {
textCapitalization: TextCapitalization.words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand Down
32 changes: 0 additions & 32 deletions lib/screens/settings_contact/cubit/settings_contact_cubit.dart

This file was deleted.

40 changes: 0 additions & 40 deletions lib/screens/settings_contact/cubit/settings_contact_state.dart

This file was deleted.

51 changes: 10 additions & 41 deletions lib/screens/settings_contact/settings_contact_page.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:realunit_wallet/generated/i18n.dart';
import 'package:realunit_wallet/packages/service/dfx/dfx_kyc_service.dart';
import 'package:realunit_wallet/screens/settings_contact/cubit/settings_contact_cubit.dart';
import 'package:realunit_wallet/screens/web_view/web_view_page.dart';
import 'package:realunit_wallet/setup/di.dart';
import 'package:realunit_wallet/setup/routing/routes/app_routes.dart';
import 'package:realunit_wallet/setup/routing/routes/support_routes.dart';
import 'package:realunit_wallet/styles/colors.dart';
Expand All @@ -16,20 +11,6 @@ import 'package:url_launcher/url_launcher.dart';
class SettingsContactPage extends StatelessWidget {
const SettingsContactPage({super.key});

@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SettingsContactCubit(
getIt<DfxKycService>(),
),
child: const SettingsContactView(),
);
}
}

class SettingsContactView extends StatelessWidget {
const SettingsContactView({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -49,28 +30,16 @@ class SettingsContactView extends StatelessWidget {
Column(
spacing: 12.0,
children: [
BlocBuilder<SettingsContactCubit, SettingsContactState>(
builder: (context, state) => switch (state) {
SettingsContactSuccess(:final supportAvailable) =>
supportAvailable
? OutlinedTile(
leading: const Icon(
Icons.support_agent_outlined,
color: RealUnitColors.realUnitBlue,
size: 24,
),
title: S.of(context).contactSupport,
subtitle: S.of(context).contactSupportDescription,
onTap: () => context.pushNamed(SupportRoutes.support),
trailingIcon: Icons.chevron_right_rounded,
)
: const SizedBox.shrink(),
SettingsContactLoading() => const Padding(
padding: EdgeInsets.all(8.0),
child: CupertinoActivityIndicator(),
),
_ => const SizedBox.shrink(),
},
OutlinedTile(
leading: const Icon(
Icons.support_agent_outlined,
color: RealUnitColors.realUnitBlue,
size: 24,
),
title: S.of(context).contactSupport,
subtitle: S.of(context).contactSupportDescription,
onTap: () => context.pushNamed(SupportRoutes.support),
trailingIcon: Icons.chevron_right_rounded,
),
OutlinedTile(
leading: const Icon(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:realunit_wallet/generated/i18n.dart';
import 'package:realunit_wallet/packages/service/dfx/dfx_kyc_service.dart';
import 'package:realunit_wallet/packages/service/dfx/models/country/country.dart';
import 'package:realunit_wallet/packages/utils/swiss_payment_text.dart';
import 'package:realunit_wallet/packages/utils/xfile_extension.dart';
import 'package:realunit_wallet/screens/settings_user_data/subpages/edit_address/cubit/settings_edit_address_cubit.dart';
import 'package:realunit_wallet/screens/settings_user_data/subpages/others/settings_edit_failure_page.dart';
Expand Down Expand Up @@ -111,6 +112,7 @@ class _SettingsEditAddressViewState extends State<SettingsEditAddressView> {
textCapitalization: .words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -121,6 +123,11 @@ class _SettingsEditAddressViewState extends State<SettingsEditAddressView> {
controller: _numberCtrl,
label: S.of(context).number,
keyboardType: .streetAddress,
validator: (value) {
if (value == null || value.isEmpty) return null;
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
),
],
Expand All @@ -138,6 +145,7 @@ class _SettingsEditAddressViewState extends State<SettingsEditAddressView> {
keyboardType: .number,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -152,6 +160,7 @@ class _SettingsEditAddressViewState extends State<SettingsEditAddressView> {
textCapitalization: .words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart';
import 'package:realunit_wallet/generated/i18n.dart';
import 'package:realunit_wallet/packages/service/dfx/dfx_kyc_service.dart';
import 'package:realunit_wallet/packages/utils/swiss_payment_text.dart';
import 'package:realunit_wallet/packages/utils/xfile_extension.dart';
import 'package:realunit_wallet/screens/settings_user_data/subpages/edit_name/cubit/settings_edit_name_cubit.dart';
import 'package:realunit_wallet/screens/settings_user_data/subpages/others/settings_edit_failure_page.dart';
Expand Down Expand Up @@ -98,6 +99,7 @@ class _SettingsEditNameViewState extends State<SettingsEditNameView> {
textCapitalization: .words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand All @@ -108,6 +110,7 @@ class _SettingsEditNameViewState extends State<SettingsEditNameView> {
textCapitalization: .words,
validator: (value) {
if (value == null || value.isEmpty) return '';
if (!isSwissPaymentText(value)) return S.of(context).swissPaymentTextInvalid;
return null;
},
),
Expand Down
10 changes: 0 additions & 10 deletions lib/screens/support/subpages/support_create_ticket_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,11 @@ class SupportCreateTicketView extends StatelessWidget {
S.of(context).supportBugReport,
Icons.bug_report_outlined,
),
(
SupportIssueType.transactionIssue,
S.of(context).supportTransactionIssue,
Icons.swap_horiz,
),
(
SupportIssueType.kycIssue,
S.of(context).supportKycIssue,
Icons.verified_user_outlined,
),
(
SupportIssueType.limitRequest,
S.of(context).supportLimitRequest,
Icons.trending_up,
),
],
selected: state.selectedType,
onSelected: context.read<SupportCreateTicketCubit>().selectType,
Expand Down
Loading
Loading