-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add option to change the type of user (#1349)
## Description A user can change twice every two weeks their type of user in the app setting without contacting the support. ## Demo ### Changing type of user https://github.com/SharezoneApp/sharezone-app/assets/24459435/9300571b-5e09-4b96-b103-76b41b7cfec2 ### When the user changed too often the type of user https://github.com/SharezoneApp/sharezone-app/assets/24459435/cce72970-4b1b-4aba-926e-efca5760554d ## Related tickets Closes #556
- Loading branch information
1 parent
a8ba1c8
commit 18b3d0e
Showing
25 changed files
with
772 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
...b/settings/src/subpages/my_profile/change_type_of_user/change_type_of_user_analytics.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) 2023 Sharezone UG (haftungsbeschränkt) | ||
// Licensed under the EUPL-1.2-or-later. | ||
// | ||
// You may obtain a copy of the Licence at: | ||
// https://joinup.ec.europa.eu/software/page/eupl | ||
// | ||
// SPDX-License-Identifier: EUPL-1.2 | ||
|
||
import 'package:analytics/analytics.dart'; | ||
import 'package:user/user.dart'; | ||
|
||
class ChangeTypeOfUserAnalytics { | ||
final Analytics analytics; | ||
|
||
const ChangeTypeOfUserAnalytics(this.analytics); | ||
|
||
void logChangedOrder({ | ||
required TypeOfUser? from, | ||
required TypeOfUser to, | ||
}) { | ||
analytics.log( | ||
ChangeOfTypeOfUserAnalyticsEvent( | ||
data: { | ||
'from': from?.name, | ||
'to': to.name, | ||
}, | ||
), | ||
); | ||
} | ||
} | ||
|
||
class ChangeOfTypeOfUserAnalyticsEvent extends AnalyticsEvent { | ||
const ChangeOfTypeOfUserAnalyticsEvent({ | ||
Map<String, dynamic>? data, | ||
}) : super('changed_type_of_user', data: data); | ||
} |
151 changes: 151 additions & 0 deletions
151
.../settings/src/subpages/my_profile/change_type_of_user/change_type_of_user_controller.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// Copyright (c) 2024 Sharezone UG (haftungsbeschränkt) | ||
// Licensed under the EUPL-1.2-or-later. | ||
// | ||
// You may obtain a copy of the Licence at: | ||
// https://joinup.ec.europa.eu/software/page/eupl | ||
// | ||
// SPDX-License-Identifier: EUPL-1.2 | ||
|
||
import 'dart:async'; | ||
import 'dart:convert'; | ||
|
||
import 'package:cloud_functions/cloud_functions.dart'; | ||
import 'package:common_domain_models/common_domain_models.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:sharezone/settings/src/subpages/my_profile/change_type_of_user/change_type_of_user_analytics.dart'; | ||
import 'package:sharezone/settings/src/subpages/my_profile/change_type_of_user/change_type_of_user_service.dart'; | ||
import 'package:user/user.dart'; | ||
|
||
class ChangeTypeOfUserController extends ChangeNotifier { | ||
final UserId userId; | ||
final ChangeTypeOfUserAnalytics analytics; | ||
final ChangeTypeOfUserService service; | ||
StreamSubscription<TypeOfUser?>? _typeOfUserSubscription; | ||
|
||
late ChangeTypeOfUserState state; | ||
|
||
/// The initial type of user of the user before the change. | ||
TypeOfUser? initialTypeOfUser; | ||
|
||
/// The currently selected type of user. | ||
TypeOfUser? selectedTypeOfUser; | ||
|
||
ChangeTypeOfUserController({ | ||
required this.userId, | ||
required this.analytics, | ||
required this.service, | ||
required Stream<TypeOfUser?> typeOfUserStream, | ||
}) { | ||
state = const ChangeTypeOfUserInitial(); | ||
_listenToTypeOfUserStream(typeOfUserStream); | ||
} | ||
|
||
void _listenToTypeOfUserStream(Stream<TypeOfUser?> typeOfUserStream) { | ||
_typeOfUserSubscription = typeOfUserStream.listen((typeOfUser) { | ||
initialTypeOfUser = typeOfUser; | ||
notifyListeners(); | ||
}); | ||
} | ||
|
||
Future<void> changeTypeOfUser() async { | ||
final typeOfUser = selectedTypeOfUser; | ||
if (typeOfUser == null) { | ||
throw const NoTypeOfUserSelectedException(); | ||
} | ||
|
||
if (typeOfUser == initialTypeOfUser) { | ||
throw const TypeUserOfUserHasNotChangedException(); | ||
} | ||
|
||
try { | ||
state = const ChangeTypeOfUserLoading(); | ||
notifyListeners(); | ||
|
||
await service.changeTypeOfUser(typeOfUser); | ||
|
||
analytics.logChangedOrder( | ||
from: initialTypeOfUser, | ||
to: typeOfUser, | ||
); | ||
initialTypeOfUser = typeOfUser; | ||
} on FirebaseFunctionsException catch (e) { | ||
_parseException(e); | ||
} catch (e) { | ||
throw ChangeTypeOfUserUnknownException(e); | ||
} finally { | ||
state = const ChangeTypeOfUserInitial(); | ||
notifyListeners(); | ||
} | ||
} | ||
|
||
void _parseException(FirebaseFunctionsException e) { | ||
final unknownErrorMessage = '[${e.plugin}/${e.code}] ${e.message}'; | ||
if (e.code != 'failed-precondition') { | ||
throw ChangeTypeOfUserUnknownException(unknownErrorMessage); | ||
} | ||
|
||
try { | ||
final json = jsonDecode(e.message!); | ||
if (json['errorId'] == 'typeofuser-change-limit-reached') { | ||
final blockedUntil = DateTime.parse(json['blockedUntil']); | ||
throw ChangedTypeOfUserTooOftenException( | ||
blockedUntil: blockedUntil, | ||
); | ||
} else { | ||
throw ChangeTypeOfUserUnknownException(unknownErrorMessage); | ||
} | ||
} catch (e) { | ||
if (e is ChangedTypeOfUserTooOftenException) rethrow; | ||
throw ChangeTypeOfUserUnknownException(unknownErrorMessage); | ||
} | ||
} | ||
|
||
void setSelectedTypeOfUser(TypeOfUser typeOfUser) { | ||
selectedTypeOfUser = typeOfUser; | ||
notifyListeners(); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_typeOfUserSubscription?.cancel(); | ||
super.dispose(); | ||
} | ||
} | ||
|
||
sealed class ChangeTypeOfUserState { | ||
const ChangeTypeOfUserState(); | ||
} | ||
|
||
class ChangeTypeOfUserInitial extends ChangeTypeOfUserState { | ||
const ChangeTypeOfUserInitial(); | ||
} | ||
|
||
class ChangeTypeOfUserLoading extends ChangeTypeOfUserState { | ||
const ChangeTypeOfUserLoading(); | ||
} | ||
|
||
sealed class ChangeTypeOfUserFailed { | ||
const ChangeTypeOfUserFailed(); | ||
} | ||
|
||
class NoTypeOfUserSelectedException extends ChangeTypeOfUserFailed { | ||
const NoTypeOfUserSelectedException(); | ||
} | ||
|
||
class TypeUserOfUserHasNotChangedException extends ChangeTypeOfUserFailed { | ||
const TypeUserOfUserHasNotChangedException(); | ||
} | ||
|
||
class ChangedTypeOfUserTooOftenException extends ChangeTypeOfUserFailed { | ||
final DateTime blockedUntil; | ||
|
||
const ChangedTypeOfUserTooOftenException({ | ||
required this.blockedUntil, | ||
}); | ||
} | ||
|
||
class ChangeTypeOfUserUnknownException extends ChangeTypeOfUserFailed { | ||
final Object? error; | ||
|
||
const ChangeTypeOfUserUnknownException(this.error); | ||
} |
Oops, something went wrong.