Merge pull request 'show message when there is error in submit or remove approvals' (#102) from like_tenders_error_approval into main

Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/102
This commit is contained in:
a.ghabeli
2025-09-06 14:11:19 +03:30
6 changed files with 137 additions and 88 deletions
+9 -9
View File
@@ -21,7 +21,7 @@ class FetchDataException extends AppException {
FetchDataException([String? message, int? statusCode, originalError])
: super(
message ?? 'Error During Communication: ',
'Network Error',
'Network Error : ',
statusCode,
originalError,
);
@@ -31,7 +31,7 @@ class AuthenticationException extends AppException {
AuthenticationException([String? message, int? statusCode, originalError])
: super(
message ?? 'Authentication Failed.',
'Auth Error: ',
'Auth Error : ',
statusCode,
originalError,
);
@@ -41,7 +41,7 @@ class NetworkConnectionException extends AppException {
NetworkConnectionException([String? message, originalError])
: super(
message ?? 'No internet connection available.',
'Connection Error: ',
'Connection Error : ',
null,
originalError,
);
@@ -51,7 +51,7 @@ class TimeoutException extends AppException {
TimeoutException([String? message, originalError])
: super(
message ?? 'Request timed out.',
'Timeout Error: ',
'Timeout Error : ',
null,
originalError,
);
@@ -61,7 +61,7 @@ class ServerException extends AppException {
ServerException([String? message, int? statusCode, originalError])
: super(
message ?? 'Server error occurred.',
'Server Error: ',
'Server Error : ',
statusCode,
originalError,
);
@@ -71,7 +71,7 @@ class BadRequestException extends AppException {
BadRequestException([String? message, int? statusCode, originalError])
: super(
message ?? 'Bad request.',
'Bad Request Error: ',
'Bad Request Error : ',
statusCode,
originalError,
);
@@ -81,7 +81,7 @@ class NotFoundException extends AppException {
NotFoundException([String? message, int? statusCode, originalError])
: super(
message ?? 'Resource not found.',
'Not Found Error: ',
'Not Found Error : ',
statusCode,
originalError,
);
@@ -91,7 +91,7 @@ class ForbiddenException extends AppException {
ForbiddenException([String? message, int? statusCode, originalError])
: super(
message ?? 'Access forbidden.',
'Forbidden Error: ',
'Forbidden Error : ',
statusCode,
originalError,
);
@@ -101,7 +101,7 @@ class RateLimitException extends AppException {
RateLimitException([String? message, int? statusCode, originalError])
: super(
message ?? 'Rate limit exceeded.',
'Rate Limit Error: ',
'Rate Limit Error : ',
statusCode,
originalError,
);
+13 -13
View File
@@ -6,22 +6,22 @@ import '../../../core/network/network_manager.dart';
class LikedTendersService {
LikedTendersService({required NetworkManager networkManager})
: _networkManager = networkManager;
: _networkManager = networkManager;
final NetworkManager _networkManager;
Future<Result<LikedTendersResponse>> getLikedTenders({
int offset = 0,
int limit = 20,
}) async {
final uri = '${LikedTendersApi.likedTenders}&limit=$limit&offset=$offset';
Future<Result<LikedTendersResponse>> getLikedTenders({
int offset = 0,
int limit = 20,
}) async {
final uri = '${LikedTendersApi.likedTenders}&limit=$limit&offset=$offset';
final result = await _networkManager.makeRequest(
uri,
(json) => LikedTendersResponse.fromJson(json),
method: 'GET',
);
final result = await _networkManager.makeRequest(
uri,
(json) => LikedTendersResponse.fromJson(json),
method: 'GET',
);
return result;
}
return result;
}
}
@@ -55,6 +55,11 @@ class LikedTendersViewModel with ChangeNotifier {
_homeViewModel.init();
}
void clearApprovalErrorMessage() {
_errorMessage = null;
notifyListeners();
}
Future<void> getLikedTenders({bool reset = false}) async {
if (!reset && (isLoadingMore || !hasMore)) {
return;
@@ -303,7 +308,7 @@ class LikedTendersViewModel with ChangeNotifier {
approvalStatus = false;
break;
}
approvalStatus = false;
_isSubmitApprovalLoading = false;
notifyListeners();
}
@@ -370,6 +375,7 @@ class LikedTendersViewModel with ChangeNotifier {
break;
}
approvalStatus = false;
_isRejectApprovalLoading = false;
notifyListeners();
}
@@ -24,9 +24,26 @@ class _LikedTendersDesktopPageState extends State<LikedTendersDesktopPage> {
@override
void initState() {
viewModel = context.read<LikedTendersViewModel>();
viewModel.addListener(_viewModelListener);
super.initState();
}
void _viewModelListener() {
if (viewModel.approvalErrorMessage?.isNotEmpty == true &&
viewModel.approvalStatus == false) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(viewModel.approvalErrorMessage!)));
viewModel.clearApprovalErrorMessage();
}
}
@override
void dispose() {
viewModel.removeListener(_viewModelListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return PopScope(
@@ -27,6 +27,18 @@ class _LikedTendersMobilePageState extends State<LikedTendersMobilePage> {
viewModel = context.read<LikedTendersViewModel>();
super.initState();
_scrollController = ScrollController()..addListener(_onScroll);
viewModel.addListener(_viewModelListener);
}
void _viewModelListener() {
if (mounted &&
viewModel.approvalErrorMessage?.isNotEmpty == true &&
viewModel.approvalStatus == false) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(viewModel.approvalErrorMessage!)));
viewModel.clearApprovalErrorMessage();
}
}
void _onScroll() {
@@ -46,6 +58,7 @@ class _LikedTendersMobilePageState extends State<LikedTendersMobilePage> {
void dispose() {
_scrollController.removeListener(_onScroll);
_scrollController.dispose();
viewModel.removeListener(_viewModelListener);
super.dispose();
}
@@ -94,75 +107,71 @@ class _LikedTendersMobilePageState extends State<LikedTendersMobilePage> {
final itemCount =
feedback.length + (viewModel.isLoadingMore ? 1 : 0);
return RefreshIndicator(
onRefresh: () async {
await viewModel.getLikedTenders(reset: true);
},
child: ListView.builder(
controller: _scrollController,
padding: EdgeInsets.symmetric(
horizontal: 24.0.w(),
vertical: 15.0.h(),
),
itemCount: itemCount,
itemBuilder: (context, index) {
if (index < feedback.length) {
final item = feedback[index];
TenderApprovalsData? approval;
bool hasApproval = viewModel
.hasTenderApprovalForTender(item.tenderId!);
if (hasApproval) {
approval = viewModel.getApprovalStatusForTender(
item.tenderId!,
);
} else {
approval = null;
}
return Padding(
padding: EdgeInsets.only(bottom: 20.0.h()),
child: Dismissible(
key: ValueKey(item.tenderId ?? index),
direction: DismissDirection.endToStart,
background: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(
horizontal: 20.0.w(),
),
child: SvgPicture.asset(
AssetsManager.trash,
width: 32.0.w(),
height: 32.0.h(),
),
),
onDismissed: (_) {
if (item.tenderId != null) {
viewModel.removeTenderById(item.tenderId!);
}
},
child: LikedListItem(
tender: item.tender!,
approval: approval,
),
),
return ListView.builder(
controller: _scrollController,
padding: EdgeInsets.symmetric(
horizontal: 24.0.w(),
vertical: 15.0.h(),
),
itemCount: itemCount,
itemBuilder: (context, index) {
if (index < feedback.length) {
final item = feedback[index];
TenderApprovalsData? approval;
bool hasApproval = viewModel.hasTenderApprovalForTender(
item.tenderId!,
);
if (hasApproval) {
approval = viewModel.getApprovalStatusForTender(
item.tenderId!,
);
} else {
return Padding(
padding: EdgeInsets.symmetric(vertical: 20.0.h()),
child: Center(
child: SizedBox(
width: 24.0.w(),
height: 24.0.h(),
child: CircularProgressIndicator(
color: AppColors.secondary50,
strokeWidth: 2,
),
approval = null;
}
return Padding(
padding: EdgeInsets.only(bottom: 20.0.h()),
child: Dismissible(
key: ValueKey(item.tenderId ?? index),
direction: DismissDirection.endToStart,
background: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(
horizontal: 20.0.w(),
),
child: SvgPicture.asset(
AssetsManager.trash,
width: 32.0.w(),
height: 32.0.h(),
),
),
);
}
},
),
onDismissed: (_) {
if (item.tenderId != null) {
viewModel.removeTenderById(item.tenderId!);
}
},
child: LikedListItem(
tender: item.tender!,
approval: approval,
),
),
);
} else {
return Padding(
padding: EdgeInsets.symmetric(vertical: 20.0.h()),
child: Center(
child: SizedBox(
width: 24.0.w(),
height: 24.0.h(),
child: CircularProgressIndicator(
color: AppColors.secondary50,
strokeWidth: 2,
),
),
),
);
}
},
);
},
),
@@ -26,6 +26,23 @@ class _LikedTendersTabletPageState extends State<LikedTendersTabletPage> {
void initState() {
viewModel = context.read<LikedTendersViewModel>();
super.initState();
viewModel.addListener(_viewModelListener);
}
void _viewModelListener() {
if (viewModel.approvalErrorMessage?.isNotEmpty == true &&
viewModel.approvalStatus == false) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(viewModel.approvalErrorMessage!)));
viewModel.clearApprovalErrorMessage();
}
}
@override
void dispose() {
viewModel.removeListener(_viewModelListener);
super.dispose();
}
@override