Merge pull request 'your_tenders_changes' (#91) from your_tenders_changes into main
Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/91
This commit is contained in:
@@ -3,10 +3,25 @@ import 'package:tm_app/data/services/model/tender_approvals_response/tender_appr
|
|||||||
import 'package:tm_app/data/services/your_tenders_service.dart';
|
import 'package:tm_app/data/services/your_tenders_service.dart';
|
||||||
|
|
||||||
class YourTendersRepository {
|
class YourTendersRepository {
|
||||||
final YourTendersService yourTendersService;
|
final YourTendersService _yourTendersService;
|
||||||
YourTendersRepository({required this.yourTendersService});
|
YourTendersRepository({required YourTendersService yourTendersService})
|
||||||
|
: _yourTendersService = yourTendersService;
|
||||||
|
|
||||||
Future<Result<TenderApprovalsResponse>> getApprovedTenders() {
|
Future<Result<TenderApprovalsResponse>> getApprovedTenders() {
|
||||||
return yourTendersService.getApprovedTenders();
|
return _yourTendersService.getApprovedTenders();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Result<TenderApprovalsResponse>> getTenders({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
required String createdFrom,
|
||||||
|
required String createdTo,
|
||||||
|
}) {
|
||||||
|
return _yourTendersService.getTenders(
|
||||||
|
limit: limit,
|
||||||
|
offset: offset,
|
||||||
|
createdFrom: createdFrom,
|
||||||
|
createdTo: createdTo,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
class YourTendersApi {
|
class YourTendersApi {
|
||||||
static const String tenderApprovalsStatus =
|
static const String tenderApprovalsStatus =
|
||||||
'/api/v1/tender-approvals?status=submitted';
|
'/api/v1/tender-approvals?status=submitted';
|
||||||
|
|
||||||
|
static const String tenderApproval = '/api/v1/tender-approvals';
|
||||||
|
|
||||||
|
static String getTenders({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
required String createdFrom,
|
||||||
|
required String createdTo,
|
||||||
|
}) {
|
||||||
|
if (createdFrom.isNotEmpty && createdTo.isNotEmpty) {
|
||||||
|
return '$tenderApproval?limit=$limit&offset=$offset&created_from=$createdFrom&created_to=$createdTo';
|
||||||
|
}
|
||||||
|
return '$tenderApproval?limit=$limit&offset=$offset';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,4 +19,23 @@ class YourTendersService {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Result<TenderApprovalsResponse>> getTenders({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
required String createdFrom,
|
||||||
|
required String createdTo,
|
||||||
|
}) async {
|
||||||
|
final result = await _networkManager.makeRequest(
|
||||||
|
YourTendersApi.getTenders(
|
||||||
|
limit: limit,
|
||||||
|
offset: offset,
|
||||||
|
createdFrom: createdFrom,
|
||||||
|
createdTo: createdTo,
|
||||||
|
),
|
||||||
|
(json) => TenderApprovalsResponse.fromJson(json),
|
||||||
|
method: 'GET',
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import 'package:tm_app/data/services/model/tender_approvals_response/tender_appr
|
|||||||
|
|
||||||
class YourTendersViewModel with ChangeNotifier {
|
class YourTendersViewModel with ChangeNotifier {
|
||||||
final YourTendersRepository yourTendersRepository;
|
final YourTendersRepository yourTendersRepository;
|
||||||
YourTendersViewModel({required this.yourTendersRepository}) {
|
YourTendersViewModel({required this.yourTendersRepository});
|
||||||
getApprovedTenders();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
String? errorMessage;
|
String? errorMessage;
|
||||||
@@ -20,10 +18,24 @@ class YourTendersViewModel with ChangeNotifier {
|
|||||||
final _fmt = DateFormat('yyyy/MM/dd');
|
final _fmt = DateFormat('yyyy/MM/dd');
|
||||||
|
|
||||||
String get startDateFormatted =>
|
String get startDateFormatted =>
|
||||||
selectedDateRange?.start != null ? _fmt.format(selectedDateRange!.start) : 'YYYY/MM/DD';
|
selectedDateRange?.start != null
|
||||||
|
? _fmt.format(selectedDateRange!.start)
|
||||||
|
: 'YYYY/MM/DD';
|
||||||
|
|
||||||
String get endDateFormatted =>
|
String get endDateFormatted =>
|
||||||
selectedDateRange?.end != null ? _fmt.format(selectedDateRange!.end) : 'YYYY/MM/DD';
|
selectedDateRange?.end != null
|
||||||
|
? _fmt.format(selectedDateRange!.end)
|
||||||
|
: 'YYYY/MM/DD';
|
||||||
|
|
||||||
|
int get startDateUnix =>
|
||||||
|
selectedDateRange?.start != null
|
||||||
|
? selectedDateRange!.start.millisecondsSinceEpoch ~/ 1000
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
int get endDateUnix =>
|
||||||
|
selectedDateRange?.end != null
|
||||||
|
? selectedDateRange!.end.millisecondsSinceEpoch ~/ 1000
|
||||||
|
: 0;
|
||||||
|
|
||||||
Future<void> getApprovedTenders() async {
|
Future<void> getApprovedTenders() async {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -45,6 +57,35 @@ class YourTendersViewModel with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> getTenders({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
required String createdFrom,
|
||||||
|
required String createdTo,
|
||||||
|
}) async {
|
||||||
|
isLoading = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
final result = await yourTendersRepository.getTenders(
|
||||||
|
limit: limit,
|
||||||
|
offset: offset,
|
||||||
|
createdFrom: createdFrom,
|
||||||
|
createdTo: createdTo,
|
||||||
|
);
|
||||||
|
switch (result) {
|
||||||
|
case Ok<TenderApprovalsResponse>():
|
||||||
|
data = result.value;
|
||||||
|
errorMessage = null;
|
||||||
|
break;
|
||||||
|
case Error<TenderApprovalsResponse>():
|
||||||
|
errorMessage = result.error.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
// --- Filter Actions ---
|
// --- Filter Actions ---
|
||||||
void setDateRange(DateTimeRange? range) {
|
void setDateRange(DateTimeRange? range) {
|
||||||
selectedDateRange = range;
|
selectedDateRange = range;
|
||||||
@@ -55,4 +96,23 @@ class YourTendersViewModel with ChangeNotifier {
|
|||||||
selectedStatus = status;
|
selectedStatus = status;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearFilter() {
|
||||||
|
selectedDateRange = null;
|
||||||
|
selectedStatus = 'All';
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> callWithFilter() async {
|
||||||
|
if (selectedStatus == 'All') {
|
||||||
|
await getTenders(
|
||||||
|
limit: 10,
|
||||||
|
offset: 0,
|
||||||
|
createdFrom: startDateUnix.toString(),
|
||||||
|
createdTo: endDateUnix.toString(),
|
||||||
|
);
|
||||||
|
} else if (selectedStatus == 'Tenders submitted') {
|
||||||
|
await getApprovedTenders();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ class TenderCard extends StatelessWidget {
|
|||||||
Widget _tenderDescription() {
|
Widget _tenderDescription() {
|
||||||
return Text(
|
return Text(
|
||||||
tender.description ?? '',
|
tender.description ?? '',
|
||||||
maxLines: 7,
|
maxLines: 4,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontSize: 16.0.sp(),
|
fontSize: 16.0.sp(),
|
||||||
|
|||||||
@@ -7,9 +7,29 @@ import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart';
|
|||||||
import 'package:tm_app/views/your_tenders/widgets/filter_button.dart';
|
import 'package:tm_app/views/your_tenders/widgets/filter_button.dart';
|
||||||
import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart';
|
import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart';
|
||||||
|
|
||||||
class YourTendersMobilePage extends StatelessWidget {
|
class YourTendersMobilePage extends StatefulWidget {
|
||||||
const YourTendersMobilePage({super.key});
|
const YourTendersMobilePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<YourTendersMobilePage> createState() => _YourTendersMobilePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _YourTendersMobilePageState extends State<YourTendersMobilePage> {
|
||||||
|
late final YourTendersViewModel viewModel;
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
viewModel = context.read<YourTendersViewModel>();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
viewModel.clearFilter();
|
||||||
|
});
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|||||||
@@ -1,13 +1,35 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||||
import 'package:tm_app/views/shared/responsive_builder.dart';
|
import 'package:tm_app/views/shared/responsive_builder.dart';
|
||||||
import 'package:tm_app/views/your_tenders/pages/your_tenders_desktop_page.dart';
|
import 'package:tm_app/views/your_tenders/pages/your_tenders_desktop_page.dart';
|
||||||
import 'package:tm_app/views/your_tenders/pages/your_tenders_mobile_page.dart';
|
import 'package:tm_app/views/your_tenders/pages/your_tenders_mobile_page.dart';
|
||||||
import 'package:tm_app/views/your_tenders/pages/your_tenders_tablet_page.dart';
|
import 'package:tm_app/views/your_tenders/pages/your_tenders_tablet_page.dart';
|
||||||
|
|
||||||
class YourTendersScreen extends StatelessWidget {
|
class YourTendersScreen extends StatefulWidget {
|
||||||
const YourTendersScreen({super.key});
|
const YourTendersScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<YourTendersScreen> createState() => _YourTendersScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _YourTendersScreenState extends State<YourTendersScreen> {
|
||||||
|
late final YourTendersViewModel viewModel;
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
viewModel = context.read<YourTendersViewModel>();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
viewModel.getTenders(
|
||||||
|
limit: 10,
|
||||||
|
offset: 0,
|
||||||
|
createdFrom: '',
|
||||||
|
createdTo: '',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SizeConfig.init(context);
|
SizeConfig.init(context);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:country_flags/country_flags.dart';
|
import 'package:country_flags/country_flags.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:tm_app/core/utils/date_utils.dart';
|
||||||
|
|
||||||
import '../../../core/constants/assets.dart';
|
import '../../../core/constants/assets.dart';
|
||||||
import '../../../core/theme/colors.dart';
|
import '../../../core/theme/colors.dart';
|
||||||
@@ -63,7 +64,7 @@ class TenderCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
// Date
|
// Date
|
||||||
Text(
|
Text(
|
||||||
date,
|
unixToDate(int.parse(date)),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey60,
|
color: AppColors.grey60,
|
||||||
fontSize: 12.0.sp(),
|
fontSize: 12.0.sp(),
|
||||||
|
|||||||
@@ -64,7 +64,9 @@ class TendersFilterDialog extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
start == null ? YourTendersStrings.startDate : viewModel.startDateFormatted,
|
start == null
|
||||||
|
? YourTendersStrings.startDate
|
||||||
|
: viewModel.startDateFormatted,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0.sp(),
|
fontSize: 16.0.sp(),
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -72,7 +74,9 @@ class TendersFilterDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
end == null ? YourTendersStrings.endDate : viewModel.endDateFormatted,
|
end == null
|
||||||
|
? YourTendersStrings.endDate
|
||||||
|
: viewModel.endDateFormatted,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0.sp(),
|
fontSize: 16.0.sp(),
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -158,6 +162,7 @@ class TendersFilterDialog extends StatelessWidget {
|
|||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pop();
|
context.pop();
|
||||||
|
vm.callWithFilter();
|
||||||
},
|
},
|
||||||
text: YourTendersStrings.confirm,
|
text: YourTendersStrings.confirm,
|
||||||
textColor: AppColors.mainBlue,
|
textColor: AppColors.mainBlue,
|
||||||
|
|||||||
Reference in New Issue
Block a user