You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
16 KiB
Dart
369 lines
16 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:mc_common_app/classes/app_state.dart';
|
|
import 'package:mc_common_app/extensions/int_extensions.dart';
|
|
import 'package:mc_common_app/extensions/string_extensions.dart';
|
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
|
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
|
|
import 'package:mc_common_app/models/subscriptions_models/branch_user_selection_model.dart';
|
|
import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart';
|
|
import 'package:mc_common_app/theme/colors.dart';
|
|
import 'package:mc_common_app/utils/enums.dart';
|
|
import 'package:mc_common_app/utils/navigator.dart';
|
|
import 'package:mc_common_app/utils/utils.dart';
|
|
import 'package:mc_common_app/view_models/payment_view_model.dart';
|
|
import 'package:mc_common_app/view_models/subscriptions_view_model.dart';
|
|
import 'package:mc_common_app/views/payments/payment_methods_view.dart';
|
|
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
|
class DowngradeDataSheet extends StatefulWidget {
|
|
final Subscription subscription;
|
|
|
|
const DowngradeDataSheet(this.subscription, {super.key});
|
|
|
|
@override
|
|
State<DowngradeDataSheet> createState() => _DowngradeDataSheetState();
|
|
}
|
|
|
|
class _DowngradeDataSheetState extends State<DowngradeDataSheet> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
context.read<SubscriptionsVM>().getSPBranchUserGet();
|
|
}
|
|
|
|
// The provider's current active plan (not the plan being downgraded to) holds how many
|
|
// branches/sub-users they currently have -- confirmed with the user this is where
|
|
// "current totals" come from, as opposed to widget.subscription which is the target plan.
|
|
Subscription? get _currentSubscription {
|
|
final list = AppState().getproviderSubscription;
|
|
return list.isEmpty ? null : list.first;
|
|
}
|
|
|
|
// subscriptionBranches/subscriptionSubUsers are each plan's own allowed quota.
|
|
// totalBranches/totalSubUsers looked plausible but turned out to be unrelated (they
|
|
// read identically on both the current and target plan records in testing).
|
|
int get _currentBranches => _currentSubscription?.subscriptionBranches ?? 0;
|
|
|
|
int get _currentUsers => _currentSubscription?.subscriptionSubUsers ?? 0;
|
|
|
|
int get _targetBranches => widget.subscription.subscriptionBranches ?? 0;
|
|
|
|
int get _targetUsers => widget.subscription.subscriptionSubUsers ?? 0;
|
|
|
|
int get _branchesToRemove => (_currentBranches - _targetBranches).clamp(0, _currentBranches);
|
|
|
|
int get _usersToRemove => (_currentUsers - _targetUsers).clamp(0, _currentUsers);
|
|
|
|
// Selecting a whole branch removes every user in it too, so that counts towards the
|
|
// user quota as well, not just the branch quota.
|
|
_SelectedCounts _selectedCounts(List<BranchSelectionModel> branchSelectionList) {
|
|
int selectedBranches = 0;
|
|
int selectedUsers = 0;
|
|
for (var branch in branchSelectionList) {
|
|
if (branch.isSelected) {
|
|
selectedBranches++;
|
|
selectedUsers += branch.usersList.length;
|
|
} else {
|
|
selectedUsers += branch.usersList.where((u) => u.isSelected).length;
|
|
}
|
|
}
|
|
return _SelectedCounts(selectedBranches, selectedUsers);
|
|
}
|
|
|
|
Widget _buildRequirementCounter(List<BranchSelectionModel> branchSelectionList) {
|
|
final counts = _selectedCounts(branchSelectionList);
|
|
final remainingBranches = (_branchesToRemove - counts.branches).clamp(0, _branchesToRemove);
|
|
final remainingUsers = (_usersToRemove - counts.users).clamp(0, _usersToRemove);
|
|
|
|
if (remainingBranches == 0 && remainingUsers == 0) {
|
|
return "You have selected enough branches/users to downgrade.".toText(fontSize: 13, color: MyColors.primaryColor, isBold: true);
|
|
}
|
|
|
|
final parts = <String>[
|
|
if (remainingBranches > 0) "$remainingBranches more branch${remainingBranches == 1 ? '' : 'es'}",
|
|
if (remainingUsers > 0) "$remainingUsers more user${remainingUsers == 1 ? '' : 's'}",
|
|
];
|
|
return "Select ${parts.join(' and ')} to downgrade.".toText(fontSize: 13, color: MyColors.textColor, isBold: true);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final targetBranchesText = "$_targetBranches branch${_targetBranches == 1 ? '' : 'es'}";
|
|
final targetUsersText = "$_targetUsers sub-user${_targetUsers == 1 ? '' : 's'}";
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
height: MediaQuery.of(context).size.height / 1.2,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(12),
|
|
child: Column(
|
|
children: [
|
|
"Deactivate the branches & users".toText(
|
|
fontSize: 19,
|
|
isBold: true,
|
|
),
|
|
8.height,
|
|
LocaleKeys.downgradeDeactivateInstruction.tr(namedArgs: {'branches': targetBranchesText, 'users': targetUsersText}).toText(
|
|
fontSize: 14,
|
|
color: MyColors.textColor,
|
|
),
|
|
12.height,
|
|
// isStartNow is passed as false for a downgrade, so the new package isn't
|
|
// applied immediately -- it takes effect once the current one expires. Make
|
|
// that explicit so it isn't mistaken for an immediate switch.
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Icon(Icons.info_outline_rounded, size: 18, color: MyColors.textColor),
|
|
8.width,
|
|
Expanded(
|
|
child: LocaleKeys.downgradeAppliedAfterExpiry.tr().toText(fontSize: 13, color: MyColors.textColor),
|
|
),
|
|
],
|
|
).toContainer(
|
|
backgroundColor: MyColors.greyButtonColor,
|
|
paddingAll: 10,
|
|
borderRadius: 6,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Consumer<SubscriptionsVM>(
|
|
builder: (BuildContext context, model, Widget? child) {
|
|
final counts = model.branchSelectionList == null ? _SelectedCounts(0, 0) : _selectedCounts(model.branchSelectionList!);
|
|
final canProceed = model.branchSelectionList != null && counts.branches >= _branchesToRemove && counts.users >= _usersToRemove;
|
|
return Column(
|
|
children: [
|
|
if (model.branchSelectionList != null)
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
child: _buildRequirementCounter(model.branchSelectionList!),
|
|
),
|
|
if (model.branchSelectionList != null) 8.height,
|
|
Expanded(
|
|
child: model.branchSelectionList == null
|
|
? const Center(child: CircularProgressIndicator())
|
|
: ListView.separated(
|
|
itemBuilder: (context, index) {
|
|
return showBranchItem(model, model.branchSelectionList![index]);
|
|
},
|
|
separatorBuilder: (context, index) {
|
|
return 12.height;
|
|
},
|
|
padding: const EdgeInsets.all(12),
|
|
itemCount: model.branchSelectionList?.length ?? 0,
|
|
),
|
|
),
|
|
ShowFillButton(
|
|
title: LocaleKeys.next.tr(),
|
|
maxWidth: double.infinity,
|
|
margin: const EdgeInsets.all(12),
|
|
isDisabled: !canProceed,
|
|
onPressed: () async {
|
|
List<int> listOfBranches = [];
|
|
List<int> listOfUsers = [];
|
|
for (var branch in model.branchSelectionList!) {
|
|
if (branch.isSelected) {
|
|
listOfBranches.add(branch.branchId);
|
|
for (var user in branch.usersList) {
|
|
listOfUsers.add(user.userId);
|
|
}
|
|
} else {
|
|
for (var user in branch.usersList) {
|
|
if (user.isSelected) {
|
|
listOfUsers.add(user.userId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (listOfBranches.isNotEmpty || listOfUsers.isNotEmpty) {
|
|
navigateTo(
|
|
context,
|
|
PaymentMethodsView(
|
|
paymentType: PaymentTypes.subscription,
|
|
onTempContinue: () async {
|
|
Utils.showLoading(context);
|
|
GenericRespModel response = await model.payForSubscription(
|
|
subscriptionId: widget.subscription.id!,
|
|
isStartNow: false,
|
|
isRenew: false,
|
|
amount: widget.subscription.price.toString(),
|
|
isDegrade: true,
|
|
listOfBranches: listOfBranches,
|
|
listOfUsers: listOfUsers,
|
|
);
|
|
|
|
Utils.hideLoading(context);
|
|
|
|
if (response.messageStatus == 1) {
|
|
if (response.message!.contains("Your current sub-users are not")) {
|
|
Utils.showToast(response.message.toString());
|
|
context.read<SubscriptionsVM>().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
|
|
pop(context);
|
|
return false;
|
|
} else {
|
|
context.read<PaymentVM>().updateOrderProviderSubscriptionId(id: response.data);
|
|
|
|
// Utils.showToast(
|
|
// "Subscriptions is successfully updated");
|
|
return true;
|
|
}
|
|
} else {
|
|
Utils.showToast(response.message.toString());
|
|
context.read<SubscriptionsVM>().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
|
|
return false;
|
|
}
|
|
},
|
|
),
|
|
);
|
|
}
|
|
},
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget showBranchItem(SubscriptionsVM viewModel, BranchSelectionModel model) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// Padding around the checkbox widens its tap target (18x18 alone is too small to
|
|
// hit reliably) without growing the checkbox's own visual size or changing the
|
|
// row's separate tap-to-expand behavior.
|
|
Padding(
|
|
padding: const EdgeInsets.all(10),
|
|
child: customCheckBox(model.isSelected),
|
|
).onPress(() {
|
|
model.isSelected = !model.isSelected;
|
|
if (model.isSelected) {
|
|
for (var user in model.usersList) {
|
|
user.isSelected = true;
|
|
}
|
|
} else {
|
|
for (var user in model.usersList) {
|
|
user.isSelected = false;
|
|
}
|
|
}
|
|
model.isOpend = true;
|
|
viewModel.setState(ViewState.idle);
|
|
}),
|
|
12.width,
|
|
Expanded(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
model.branchName.toText(
|
|
fontSize: 18,
|
|
isBold: true,
|
|
),
|
|
("${model.usersList.length} Users").toText(
|
|
fontSize: 10,
|
|
color: MyColors.lightTextColor,
|
|
)
|
|
],
|
|
),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
model.isOpend ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (model.isOpend) 12.height,
|
|
if (model.isOpend)
|
|
ListView.separated(
|
|
itemBuilder: (context, index) {
|
|
return Row(
|
|
children: [
|
|
customCheckBox(model.usersList[index].isSelected),
|
|
8.width,
|
|
model.usersList[index].userName.toText(
|
|
fontSize: 14,
|
|
),
|
|
],
|
|
).onPress(() {
|
|
// for (int i = 0; i < model.usersList.length; i++) {
|
|
// if (i != index) {
|
|
// model.usersList[index].isSelected = false;
|
|
// }
|
|
// }
|
|
model.usersList[index].isSelected = !model.usersList[index].isSelected;
|
|
viewModel.setState(ViewState.idle);
|
|
});
|
|
},
|
|
separatorBuilder: (context, index) {
|
|
return 12.height;
|
|
},
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
shrinkWrap: true,
|
|
itemCount: model.usersList.length,
|
|
),
|
|
],
|
|
).onPress(() {
|
|
model.isOpend = !model.isOpend;
|
|
viewModel.setState(ViewState.idle);
|
|
}),
|
|
)
|
|
],
|
|
).toWhiteContainer(
|
|
width: double.infinity,
|
|
pading: const EdgeInsets.all(12),
|
|
);
|
|
}
|
|
|
|
Widget customCheckBox(bool isChecked) {
|
|
return SizedBox(
|
|
height: 18,
|
|
width: 18,
|
|
child: isChecked
|
|
? const Icon(
|
|
Icons.done,
|
|
color: Colors.white,
|
|
size: 14,
|
|
)
|
|
: const SizedBox(),
|
|
).toContainer(
|
|
isEnabledBorder: true,
|
|
paddingAll: 0,
|
|
borderRadius: 0,
|
|
borderWidget: 1,
|
|
borderColor: MyColors.primaryColor,
|
|
backgroundColor: isChecked ? MyColors.primaryColor : Colors.transparent,
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SelectedCounts {
|
|
final int branches;
|
|
final int users;
|
|
|
|
_SelectedCounts(this.branches, this.users);
|
|
}
|