Merge pull request 'refactor' (#74) from refactor into main
Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/74
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
class AppStrings {
|
class AppStrings {
|
||||||
AppStrings._();
|
AppStrings._();
|
||||||
|
|
||||||
|
static const String noData = 'No data';
|
||||||
|
|
||||||
// App Titles
|
// App Titles
|
||||||
static const String appName = 'My Awesome App';
|
static const String appName = 'My Awesome App';
|
||||||
static const String loginTitle = 'Welcome Back';
|
static const String loginTitle = 'Welcome Back';
|
||||||
@@ -50,6 +53,12 @@ class AppStrings {
|
|||||||
static const String profile = 'Profile';
|
static const String profile = 'Profile';
|
||||||
static const String settings = 'Settings';
|
static const String settings = 'Settings';
|
||||||
static const String appTheme = 'App Theme';
|
static const String appTheme = 'App Theme';
|
||||||
|
static const String companyName = 'Company Name';
|
||||||
|
static const String nationalId = 'National ID';
|
||||||
|
static const String registrationNumber = 'Registration No.';
|
||||||
|
static const String businessType = 'Business Type';
|
||||||
|
static const String founded = 'Founded';
|
||||||
|
static const String logout = 'Logout';
|
||||||
|
|
||||||
//your tenders
|
//your tenders
|
||||||
static const String yourTendersTitle = 'Your tenders';
|
static const String yourTendersTitle = 'Your tenders';
|
||||||
@@ -65,7 +74,6 @@ class AppStrings {
|
|||||||
static const String tenderDeliveryLocationsLabel = 'Delivery Locations';
|
static const String tenderDeliveryLocationsLabel = 'Delivery Locations';
|
||||||
static const String tenderReferenceNumberLabel = 'Reference Number';
|
static const String tenderReferenceNumberLabel = 'Reference Number';
|
||||||
static const String tenderLocationLabel = 'Locations';
|
static const String tenderLocationLabel = 'Locations';
|
||||||
static const String tenderLocationCountry = 'UK';
|
|
||||||
static const String tenderPdfDocument = 'PDF , Document';
|
static const String tenderPdfDocument = 'PDF , Document';
|
||||||
static const String tenderMatchProfile = 'Match with your profile';
|
static const String tenderMatchProfile = 'Match with your profile';
|
||||||
static const String tenderIncompleteResume = 'Incomplete Resume Information';
|
static const String tenderIncompleteResume = 'Incomplete Resume Information';
|
||||||
@@ -73,21 +81,17 @@ class AppStrings {
|
|||||||
'No experience in e-platform development';
|
'No experience in e-platform development';
|
||||||
static const String tenderSubmitButton = 'Submit';
|
static const String tenderSubmitButton = 'Submit';
|
||||||
static const String tenderRejectButton = 'Reject';
|
static const String tenderRejectButton = 'Reject';
|
||||||
static const String tenderDateExample = '2025-05-21';
|
|
||||||
static const String tenderTitleExample =
|
|
||||||
'Operation, support and further development of open e-platform Operation, support and further development of open e-platform';
|
|
||||||
static const String tenderIdExample = 'JNDFKMDV-100-JF';
|
|
||||||
static const String tenderApprovalDateExample = '2025-05-21';
|
|
||||||
static const String tenderSubmissionDateExample = '2025-05-21';
|
|
||||||
static const String tenderClientExample =
|
static const String tenderClientExample =
|
||||||
'Procurement Notice Procurement Notice';
|
'Procurement Notice Procurement Notice';
|
||||||
static const String tenderDeliveryLocationExample = 'Norrbotten County';
|
|
||||||
static const String tenderReferenceNumberExample = 'KLF 2025/120';
|
|
||||||
static const String tenderDescriptionExample =
|
|
||||||
'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten)...';
|
|
||||||
static const String tenderMatchPercentageExample = '75%';
|
|
||||||
static const String locationDescription =
|
|
||||||
'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).
The procurement includes operation, support, and further development of the existing open e-platform.
No additional information, amendments, or answers to questions will be provided after June 16.o additional information, amendments, or answers to questions will be provided after June 16.o additional information, amendments, or answers to questions will be provided after June 16.website: www.tenders.com Lorem ipsum is amet Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).
The procurement includes operation, support, and further development of the existing open e-platform.
No additional information, amendments, or answers to questions will be provided after June 16. o additional information, amendments, or answers to questions will be provided after June 16. o additional information, amendments, or answers to questions will be provided after June 16.website: www.tenders.com';
|
|
||||||
static const String estimatedValue = 'Estimated Value ';
|
static const String estimatedValue = 'Estimated Value ';
|
||||||
static const String duration = 'Duration';
|
static const String duration = 'Duration';
|
||||||
|
static const String tenderSubmittedSuccessfully =
|
||||||
|
'tender submitted successfully!';
|
||||||
|
static const String tenderRejectedSuccessfully =
|
||||||
|
'tender rejected successfully!';
|
||||||
|
static const String tenderUnrejectedSuccessfully =
|
||||||
|
'tender unrejected successfully!';
|
||||||
|
static const String tenderUnsubmittedSuccessfully =
|
||||||
|
'tender unsubmitted successfully!';
|
||||||
|
static const String tenderNoData = 'No tender details available';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ class NetworkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _addInterceptors() {
|
void _addInterceptors() {
|
||||||
if (_interceptorsAdded) return;
|
if (_interceptorsAdded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final requestInterceptor = InterceptorsWrapper(
|
final requestInterceptor = InterceptorsWrapper(
|
||||||
onRequest: (options, handler) {
|
onRequest: (options, handler) {
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ class AppShellScreen extends StatelessWidget {
|
|||||||
final StatefulNavigationShell navigationShell;
|
final StatefulNavigationShell navigationShell;
|
||||||
|
|
||||||
void _gotoBranch(int index, BuildContext context) {
|
void _gotoBranch(int index, BuildContext context) {
|
||||||
|
if (index == navigationShell.currentIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
navigationShell.goBranch(
|
navigationShell.goBranch(
|
||||||
index,
|
index,
|
||||||
initialLocation: index == navigationShell.currentIndex,
|
initialLocation: index == navigationShell.currentIndex,
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ class AppColors {
|
|||||||
// static const Color red0 = Color(0xFF312F2F);
|
// static const Color red0 = Color(0xFF312F2F);
|
||||||
// static const Color red10 = Color(0xFF524545);
|
// static const Color red10 = Color(0xFF524545);
|
||||||
static const Color red = Color(0xFFFF3B30);
|
static const Color red = Color(0xFFFF3B30);
|
||||||
|
static const Color orange = Color(0xFFE5821E);
|
||||||
|
|
||||||
// Other colors
|
// Other colors
|
||||||
static const Color lightBlue = Color(0xFFe8ecfc);
|
static const Color lightBlue = Color(0xFFe8ecfc);
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class DateUtils {
|
/// Extension on int to provide date formatting utilities for Unix timestamps
|
||||||
|
extension UnixTimestampExtension on int? {
|
||||||
/// Converts Unix timestamp (seconds since epoch) to a formatted date string
|
/// Converts Unix timestamp (seconds since epoch) to a formatted date string
|
||||||
static String unixToDate(int? unixTimestamp, {String format = 'yyyy-MM-dd'}) {
|
String toDate({String format = 'yyyy-MM-dd'}) {
|
||||||
if (unixTimestamp == null) return '';
|
if (this == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
// Convert seconds to milliseconds if needed
|
// Convert seconds to milliseconds if needed
|
||||||
int timestampInMs =
|
int timestampInMs = this! > 1000000000000 ? this! : this! * 1000;
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
timestampInMs,
|
timestampInMs,
|
||||||
@@ -16,11 +18,12 @@ class DateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts Unix timestamp to a readable date string
|
/// Converts Unix timestamp to a readable date string
|
||||||
static String unixToReadableDate(int? unixTimestamp) {
|
String toReadableDate() {
|
||||||
if (unixTimestamp == null) return '';
|
if (this == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
int timestampInMs =
|
int timestampInMs = this! > 1000000000000 ? this! : this! * 1000;
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
timestampInMs,
|
timestampInMs,
|
||||||
@@ -40,11 +43,12 @@ class DateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts Unix timestamp to a short date format
|
/// Converts Unix timestamp to a short date format
|
||||||
static String unixToShortDate(int? unixTimestamp) {
|
String toShortDate() {
|
||||||
if (unixTimestamp == null) return '';
|
if (this == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
int timestampInMs =
|
int timestampInMs = this! > 1000000000000 ? this! : this! * 1000;
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
timestampInMs,
|
timestampInMs,
|
||||||
@@ -53,11 +57,12 @@ class DateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts Unix timestamp to a full date and time format
|
/// Converts Unix timestamp to a full date and time format
|
||||||
static String unixToDateTime(int? unixTimestamp) {
|
String toDateTime() {
|
||||||
if (unixTimestamp == null) return '';
|
if (this == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
int timestampInMs =
|
int timestampInMs = this! > 1000000000000 ? this! : this! * 1000;
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
timestampInMs,
|
timestampInMs,
|
||||||
@@ -66,11 +71,12 @@ class DateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a Unix timestamp is in the past
|
/// Checks if a Unix timestamp is in the past
|
||||||
static bool isPast(int? unixTimestamp) {
|
bool get isPast {
|
||||||
if (unixTimestamp == null) return false;
|
if (this == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int timestampInMs =
|
int timestampInMs = this! > 1000000000000 ? this! : this! * 1000;
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
timestampInMs,
|
timestampInMs,
|
||||||
@@ -79,11 +85,12 @@ class DateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of days remaining until a Unix timestamp
|
/// Gets the number of days remaining until a Unix timestamp
|
||||||
static int daysRemaining(int? unixTimestamp) {
|
int get daysRemaining {
|
||||||
if (unixTimestamp == null) return 0;
|
if (this == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int timestampInMs =
|
int timestampInMs = this! > 1000000000000 ? this! : this! * 1000;
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
timestampInMs,
|
timestampInMs,
|
||||||
@@ -94,3 +101,69 @@ class DateUtils {
|
|||||||
return difference.inDays;
|
return difference.inDays;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extension on DateTime to provide additional formatting utilities
|
||||||
|
extension DateTimeExtension on DateTime {
|
||||||
|
/// Formats the DateTime to a readable string
|
||||||
|
String toReadableString() {
|
||||||
|
final DateTime now = DateTime.now();
|
||||||
|
final Duration difference = now.difference(this);
|
||||||
|
|
||||||
|
if (difference.inDays == 0) {
|
||||||
|
return 'Today';
|
||||||
|
} else if (difference.inDays == 1) {
|
||||||
|
return 'Yesterday';
|
||||||
|
} else if (difference.inDays < 7) {
|
||||||
|
return '${difference.inDays} days ago';
|
||||||
|
} else {
|
||||||
|
return DateFormat('MMM dd, yyyy').format(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the DateTime to a short date string
|
||||||
|
String toShortDate() {
|
||||||
|
return DateFormat('MMM dd').format(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the DateTime to a full date and time string
|
||||||
|
String toDateTimeString() {
|
||||||
|
return DateFormat('MMM dd, yyyy HH:mm').format(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the DateTime is in the past
|
||||||
|
bool get isPast {
|
||||||
|
return isBefore(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the number of days remaining until this DateTime
|
||||||
|
int get daysRemaining {
|
||||||
|
final DateTime now = DateTime.now();
|
||||||
|
final Duration difference = this.difference(now);
|
||||||
|
return difference.inDays;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility class for date operations
|
||||||
|
class DateUtils {
|
||||||
|
/// Converts Unix timestamp to a formatted date string
|
||||||
|
|
||||||
|
static String unixToDate(int? timestamp) {
|
||||||
|
if (timestamp == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert seconds to milliseconds if needed
|
||||||
|
int timestampInMs =
|
||||||
|
timestamp > 1000000000000 ? timestamp : timestamp * 1000;
|
||||||
|
|
||||||
|
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
timestampInMs,
|
||||||
|
);
|
||||||
|
return DateFormat('MMM dd, yyyy').format(dateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Global function for backward compatibility
|
||||||
|
String unixToDate(int? timestamp) {
|
||||||
|
return DateUtils.unixToDate(timestamp);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:tm_app/data/services/model/login_response/login_response_model.dart';
|
import 'package:tm_app/data/services/model/login_response/login_response_model.dart';
|
||||||
import 'package:tm_app/data/services/model/logout_response/logout_response.dart';
|
|
||||||
|
|
||||||
import '../../core/utils/result.dart';
|
import '../../core/utils/result.dart';
|
||||||
import '../services/auth_service.dart';
|
import '../services/auth_service.dart';
|
||||||
|
import '../services/model/logout_response/logout_response.dart';
|
||||||
|
|
||||||
class AuthRepository {
|
class AuthRepository {
|
||||||
final AuthService _authService;
|
final AuthService _authService;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
import 'package:tm_app/data/services/home_service.dart';
|
import 'package:tm_app/data/services/home_service.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart';
|
|
||||||
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
||||||
@@ -13,12 +11,6 @@ class HomeRepository {
|
|||||||
: _homeService = homeService;
|
: _homeService = homeService;
|
||||||
final HomeService _homeService;
|
final HomeService _homeService;
|
||||||
|
|
||||||
Future<Result<HomeResponseModel>> getHome({
|
|
||||||
HomeRequestModel? homeRequestModel,
|
|
||||||
}) async {
|
|
||||||
return _homeService.getHome(homeRequestModel: homeRequestModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Result<RecommendedTendersResponse>> getHomeRecommendedTenders({
|
Future<Result<RecommendedTendersResponse>> getHomeRecommendedTenders({
|
||||||
required int limit,
|
required int limit,
|
||||||
required int offset,
|
required int offset,
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ class TendersRepository {
|
|||||||
return _tendersService.getTenderFeedback(tenderId: tenderId);
|
return _tendersService.getTenderFeedback(tenderId: tenderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<FeedbackResponse>> feedback({
|
Future<Result<FeedbackResponse>> toggleFeedback({
|
||||||
required String tenderId,
|
required String tenderId,
|
||||||
required String feedbackType,
|
required String feedbackType,
|
||||||
}) async {
|
}) async {
|
||||||
return _tendersService.feedback(
|
return _tendersService.toggleFeedback(
|
||||||
tenderId: tenderId,
|
tenderId: tenderId,
|
||||||
feedbackType: feedbackType,
|
feedbackType: feedbackType,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class AuthApi {
|
||||||
|
static const String login = '/api/v1/profile/login';
|
||||||
|
static const String logout = '/api/v1/profile/logout';
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class HomeApi {
|
||||||
|
static const String recommendedTenders = '/api/v1/tenders/recommend';
|
||||||
|
static String getRecommendedTenders({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
}) {
|
||||||
|
return '$recommendedTenders?limit=$limit&offset=$offset';
|
||||||
|
}
|
||||||
|
|
||||||
|
static const String tenderApprovals = '/api/v1/tender-approvals';
|
||||||
|
static const String tenderApprovalStats = '/api/v1/tender-approvals/stats';
|
||||||
|
static const String statsCompany = '/api/v1/feedback/stats/company';
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class ProfileApi {
|
||||||
|
static const String profile = '/api/v1/profile';
|
||||||
|
static const String companyProfile = '/api/v1/companies';
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class TenderDetailApi {
|
||||||
|
static const String tenderDetails = '/api/v1/tenders/details';
|
||||||
|
static String getTenderDetails({required String tenderId}) {
|
||||||
|
return '$tenderDetails/$tenderId';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
class TendersApi {
|
||||||
|
static const String tenders = '/api/v1/tenders';
|
||||||
|
static String getTenders({required int limit, required int offset}) {
|
||||||
|
return '$tenders?limit=$limit&offset=$offset';
|
||||||
|
}
|
||||||
|
|
||||||
|
static const String feedbackTender = '/api/v1/feedback/tender';
|
||||||
|
static String getFeedbackForTender({required String tenderId}) {
|
||||||
|
return '$feedbackTender/$tenderId';
|
||||||
|
}
|
||||||
|
|
||||||
|
static const String feedback = '/api/v1/feedback';
|
||||||
|
|
||||||
|
static const String tenderApprovals = '/api/v1/tender-approvals';
|
||||||
|
|
||||||
|
static const String tenderApprovalsTender = '/api/v1/tender-approvals/tender';
|
||||||
|
static String getTenderApprovalById({required String tenderId}) {
|
||||||
|
return '$tenderApprovalsTender/$tenderId';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class YourTendersApi {
|
||||||
|
static const String tenderApprovalsStatus =
|
||||||
|
'/api/v1/tender-approvals?status=submitted';
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:tm_app/core/utils/logger.dart';
|
||||||
|
import 'package:tm_app/data/services/api/auth_api.dart';
|
||||||
import 'package:tm_app/data/services/model/login_response/login_response_model.dart';
|
import 'package:tm_app/data/services/model/login_response/login_response_model.dart';
|
||||||
import 'package:tm_app/data/services/model/logout_response/logout_response.dart';
|
import 'package:tm_app/data/services/model/logout_response/logout_response.dart';
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ class AuthService {
|
|||||||
var data = jsonEncode({"password": password, "username": username});
|
var data = jsonEncode({"password": password, "username": username});
|
||||||
|
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/profile/login',
|
AuthApi.login,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
(json) => LoginResponseModel.fromJson(json),
|
(json) => LoginResponseModel.fromJson(json),
|
||||||
data: data,
|
data: data,
|
||||||
@@ -41,7 +43,7 @@ class AuthService {
|
|||||||
|
|
||||||
Future<Result<LogoutResponse>> logout() async {
|
Future<Result<LogoutResponse>> logout() async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/profile/logout',
|
AuthApi.logout,
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
(json) => LogoutResponse.fromJson(json),
|
(json) => LogoutResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
@@ -52,5 +54,6 @@ class AuthService {
|
|||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.remove('bearer');
|
await prefs.remove('bearer');
|
||||||
await prefs.remove('refresh_token');
|
await prefs.remove('refresh_token');
|
||||||
|
appLogger.info('tokens cleared!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:tm_app/core/utils/logger.dart';
|
|
||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
import 'package:tm_app/data/services/mock_data/home_mock_data.dart';
|
import 'package:tm_app/data/services/api/home_api.dart';
|
||||||
import 'package:tm_app/data/services/model/feedback_stats_response/feedback_stat_response.dart';
|
import 'package:tm_app/data/services/model/feedback_stats_response/feedback_stat_response.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart';
|
|
||||||
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
||||||
@@ -18,36 +12,12 @@ class HomeService {
|
|||||||
: _networkManager = networkManager;
|
: _networkManager = networkManager;
|
||||||
final NetworkManager _networkManager;
|
final NetworkManager _networkManager;
|
||||||
|
|
||||||
Future<Result<HomeResponseModel>> getHome({
|
|
||||||
HomeRequestModel? homeRequestModel,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
// final result = await _networkManager.makeRequest(
|
|
||||||
// '/api/v1/home',
|
|
||||||
// (json) => HomeResponseModel.fromJson(json),
|
|
||||||
// method: 'GET',
|
|
||||||
// );
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
appLogger.info('get home success');
|
|
||||||
// TODO: will change when api is ready
|
|
||||||
return Result.ok(
|
|
||||||
HomeResponseModel.fromJson(jsonDecode(homeMockData)['data']),
|
|
||||||
);
|
|
||||||
} on DioException catch (e) {
|
|
||||||
appLogger.error('get home failed: $e');
|
|
||||||
return Result.error(e);
|
|
||||||
} on Exception catch (e, stackTrace) {
|
|
||||||
appLogger.error('get home failed: $e', stackTrace: stackTrace);
|
|
||||||
return Result.error(Exception(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Result<RecommendedTendersResponse>> getRecommendedTenders({
|
Future<Result<RecommendedTendersResponse>> getRecommendedTenders({
|
||||||
required int limit,
|
required int limit,
|
||||||
required int offset,
|
required int offset,
|
||||||
}) async {
|
}) async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tenders/recommend?limit=$limit&offset=$offset',
|
HomeApi.getRecommendedTenders(limit: limit, offset: offset),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => RecommendedTendersResponse.fromJson(json),
|
(json) => RecommendedTendersResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
@@ -56,7 +26,7 @@ class HomeService {
|
|||||||
|
|
||||||
Future<Result<TenderApprovalsResponse>> getYourTenders() async {
|
Future<Result<TenderApprovalsResponse>> getYourTenders() async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tender-approvals',
|
HomeApi.tenderApprovals,
|
||||||
(json) => TenderApprovalsResponse.fromJson(json),
|
(json) => TenderApprovalsResponse.fromJson(json),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
);
|
);
|
||||||
@@ -67,7 +37,7 @@ class HomeService {
|
|||||||
Future<Result<TenderApprovalsStateResponse>>
|
Future<Result<TenderApprovalsStateResponse>>
|
||||||
getTendersApprovalsState() async {
|
getTendersApprovalsState() async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tender-approvals/stats',
|
HomeApi.tenderApprovalStats,
|
||||||
(json) => TenderApprovalsStateResponse.fromJson(json),
|
(json) => TenderApprovalsStateResponse.fromJson(json),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
);
|
);
|
||||||
@@ -77,7 +47,7 @@ class HomeService {
|
|||||||
|
|
||||||
Future<Result<FeedbackStatResponse>> getFeedbackStats() async {
|
Future<Result<FeedbackStatResponse>> getFeedbackStats() async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/feedback/stats/company',
|
HomeApi.statsCompany,
|
||||||
(json) => FeedbackStatResponse.fromJson(json),
|
(json) => FeedbackStatResponse.fromJson(json),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:tm_app/data/services/api/profile_api.dart';
|
||||||
import 'package:tm_app/data/services/model/company_profile_response/company_profile_response.dart';
|
import 'package:tm_app/data/services/model/company_profile_response/company_profile_response.dart';
|
||||||
import 'package:tm_app/data/services/model/profile_response/profile_response.dart';
|
import 'package:tm_app/data/services/model/profile_response/profile_response.dart';
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ class ProfileService {
|
|||||||
|
|
||||||
Future<Result<ProfileResponse>> getProfile() async {
|
Future<Result<ProfileResponse>> getProfile() async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/profile',
|
ProfileApi.profile,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => ProfileResponse.fromJson(json),
|
(json) => ProfileResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
@@ -21,7 +22,7 @@ class ProfileService {
|
|||||||
|
|
||||||
Future<Result<CompanyProfileResponse>> getCompanyProfile() async {
|
Future<Result<CompanyProfileResponse>> getCompanyProfile() async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/companies',
|
ProfileApi.companyProfile,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => CompanyProfileResponse.fromJson(json),
|
(json) => CompanyProfileResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
|
import 'package:tm_app/data/services/api/tender_detail_api.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
|
|
||||||
import '../../core/network/network_manager.dart';
|
import '../../core/network/network_manager.dart';
|
||||||
@@ -13,7 +14,7 @@ class TenderDetailService {
|
|||||||
required String tenderId,
|
required String tenderId,
|
||||||
}) async {
|
}) async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tenders/details/$tenderId',
|
TenderDetailApi.getTenderDetails(tenderId: tenderId),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => TenderDetailResponseModel.fromJson(json),
|
(json) => TenderDetailResponseModel.fromJson(json),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
|
import 'package:tm_app/data/services/api/tenders_api.dart';
|
||||||
import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart';
|
import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart';
|
||||||
@@ -18,7 +19,7 @@ class TendersService {
|
|||||||
required int offset,
|
required int offset,
|
||||||
}) async {
|
}) async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tenders?limit=$limit&offset=$offset',
|
TendersApi.getTenders(limit: limit, offset: offset),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => TendersResponse.fromJson(json),
|
(json) => TendersResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
@@ -29,14 +30,14 @@ class TendersService {
|
|||||||
required String tenderId,
|
required String tenderId,
|
||||||
}) async {
|
}) async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/feedback/tender/$tenderId',
|
TendersApi.getFeedbackForTender(tenderId: tenderId),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => FeedbackResponse.fromJson(json),
|
(json) => FeedbackResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<FeedbackResponse>> feedback({
|
Future<Result<FeedbackResponse>> toggleFeedback({
|
||||||
required String tenderId,
|
required String tenderId,
|
||||||
required String feedbackType,
|
required String feedbackType,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -45,7 +46,7 @@ class TendersService {
|
|||||||
'tender_id': tenderId,
|
'tender_id': tenderId,
|
||||||
});
|
});
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/feedback',
|
TendersApi.feedback,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
(json) => FeedbackResponse.fromJson(json),
|
(json) => FeedbackResponse.fromJson(json),
|
||||||
data: data,
|
data: data,
|
||||||
@@ -64,7 +65,7 @@ class TendersService {
|
|||||||
'status': status,
|
'status': status,
|
||||||
});
|
});
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tender-approvals',
|
TendersApi.tenderApprovals,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
(json) => TenderApprovalsToggleResponse.fromJson(json),
|
(json) => TenderApprovalsToggleResponse.fromJson(json),
|
||||||
data: data,
|
data: data,
|
||||||
@@ -76,7 +77,7 @@ class TendersService {
|
|||||||
required String tenderId,
|
required String tenderId,
|
||||||
}) async {
|
}) async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tender-approvals/tender/$tenderId',
|
TendersApi.getTenderApprovalById(tenderId: tenderId),
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => TenderApprovalsByIdResponse.fromJson(json),
|
(json) => TenderApprovalsByIdResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:tm_app/core/utils/logger.dart';
|
|
||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
|
import 'package:tm_app/data/services/api/your_tenders_api.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
||||||
|
|
||||||
import '../../../core/network/network_manager.dart';
|
import '../../../core/network/network_manager.dart';
|
||||||
@@ -12,23 +11,12 @@ class YourTendersService {
|
|||||||
final NetworkManager _networkManager;
|
final NetworkManager _networkManager;
|
||||||
|
|
||||||
Future<Result<TenderApprovalsResponse>> getApprovedTenders() async {
|
Future<Result<TenderApprovalsResponse>> getApprovedTenders() async {
|
||||||
try {
|
final result = await _networkManager.makeRequest(
|
||||||
final result = await _networkManager.makeRequest(
|
YourTendersApi.tenderApprovalsStatus,
|
||||||
'/api/v1/tender-approvals?status=submitted',
|
(json) => TenderApprovalsResponse.fromJson(json),
|
||||||
(json) => TenderApprovalsResponse.fromJson(json),
|
method: 'GET',
|
||||||
method: 'GET',
|
);
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} on DioException catch (e) {
|
|
||||||
appLogger.error('get submitted tenders failed: $e');
|
|
||||||
return Result.error(e);
|
|
||||||
} on Exception catch (e, stackTrace) {
|
|
||||||
appLogger.error(
|
|
||||||
'get submitted tenders failed: $e',
|
|
||||||
stackTrace: stackTrace,
|
|
||||||
);
|
|
||||||
return Result.error(Exception(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
import 'package:tm_app/data/services/model/feedback_stats/feedback_stats.dart';
|
import 'package:tm_app/data/services/model/feedback_stats/feedback_stats.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart';
|
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
||||||
@@ -51,30 +50,10 @@ class HomeViewModel with ChangeNotifier {
|
|||||||
await getFeedbackStats();
|
await getFeedbackStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getHome({HomeRequestModel? homeRequestModel}) async {
|
|
||||||
_isLoading = true;
|
|
||||||
_errorMessage = null;
|
|
||||||
notifyListeners();
|
|
||||||
|
|
||||||
final result = await _homeRepository.getHome(
|
|
||||||
homeRequestModel: homeRequestModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
switch (result) {
|
|
||||||
case Ok<HomeResponseModel>():
|
|
||||||
_homeResponse = result.value;
|
|
||||||
break;
|
|
||||||
case Error<HomeResponseModel>():
|
|
||||||
_errorMessage = result.error.toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_isLoading = false;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> getHomeRecommandTenders({bool reset = false}) async {
|
Future<void> getHomeRecommandTenders({bool reset = false}) async {
|
||||||
if (_isLoadingMore || (!_hasMore && !reset)) return;
|
if (_isLoadingMore || (!_hasMore && !reset)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (reset) {
|
if (reset) {
|
||||||
_currentPage = 0;
|
_currentPage = 0;
|
||||||
@@ -186,4 +165,27 @@ class HomeViewModel with ChangeNotifier {
|
|||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculation methods for progress bars
|
||||||
|
double get partnershipCount {
|
||||||
|
return tenderApprovalsStateResponse?.data?.partnershipCount?.toDouble() ??
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get selfApplyCount {
|
||||||
|
return tenderApprovalsStateResponse?.data?.selfApplyCount?.toDouble() ??
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get totalCount {
|
||||||
|
return partnershipCount + selfApplyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get partnershipPercent {
|
||||||
|
return totalCount > 0 ? (partnershipCount / totalCount) * 100 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get selfApplyPercent {
|
||||||
|
return totalCount > 0 ? (selfApplyCount / totalCount) * 100 : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ class TenderDetailViewModel with ChangeNotifier {
|
|||||||
final result = await _tendersRepository.getTenderApprovals(
|
final result = await _tendersRepository.getTenderApprovals(
|
||||||
tenderId: tenderId,
|
tenderId: tenderId,
|
||||||
);
|
);
|
||||||
|
approvalStatus = false;
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case Ok<TenderApprovalsByIdResponse>():
|
case Ok<TenderApprovalsByIdResponse>():
|
||||||
_tenderApprovalData = result.value.data;
|
_tenderApprovalData = result.value.data;
|
||||||
|
|||||||
@@ -122,7 +122,9 @@ class TendersViewModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadMoreTenders() async {
|
Future<void> loadMoreTenders() async {
|
||||||
if (_isLoadingMore || !_hasMoreData) return;
|
if (_isLoadingMore || !_hasMoreData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_isLoadingMore = true;
|
_isLoadingMore = true;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
@@ -246,14 +248,14 @@ class TendersViewModel with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> feedback({
|
Future<void> toogleFeedback({
|
||||||
required String tenderId,
|
required String tenderId,
|
||||||
required String feedbackType,
|
required String feedbackType,
|
||||||
}) async {
|
}) async {
|
||||||
_feedbackErrorMessage = null;
|
_feedbackErrorMessage = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _tendersRepository.feedback(
|
final result = await _tendersRepository.toggleFeedback(
|
||||||
tenderId: tenderId,
|
tenderId: tenderId,
|
||||||
feedbackType: feedbackType,
|
feedbackType: feedbackType,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
|||||||
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
|
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
import '../../../view_models/home_view_model.dart';
|
import '../../../view_models/home_view_model.dart';
|
||||||
import '../../../view_models/tenders_view_model.dart';
|
import '../../../view_models/tenders_view_model.dart';
|
||||||
import '../../shared/desktop_navigation_widget.dart';
|
import '../../shared/desktop_navigation_widget.dart';
|
||||||
@@ -34,39 +35,39 @@ class _TenderDetailDesktopPageState extends State<TenderDetailDesktopPage> {
|
|||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'submitted' &&
|
viewModel.status == 'submitted' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
SnackBar(content: Text(AppStrings.tenderSubmittedSuccessfully)),
|
||||||
).showSnackBar(SnackBar(content: Text('tender submitted successfully!')));
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'unsubmitted' &&
|
viewModel.status == 'unsubmitted' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('tender submitted removed sucessfully!')),
|
SnackBar(content: Text(AppStrings.tenderUnsubmittedSuccessfully)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'rejected' &&
|
viewModel.status == 'rejected' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
SnackBar(content: Text(AppStrings.tenderRejectedSuccessfully)),
|
||||||
).showSnackBar(SnackBar(content: Text('tender rejected sucessfully!')));
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'unrejected' &&
|
viewModel.status == 'unrejected' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('tender reject removed sucessfully!')),
|
SnackBar(content: Text(AppStrings.tenderUnrejectedSuccessfully)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (viewModel.approvalStatus != false && viewModel.errorMessage != null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
backgroundColor: AppColors.errorColor,
|
||||||
|
content: Text(viewModel.errorMessage!),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// if (viewModel.errorMessage != null) {
|
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
// SnackBar(
|
|
||||||
// backgroundColor: AppColors.errorColor,
|
|
||||||
// content: Text(viewModel.errorMessage!),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -99,7 +100,7 @@ class _TenderDetailDesktopPageState extends State<TenderDetailDesktopPage> {
|
|||||||
|
|
||||||
final detail = tenderViewModel.tenderDetail;
|
final detail = tenderViewModel.tenderDetail;
|
||||||
if (detail == null) {
|
if (detail == null) {
|
||||||
return const Center(child: Text('No tender details available'));
|
return const Center(child: Text(AppStrings.tenderNoData));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
|||||||
@@ -30,39 +30,39 @@ class _TenderDetailMobilePageState extends State<TenderDetailMobilePage> {
|
|||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'submitted' &&
|
viewModel.status == 'submitted' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
SnackBar(content: Text(AppStrings.tenderSubmittedSuccessfully)),
|
||||||
).showSnackBar(SnackBar(content: Text('tender submitted successfully!')));
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'unsubmitted' &&
|
viewModel.status == 'unsubmitted' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('tender submitted removed sucessfully!')),
|
SnackBar(content: Text(AppStrings.tenderUnsubmittedSuccessfully)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'rejected' &&
|
viewModel.status == 'rejected' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
SnackBar(content: Text(AppStrings.tenderRejectedSuccessfully)),
|
||||||
).showSnackBar(SnackBar(content: Text('tender rejected sucessfully!')));
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'unrejected' &&
|
viewModel.status == 'unrejected' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('tender reject removed sucessfully!')),
|
SnackBar(content: Text(AppStrings.tenderUnrejectedSuccessfully)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (viewModel.approvalStatus != false && viewModel.errorMessage != null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
backgroundColor: AppColors.errorColor,
|
||||||
|
content: Text(viewModel.errorMessage!),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// if (viewModel.errorMessage != null) {
|
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
// SnackBar(
|
|
||||||
// backgroundColor: AppColors.errorColor,
|
|
||||||
// content: Text(viewModel.errorMessage!),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -90,7 +90,7 @@ class _TenderDetailMobilePageState extends State<TenderDetailMobilePage> {
|
|||||||
|
|
||||||
final detail = tenderViewModel.tenderDetail;
|
final detail = tenderViewModel.tenderDetail;
|
||||||
if (detail == null) {
|
if (detail == null) {
|
||||||
return const Center(child: Text('No tender details available'));
|
return const Center(child: Text(AppStrings.tenderNoData));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
|
|||||||
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
||||||
import 'package:tm_app/views/shared/tablet_navigation_widget.dart';
|
import 'package:tm_app/views/shared/tablet_navigation_widget.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
|
||||||
class TenderDetailTabletPage extends StatefulWidget {
|
class TenderDetailTabletPage extends StatefulWidget {
|
||||||
final String tenderId;
|
final String tenderId;
|
||||||
const TenderDetailTabletPage({required this.tenderId, super.key});
|
const TenderDetailTabletPage({required this.tenderId, super.key});
|
||||||
@@ -33,39 +35,39 @@ class _TenderDetailTabletPageState extends State<TenderDetailTabletPage> {
|
|||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'submitted' &&
|
viewModel.status == 'submitted' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
SnackBar(content: Text(AppStrings.tenderSubmittedSuccessfully)),
|
||||||
).showSnackBar(SnackBar(content: Text('tender submitted successfully!')));
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'unsubmitted' &&
|
viewModel.status == 'unsubmitted' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('tender submitted removed sucessfully!')),
|
SnackBar(content: Text(AppStrings.tenderUnsubmittedSuccessfully)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'rejected' &&
|
viewModel.status == 'rejected' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
SnackBar(content: Text(AppStrings.tenderRejectedSuccessfully)),
|
||||||
).showSnackBar(SnackBar(content: Text('tender rejected sucessfully!')));
|
);
|
||||||
}
|
}
|
||||||
if (viewModel.status.isNotEmpty &&
|
if (viewModel.status.isNotEmpty &&
|
||||||
viewModel.status == 'unrejected' &&
|
viewModel.status == 'unrejected' &&
|
||||||
viewModel.approvalStatus == true) {
|
viewModel.approvalStatus == true) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('tender reject removed sucessfully!')),
|
SnackBar(content: Text(AppStrings.tenderUnrejectedSuccessfully)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (viewModel.approvalStatus != false && viewModel.errorMessage != null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
backgroundColor: AppColors.errorColor,
|
||||||
|
content: Text(viewModel.errorMessage!),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// if (viewModel.errorMessage != null) {
|
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
// SnackBar(
|
|
||||||
// backgroundColor: AppColors.errorColor,
|
|
||||||
// content: Text(viewModel.errorMessage!),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -138,7 +140,7 @@ class _TenderDetailTabletPageState extends State<TenderDetailTabletPage> {
|
|||||||
|
|
||||||
final detail = tenderViewModel.tenderDetail;
|
final detail = tenderViewModel.tenderDetail;
|
||||||
if (detail == null) {
|
if (detail == null) {
|
||||||
return const Center(child: Text('No tender details available'));
|
return const Center(child: Text(AppStrings.tenderNoData));
|
||||||
}
|
}
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Center(
|
child: Center(
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
import 'package:tm_app/core/utils/date_utils.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
import '../../../data/services/model/tender_data/tender_data.dart';
|
||||||
|
|
||||||
class DeadlineItem extends StatelessWidget {
|
class DeadlineItem extends StatelessWidget {
|
||||||
final String title;
|
final TenderData detail;
|
||||||
final String approvalText;
|
|
||||||
final String approvalDate;
|
|
||||||
final String submissionText;
|
|
||||||
final String submissionDate;
|
|
||||||
final bool isScreenBig;
|
final bool isScreenBig;
|
||||||
|
|
||||||
const DeadlineItem({
|
const DeadlineItem({
|
||||||
required this.title,
|
required this.detail,
|
||||||
required this.approvalText,
|
|
||||||
required this.approvalDate,
|
|
||||||
required this.submissionText,
|
|
||||||
required this.submissionDate,
|
|
||||||
required this.isScreenBig,
|
required this.isScreenBig,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
@@ -31,7 +28,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 45.0.h(),
|
height: 45.0.h(),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
detail.title ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@@ -47,7 +44,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
approvalText,
|
AppStrings.tenderApprovalText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -56,7 +53,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 4.0.h()),
|
SizedBox(height: 4.0.h()),
|
||||||
Text(
|
Text(
|
||||||
approvalDate,
|
unixToDate(detail.submissionDeadline),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -76,7 +73,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
submissionText,
|
AppStrings.tenderSubmissionText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -85,7 +82,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 4.0.h()),
|
SizedBox(height: 4.0.h()),
|
||||||
Text(
|
Text(
|
||||||
submissionDate,
|
unixToDate(detail.applicationDeadline),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -99,7 +96,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
Divider(color: AppColors.grey20,),
|
Divider(color: AppColors.grey20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -111,7 +108,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 45.0.h(),
|
height: 45.0.h(),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
detail.title ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@@ -123,7 +120,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
approvalText,
|
AppStrings.tenderApprovalText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -131,7 +128,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
approvalDate,
|
unixToDate(detail.submissionDeadline),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -145,7 +142,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
submissionText,
|
AppStrings.tenderSubmissionText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -153,7 +150,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
submissionDate,
|
unixToDate(detail.applicationDeadline),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@@ -163,7 +160,7 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
Divider(color: AppColors.grey20,),
|
Divider(color: AppColors.grey20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class TenderDetailCard extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
AppStrings.tenderMatchPercentageExample,
|
'75%',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.0.sp(),
|
fontSize: 12.0.sp(),
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
import 'package:tm_app/core/utils/date_utils.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/status_tag.dart';
|
import 'package:tm_app/views/detail/widgets/status_tag.dart';
|
||||||
@@ -73,14 +73,3 @@ class TenderDetailHeader extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String unixToDate(int? unixTimestamp, {String format = 'yyyy-MM-dd'}) {
|
|
||||||
if (unixTimestamp == null) return '';
|
|
||||||
|
|
||||||
// Convert seconds to milliseconds if needed
|
|
||||||
int timestampInMs =
|
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestampInMs);
|
|
||||||
return DateFormat(format).format(dateTime);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
import 'package:tm_app/core/constants/strings.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/deadline_item.dart';
|
import 'package:tm_app/views/detail/widgets/deadline_item.dart';
|
||||||
@@ -21,14 +20,7 @@ class TenderDetailInfoSection extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
InfoItem(title: AppStrings.tenderIdLabel, value: detail.tenderId ?? ''),
|
InfoItem(title: AppStrings.tenderIdLabel, value: detail.tenderId ?? ''),
|
||||||
DeadlineItem(
|
DeadlineItem(detail: detail, isScreenBig: isScreenBig),
|
||||||
title: AppStrings.tenderDeadlineLabel,
|
|
||||||
approvalText: AppStrings.tenderApprovalText,
|
|
||||||
approvalDate: unixToDate(detail.submissionDeadline),
|
|
||||||
submissionText: AppStrings.tenderSubmissionText,
|
|
||||||
submissionDate: unixToDate(detail.applicationDeadline),
|
|
||||||
isScreenBig: isScreenBig,
|
|
||||||
),
|
|
||||||
InfoItem(
|
InfoItem(
|
||||||
title: AppStrings.tenderClientLabel,
|
title: AppStrings.tenderClientLabel,
|
||||||
value: detail.buyerOrganization!.name ?? '',
|
value: detail.buyerOrganization!.name ?? '',
|
||||||
@@ -49,16 +41,3 @@ class TenderDetailInfoSection extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String unixToDate(int? unixTimestamp, {String format = 'yyyy-MM-dd'}) {
|
|
||||||
if (unixTimestamp == null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert seconds to milliseconds if needed
|
|
||||||
int timestampInMs =
|
|
||||||
unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000;
|
|
||||||
|
|
||||||
final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestampInMs);
|
|
||||||
return DateFormat(format).format(dateTime);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import 'package:tm_app/core/constants/strings.dart';
|
|||||||
import 'package:tm_app/core/routes/app_routes.dart';
|
import 'package:tm_app/core/routes/app_routes.dart';
|
||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart';
|
|
||||||
import 'package:tm_app/view_models/home_view_model.dart';
|
import 'package:tm_app/view_models/home_view_model.dart';
|
||||||
import 'package:tm_app/views/shared/desktop_navigation_widget.dart';
|
import 'package:tm_app/views/shared/desktop_navigation_widget.dart';
|
||||||
|
|
||||||
@@ -30,111 +29,99 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
return Center(child: Text(homeViewModel.errorMessage!));
|
return Center(child: Text(homeViewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
if (homeViewModel.tenderApprovalsStateResponse != null &&
|
||||||
children: [
|
homeViewModel.data != null &&
|
||||||
DesktopNavigationWidget(
|
homeViewModel.feedbackStats != null) {
|
||||||
currentIndex: 0, // Home index
|
return Column(
|
||||||
onTabChanged: (index) {
|
children: [
|
||||||
// Navigate to different screens based on index
|
DesktopNavigationWidget(
|
||||||
switch (index) {
|
currentIndex: 0, // Home index
|
||||||
case 0:
|
onTabChanged: (index) {
|
||||||
// Already on home
|
// Navigate to different screens based on index
|
||||||
break;
|
switch (index) {
|
||||||
case 1:
|
case 0:
|
||||||
// Navigate to tenders
|
// Already on home
|
||||||
Router.neglect(context, () => context.go('/tenders'));
|
break;
|
||||||
break;
|
case 1:
|
||||||
case 2:
|
// Navigate to tenders
|
||||||
// Navigate to profile
|
Router.neglect(context, () => context.go('/tenders'));
|
||||||
Router.neglect(context, () => context.go('/profile'));
|
break;
|
||||||
break;
|
case 2:
|
||||||
}
|
// Navigate to profile
|
||||||
},
|
Router.neglect(context, () => context.go('/profile'));
|
||||||
),
|
break;
|
||||||
Expanded(
|
}
|
||||||
child: Center(
|
},
|
||||||
child: SizedBox(
|
),
|
||||||
width: 780,
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: Center(
|
||||||
child: Column(
|
child: SizedBox(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
width: 780,
|
||||||
children: [
|
child: SingleChildScrollView(
|
||||||
SizedBox(height: 55),
|
child: Column(
|
||||||
// SizedBox(width: 780, child: NotificationCard()),
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
SizedBox(height: 40.0),
|
children: [
|
||||||
_progressBarsRow(
|
SizedBox(height: 55),
|
||||||
homeViewModel.tenderApprovalsStateResponse!,
|
// SizedBox(width: 780, child: NotificationCard()),
|
||||||
),
|
SizedBox(height: 40.0),
|
||||||
SizedBox(height: 32.0.h()),
|
_progressBarsRow(homeViewModel),
|
||||||
Padding(
|
SizedBox(height: 32.0.h()),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 15.0.w()),
|
Padding(
|
||||||
child: _firstTenderCardsRow(
|
padding: EdgeInsets.symmetric(
|
||||||
context,
|
horizontal: 15.0.w(),
|
||||||
homeViewModel.tenderApprovalsStateResponse!,
|
),
|
||||||
homeViewModel,
|
child: _firstTenderCardsRow(
|
||||||
|
context,
|
||||||
|
homeViewModel,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 32.0.h()),
|
||||||
SizedBox(height: 32.0.h()),
|
_yourTenderText(homeViewModel),
|
||||||
_yourTenderText(homeViewModel),
|
SizedBox(height: 8.0.h()),
|
||||||
SizedBox(height: 8.0.h()),
|
_bottomListView(homeViewModel),
|
||||||
_bottomListView(homeViewModel),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
);
|
||||||
|
}
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _progressBarsRow(
|
Widget _progressBarsRow(HomeViewModel homeViewModel) {
|
||||||
TenderApprovalsStateResponse tenderApprovalsStateResponse,
|
|
||||||
) {
|
|
||||||
final partnership =
|
|
||||||
tenderApprovalsStateResponse.data!.partnershipCount ?? 0;
|
|
||||||
final selfApply = tenderApprovalsStateResponse.data!.selfApplyCount ?? 0;
|
|
||||||
final total = (partnership + selfApply);
|
|
||||||
|
|
||||||
final partnershipPercent = total > 0 ? (partnership / total) * 100 : 0;
|
|
||||||
final selfApplyPercent = total > 0 ? (selfApply / total) * 100 : 0;
|
|
||||||
return Row(
|
return Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ProgressBarColumn(
|
ProgressBarColumn(
|
||||||
text: AppStrings.partnership,
|
text: AppStrings.partnership,
|
||||||
value: double.parse('$partnershipPercent'),
|
value: homeViewModel.partnershipPercent,
|
||||||
amount: double.parse('$partnershipPercent').toString(),
|
amount: homeViewModel.partnershipPercent.toString(),
|
||||||
circularProgressIndicatorWidth: 176,
|
circularProgressIndicatorWidth: 176,
|
||||||
circularProgressIndicatorHeight: 176,
|
circularProgressIndicatorHeight: 176,
|
||||||
),
|
),
|
||||||
SizedBox(width: 106),
|
SizedBox(width: 106),
|
||||||
ProgressBarColumn(
|
ProgressBarColumn(
|
||||||
text: AppStrings.selfApply,
|
text: AppStrings.selfApply,
|
||||||
value: double.parse(selfApplyPercent.toString()),
|
value: homeViewModel.selfApplyPercent,
|
||||||
amount: double.parse(selfApplyPercent.toString()).toString(),
|
amount: homeViewModel.selfApplyPercent.toString(),
|
||||||
circularProgressIndicatorWidth: 176,
|
circularProgressIndicatorWidth: 176,
|
||||||
circularProgressIndicatorHeight: 176,
|
circularProgressIndicatorHeight: 176,
|
||||||
),
|
),
|
||||||
//SizedBox(width: 106),
|
|
||||||
// ProgressBarColumn(
|
|
||||||
// text: AppStrings.contracting,
|
|
||||||
// value: double.parse(homeResponse.contracting ?? '0'),
|
|
||||||
// amount: homeResponse.contracting ?? '0',
|
|
||||||
// circularProgressIndicatorWidth: 176,
|
|
||||||
// circularProgressIndicatorHeight: 176,
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _firstTenderCardsRow(
|
Widget _firstTenderCardsRow(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
TenderApprovalsStateResponse tenderApprovalsStateResponse,
|
|
||||||
HomeViewModel homeViewModel,
|
HomeViewModel homeViewModel,
|
||||||
) {
|
) {
|
||||||
return Row(
|
return Row(
|
||||||
@@ -143,16 +130,16 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TenderCard(
|
child: TenderCard(
|
||||||
backgroundColor: AppColors.primary20,
|
backgroundColor: AppColors.primary20,
|
||||||
iconPath: 'assets/icons/arrows.svg',
|
iconPath: AssetsManager.arrows,
|
||||||
title: AppStrings.tenderSubmitted,
|
title: AppStrings.tenderSubmitted,
|
||||||
amount:
|
amount:
|
||||||
tenderApprovalsStateResponse.data!.submittedTenders.toString(),
|
homeViewModel
|
||||||
// tenderApprovalsStateResponse
|
.tenderApprovalsStateResponse!
|
||||||
// .data!
|
.data!
|
||||||
// .approvalsBySubmission!
|
.submittedTenders
|
||||||
// .selfApply
|
.toString(),
|
||||||
// .toString(),
|
|
||||||
textColor: Color(0xFF0164FF),
|
textColor: AppColors.mainBlue,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 148,
|
height: 148,
|
||||||
@@ -168,7 +155,7 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
iconPath: AssetsManager.approve,
|
iconPath: AssetsManager.approve,
|
||||||
title: AppStrings.approvedTenders,
|
title: AppStrings.approvedTenders,
|
||||||
amount: '0',
|
amount: '0',
|
||||||
textColor: Color(0xFF24848E),
|
textColor: AppColors.jellyBean,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 148,
|
height: 148,
|
||||||
@@ -180,10 +167,10 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
TenderCard(
|
TenderCard(
|
||||||
backgroundColor: AppColors.orange10,
|
backgroundColor: AppColors.orange10,
|
||||||
iconPath: 'assets/icons/shield.svg',
|
iconPath: AssetsManager.shield,
|
||||||
title: AppStrings.tenderValue,
|
title: AppStrings.tenderValue,
|
||||||
amount: '3',
|
amount: '3',
|
||||||
textColor: Color(0xFFE5821E),
|
textColor: AppColors.orange,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 148,
|
height: 148,
|
||||||
@@ -195,7 +182,7 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
iconPath: AssetsManager.thumbLike,
|
iconPath: AssetsManager.thumbLike,
|
||||||
title: AppStrings.likedTenders,
|
title: AppStrings.likedTenders,
|
||||||
amount: homeViewModel.feedbackStats?.totalLikes.toString() ?? '0',
|
amount: homeViewModel.feedbackStats?.totalLikes.toString() ?? '0',
|
||||||
textColor: Color(0xFF9E9E9E),
|
textColor: AppColors.grey80,
|
||||||
enableTap: false,
|
enableTap: false,
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 148,
|
height: 148,
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (homeViewModel.tenderApprovalsStateResponse != null &&
|
if (homeViewModel.tenderApprovalsStateResponse != null &&
|
||||||
homeViewModel.data != null) {
|
homeViewModel.data != null &&
|
||||||
|
homeViewModel.feedbackStats != null) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -39,7 +40,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
// SizedBox(height: 18.0.h()),
|
// SizedBox(height: 18.0.h()),
|
||||||
// NotificationCard(),
|
// NotificationCard(),
|
||||||
SizedBox(height: 32.0.h()),
|
SizedBox(height: 32.0.h()),
|
||||||
_progressBarsRow(homeViewModel.tenderApprovalsStateResponse!),
|
_progressBarsRow(homeViewModel),
|
||||||
SizedBox(height: 32.0.h()),
|
SizedBox(height: 32.0.h()),
|
||||||
_firstTenderCardsRow(
|
_firstTenderCardsRow(
|
||||||
context,
|
context,
|
||||||
@@ -62,17 +63,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _progressBarsRow(
|
Widget _progressBarsRow(HomeViewModel homeViewModel) {
|
||||||
TenderApprovalsStateResponse tenderApprovalsStateResponse,
|
|
||||||
) {
|
|
||||||
final partnership =
|
|
||||||
tenderApprovalsStateResponse.data!.partnershipCount ?? 0;
|
|
||||||
final selfApply = tenderApprovalsStateResponse.data!.selfApplyCount ?? 0;
|
|
||||||
final total = (partnership + selfApply);
|
|
||||||
|
|
||||||
final partnershipPercent = total > 0 ? (partnership / total) * 100 : 0;
|
|
||||||
final selfApplyPercent = total > 0 ? (selfApply / total) * 100 : 0;
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -81,22 +72,17 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
SizedBox(width: 20.0.w()),
|
SizedBox(width: 20.0.w()),
|
||||||
ProgressBarColumn(
|
ProgressBarColumn(
|
||||||
text: AppStrings.partnership,
|
text: AppStrings.partnership,
|
||||||
value: double.parse('$partnershipPercent'),
|
value: homeViewModel.partnershipPercent,
|
||||||
amount: double.parse('$partnershipPercent').toString(),
|
amount: homeViewModel.partnershipPercent.toString(),
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
ProgressBarColumn(
|
ProgressBarColumn(
|
||||||
text: AppStrings.selfApply,
|
text: AppStrings.selfApply,
|
||||||
value: double.parse(selfApplyPercent.toString()),
|
value: homeViewModel.selfApplyPercent,
|
||||||
amount: double.parse(selfApplyPercent.toString()).toString(),
|
amount: homeViewModel.selfApplyPercent.toString(),
|
||||||
),
|
),
|
||||||
SizedBox(width: 20.0.w()),
|
SizedBox(width: 20.0.w()),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
// ProgressBarColumn(
|
|
||||||
// text: AppStrings.contracting,
|
|
||||||
// value: double.parse(tenderApprovalsStateResponse.data.contracting ?? '0'),
|
|
||||||
// amount: tenderApprovalsStateResponse.data.contracting ?? '0',
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -117,12 +103,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
title: AppStrings.tenderSubmitted,
|
title: AppStrings.tenderSubmitted,
|
||||||
amount:
|
amount:
|
||||||
tenderApprovalsStateResponse.data!.submittedTenders.toString(),
|
tenderApprovalsStateResponse.data!.submittedTenders.toString(),
|
||||||
// tenderApprovalsStateResponse
|
textColor: AppColors.mainBlue,
|
||||||
// .data!
|
|
||||||
// .approvalsBySubmission!
|
|
||||||
// .selfApply
|
|
||||||
// .toString(),
|
|
||||||
textColor: Color(0xFF0164FF),
|
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
YourTendersRouteData().push(context);
|
YourTendersRouteData().push(context);
|
||||||
@@ -134,7 +115,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
title: AppStrings.approvedTenders,
|
title: AppStrings.approvedTenders,
|
||||||
amount: '0',
|
amount: '0',
|
||||||
|
|
||||||
textColor: Color(0xFF24848E),
|
textColor: AppColors.jellyBean,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
YourTendersRouteData().push(context);
|
YourTendersRouteData().push(context);
|
||||||
@@ -157,7 +138,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
iconPath: AssetsManager.shield,
|
iconPath: AssetsManager.shield,
|
||||||
title: AppStrings.tenderValue,
|
title: AppStrings.tenderValue,
|
||||||
amount: '3',
|
amount: '3',
|
||||||
textColor: Color(0xFFE5821E),
|
textColor: AppColors.orange,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
@@ -166,7 +147,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
iconPath: AssetsManager.thumbLike,
|
iconPath: AssetsManager.thumbLike,
|
||||||
title: AppStrings.likedTenders,
|
title: AppStrings.likedTenders,
|
||||||
amount: homeViewModel.feedbackStats?.totalLikes.toString() ?? '0',
|
amount: homeViewModel.feedbackStats?.totalLikes.toString() ?? '0',
|
||||||
textColor: Color(0xFF9E9E9E),
|
textColor: AppColors.grey80,
|
||||||
enableTap: false,
|
enableTap: false,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -81,58 +81,56 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
return Center(child: Text(homeViewModel.errorMessage!));
|
return Center(child: Text(homeViewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SingleChildScrollView(
|
if (homeViewModel.tenderApprovalsStateResponse != null &&
|
||||||
child: Padding(
|
homeViewModel.data != null &&
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
homeViewModel.feedbackStats != null) {
|
||||||
24.0.w(),
|
return SingleChildScrollView(
|
||||||
24.0.h(),
|
child: Padding(
|
||||||
24.0.w(),
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
24.0.h(),
|
24.0.w(),
|
||||||
|
24.0.h(),
|
||||||
|
24.0.w(),
|
||||||
|
24.0.h(),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// NotificationCard(),
|
||||||
|
SizedBox(height: 40.0.h()),
|
||||||
|
_progressBarsRow(homeViewModel),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
_firstTenderCardsRow(
|
||||||
|
context,
|
||||||
|
homeViewModel.tenderApprovalsStateResponse!,
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.0.h()),
|
||||||
|
_secondTenderCardsRow(homeViewModel),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
_yourTenderText(homeViewModel),
|
||||||
|
SizedBox(height: 8.0.h()),
|
||||||
|
_bottomListView(homeViewModel),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
}
|
||||||
children: [
|
return const Center(
|
||||||
// NotificationCard(),
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
SizedBox(height: 40.0.h()),
|
|
||||||
_progressBarsRow(homeViewModel.tenderApprovalsStateResponse!),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
_firstTenderCardsRow(
|
|
||||||
context,
|
|
||||||
homeViewModel.tenderApprovalsStateResponse!,
|
|
||||||
),
|
|
||||||
SizedBox(height: 8.0.h()),
|
|
||||||
_secondTenderCardsRow(homeViewModel),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
_yourTenderText(homeViewModel),
|
|
||||||
SizedBox(height: 8.0.h()),
|
|
||||||
_bottomListView(homeViewModel),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _progressBarsRow(
|
Widget _progressBarsRow(HomeViewModel homeViewModel) {
|
||||||
TenderApprovalsStateResponse tenderApprovalsStateResponse,
|
|
||||||
) {
|
|
||||||
final partnership =
|
|
||||||
tenderApprovalsStateResponse.data!.partnershipCount ?? 0;
|
|
||||||
final selfApply = tenderApprovalsStateResponse.data!.selfApplyCount ?? 0;
|
|
||||||
final total = (partnership + selfApply);
|
|
||||||
|
|
||||||
final partnershipPercent = total > 0 ? (partnership / total) * 100 : 0;
|
|
||||||
final selfApplyPercent = total > 0 ? (selfApply / total) * 100 : 0;
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Spacer(),
|
Spacer(),
|
||||||
SizedBox(width: 20.0.w()),
|
SizedBox(width: 20.0.w()),
|
||||||
ProgressBarColumn(
|
ProgressBarColumn(
|
||||||
text: AppStrings.partnership,
|
text: AppStrings.partnership,
|
||||||
value: double.parse('$partnershipPercent'),
|
value: homeViewModel.partnershipPercent,
|
||||||
amount: double.parse('$partnershipPercent').toString(),
|
amount: homeViewModel.partnershipPercent.toString(),
|
||||||
circularProgressIndicatorWidth: 176.0,
|
circularProgressIndicatorWidth: 176.0,
|
||||||
circularProgressIndicatorHeight: 176.0,
|
circularProgressIndicatorHeight: 176.0,
|
||||||
strokeWidth: 8.0,
|
strokeWidth: 8.0,
|
||||||
@@ -140,22 +138,14 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
Spacer(),
|
Spacer(),
|
||||||
ProgressBarColumn(
|
ProgressBarColumn(
|
||||||
text: AppStrings.selfApply,
|
text: AppStrings.selfApply,
|
||||||
value: double.parse(selfApplyPercent.toString()),
|
value: homeViewModel.selfApplyPercent,
|
||||||
amount: double.parse(selfApplyPercent.toString()).toString(),
|
amount: homeViewModel.selfApplyPercent.toString(),
|
||||||
circularProgressIndicatorWidth: 176.0,
|
circularProgressIndicatorWidth: 176.0,
|
||||||
circularProgressIndicatorHeight: 176.0,
|
circularProgressIndicatorHeight: 176.0,
|
||||||
strokeWidth: 8.0,
|
strokeWidth: 8.0,
|
||||||
),
|
),
|
||||||
SizedBox(width: 20.0.w()),
|
SizedBox(width: 20.0.w()),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
// ProgressBarColumn(
|
|
||||||
// text: AppStrings.contracting,
|
|
||||||
// value: double.parse(homeResponse.contracting ?? '0'),
|
|
||||||
// amount: homeResponse.contracting ?? '0',
|
|
||||||
// circularProgressIndicatorWidth: 176.0,
|
|
||||||
// circularProgressIndicatorHeight: 176.0,
|
|
||||||
// strokeWidth: 8.0,
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -170,16 +160,12 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TenderCard(
|
child: TenderCard(
|
||||||
backgroundColor: AppColors.primary20,
|
backgroundColor: AppColors.primary20,
|
||||||
iconPath: 'assets/icons/arrows.svg',
|
iconPath: AssetsManager.arrows,
|
||||||
title: AppStrings.tenderSubmitted,
|
title: AppStrings.tenderSubmitted,
|
||||||
amount:
|
amount:
|
||||||
tenderApprovalsStateResponse.data!.submittedTenders.toString(),
|
tenderApprovalsStateResponse.data!.submittedTenders.toString(),
|
||||||
// tenderApprovalsStateResponse
|
|
||||||
// .data!
|
textColor: AppColors.mainBlue,
|
||||||
// .approvalsBySubmission!
|
|
||||||
// .selfApply
|
|
||||||
// .toString(),
|
|
||||||
textColor: Color(0xFF0164FF),
|
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 148,
|
height: 148,
|
||||||
@@ -196,7 +182,7 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
title: AppStrings.approvedTenders,
|
title: AppStrings.approvedTenders,
|
||||||
amount: '0',
|
amount: '0',
|
||||||
|
|
||||||
textColor: Color(0xFF24848E),
|
textColor: AppColors.jellyBean,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 148,
|
height: 148,
|
||||||
@@ -217,10 +203,10 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TenderCard(
|
child: TenderCard(
|
||||||
backgroundColor: AppColors.orange10,
|
backgroundColor: AppColors.orange10,
|
||||||
iconPath: 'assets/icons/shield.svg',
|
iconPath: AssetsManager.shield,
|
||||||
title: AppStrings.tenderValue,
|
title: AppStrings.tenderValue,
|
||||||
amount: '3',
|
amount: '3',
|
||||||
textColor: Color(0xFFE5821E),
|
textColor: AppColors.orange,
|
||||||
enableTap: true,
|
enableTap: true,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 148,
|
height: 148,
|
||||||
@@ -234,7 +220,7 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
iconPath: AssetsManager.thumbLike,
|
iconPath: AssetsManager.thumbLike,
|
||||||
title: AppStrings.likedTenders,
|
title: AppStrings.likedTenders,
|
||||||
amount: homeViewModel.feedbackStats?.totalLikes.toString() ?? '0',
|
amount: homeViewModel.feedbackStats?.totalLikes.toString() ?? '0',
|
||||||
textColor: Color(0xFF9E9E9E),
|
textColor: AppColors.grey80,
|
||||||
enableTap: false,
|
enableTap: false,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 148,
|
height: 148,
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class _ProgressBarColumnState extends State<ProgressBarColumn>
|
|||||||
animation: _animation,
|
animation: _animation,
|
||||||
builder:
|
builder:
|
||||||
(context, child) => CircularProgressIndicator(
|
(context, child) => CircularProgressIndicator(
|
||||||
backgroundColor: Color(0xFFE1E1E1),
|
backgroundColor: AppColors.grey10,
|
||||||
strokeCap: StrokeCap.round,
|
strokeCap: StrokeCap.round,
|
||||||
strokeWidth: widget.strokeWidth ?? 6.0,
|
strokeWidth: widget.strokeWidth ?? 6.0,
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(AppColors.jellyBean),
|
valueColor: AlwaysStoppedAnimation<Color>(AppColors.jellyBean),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
import '../../core/constants/assets.dart';
|
import '../../core/constants/assets.dart';
|
||||||
|
import '../../core/theme/colors.dart';
|
||||||
import '../../core/utils/size_config.dart';
|
import '../../core/utils/size_config.dart';
|
||||||
|
|
||||||
class TenderCard extends StatelessWidget {
|
class TenderCard extends StatelessWidget {
|
||||||
@@ -50,7 +51,7 @@ class TenderCard extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0.sp(),
|
fontSize: 16.0.sp(),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color(0xFF777777),
|
color: AppColors.grey80,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ class TendersListItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
// SizedBox(height: 18.0.h()),
|
|
||||||
TenderCardProgressBar(),
|
TenderCardProgressBar(),
|
||||||
SizedBox(height: 15.0.h()),
|
SizedBox(height: 15.0.h()),
|
||||||
|
|
||||||
@@ -123,23 +122,6 @@ class TendersListItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
// Container(
|
|
||||||
// width: 96.0.w(),
|
|
||||||
// height: 24.0.h(),
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: AppColors.grey30,
|
|
||||||
// borderRadius: BorderRadius.circular(88),
|
|
||||||
// ),
|
|
||||||
// alignment: Alignment.center,
|
|
||||||
// child: Text(
|
|
||||||
// 'tender.type',
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: 12.0.sp(),
|
|
||||||
// fontWeight: FontWeight.w500,
|
|
||||||
// color: AppColors.grey60,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class TenderCardProgressBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
AppStrings.tenderMatchPercentageExample,
|
'75%',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.0.sp(),
|
fontSize: 12.0.sp(),
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ class _DesktopProfilePageState extends State<DesktopProfilePage> {
|
|||||||
return Center(child: Text(viewModel.errorMessage!));
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (viewModel.companyProfileData == null) {
|
||||||
|
return Center(child: Text(AppStrings.noData));
|
||||||
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
DesktopNavigationWidget(
|
DesktopNavigationWidget(
|
||||||
@@ -81,34 +85,34 @@ class _DesktopProfilePageState extends State<DesktopProfilePage> {
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// Already on profile
|
// Already on profile
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
// color: Colors.amber.shade100,
|
|
||||||
width: 740,
|
width: 740,
|
||||||
// height: 662,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 36.0.h()),
|
SizedBox(height: 36.0.h()),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Company Name',
|
title: AppStrings.companyName,
|
||||||
description: viewModel.companyProfileData!.name!,
|
description: viewModel.companyProfileData!.name!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'National ID',
|
title: AppStrings.nationalId,
|
||||||
description: viewModel.companyProfileData!.id!,
|
description: viewModel.companyProfileData!.id!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Registration No.',
|
title: AppStrings.registrationNumber,
|
||||||
description:
|
description:
|
||||||
viewModel.companyProfileData!.registrationNumber!,
|
viewModel.companyProfileData!.registrationNumber!,
|
||||||
),
|
),
|
||||||
TitleDescription(title: 'Business Type', description: '-'),
|
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Founded',
|
title: AppStrings.businessType,
|
||||||
|
description: '-',
|
||||||
|
),
|
||||||
|
TitleDescription(
|
||||||
|
title: AppStrings.founded,
|
||||||
description:
|
description:
|
||||||
viewModel.companyProfileData!.foundedYear!.toString(),
|
viewModel.companyProfileData!.foundedYear!.toString(),
|
||||||
),
|
),
|
||||||
@@ -168,7 +172,7 @@ class _DesktopProfilePageState extends State<DesktopProfilePage> {
|
|||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Logout',
|
AppStrings.logout,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0.sp(),
|
fontSize: 14.0.sp(),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ class _MobileProfilePageState extends State<MobileProfilePage> {
|
|||||||
return Center(child: Text(viewModel.errorMessage!));
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (viewModel.companyProfileData == null) {
|
||||||
|
return Center(child: Text(AppStrings.noData));
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: 24.0.w(),
|
horizontal: 24.0.w(),
|
||||||
@@ -74,21 +78,24 @@ class _MobileProfilePageState extends State<MobileProfilePage> {
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(height: 36.0.h()),
|
SizedBox(height: 36.0.h()),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Company Name',
|
title: AppStrings.companyName,
|
||||||
description: viewModel.companyProfileData!.name!,
|
description: viewModel.companyProfileData!.name!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'National ID',
|
title: AppStrings.nationalId,
|
||||||
description: viewModel.companyProfileData!.id!,
|
description: viewModel.companyProfileData!.id!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Registration No.',
|
title: AppStrings.registrationNumber,
|
||||||
description:
|
description:
|
||||||
viewModel.companyProfileData!.registrationNumber!,
|
viewModel.companyProfileData!.registrationNumber!,
|
||||||
),
|
),
|
||||||
TitleDescription(title: 'Business Type', description: '-'),
|
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Founded',
|
title: AppStrings.businessType,
|
||||||
|
description: '-',
|
||||||
|
),
|
||||||
|
TitleDescription(
|
||||||
|
title: AppStrings.founded,
|
||||||
description:
|
description:
|
||||||
viewModel.companyProfileData!.foundedYear!.toString(),
|
viewModel.companyProfileData!.foundedYear!.toString(),
|
||||||
),
|
),
|
||||||
@@ -145,7 +152,7 @@ class _MobileProfilePageState extends State<MobileProfilePage> {
|
|||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Logout',
|
AppStrings.logout,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0.sp(),
|
fontSize: 14.0.sp(),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ class _TabletProfilePageState extends State<TabletProfilePage> {
|
|||||||
return Center(child: Text(viewModel.errorMessage!));
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (viewModel.companyProfileData == null) {
|
||||||
|
return Center(child: Text(AppStrings.noData));
|
||||||
|
}
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
key: key,
|
key: key,
|
||||||
@@ -118,22 +122,27 @@ class _TabletProfilePageState extends State<TabletProfilePage> {
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(height: 128.0.h()),
|
SizedBox(height: 128.0.h()),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Company Name',
|
title: AppStrings.companyName,
|
||||||
description: 'Telecom Solutions GmbH',
|
description: viewModel.companyProfileData!.name!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'National ID',
|
title: AppStrings.nationalId,
|
||||||
description: '12345678901',
|
description: viewModel.companyProfileData!.id!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Registration No.',
|
title: AppStrings.registrationNumber,
|
||||||
description: 'DE-55667788',
|
description:
|
||||||
|
viewModel.companyProfileData!.registrationNumber!,
|
||||||
),
|
),
|
||||||
TitleDescription(
|
TitleDescription(
|
||||||
title: 'Business Type',
|
title: AppStrings.businessType,
|
||||||
description: 'Telecommunications',
|
description: '-',
|
||||||
|
),
|
||||||
|
TitleDescription(
|
||||||
|
title: AppStrings.founded,
|
||||||
|
description:
|
||||||
|
viewModel.companyProfileData!.foundedYear!.toString(),
|
||||||
),
|
),
|
||||||
TitleDescription(title: 'Founded', description: '2010'),
|
|
||||||
SizedBox(height: 24.0.h()),
|
SizedBox(height: 24.0.h()),
|
||||||
// Theme Toggle
|
// Theme Toggle
|
||||||
Align(
|
Align(
|
||||||
@@ -190,7 +199,7 @@ class _TabletProfilePageState extends State<TabletProfilePage> {
|
|||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Logout',
|
AppStrings.logout,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0.sp(),
|
fontSize: 14.0.sp(),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
class Tender {
|
|
||||||
final String date;
|
|
||||||
final String deadline;
|
|
||||||
final String title;
|
|
||||||
final String description;
|
|
||||||
final String tenderId;
|
|
||||||
final String location;
|
|
||||||
final String country;
|
|
||||||
final double matchPercentage;
|
|
||||||
|
|
||||||
Tender({
|
|
||||||
required this.date,
|
|
||||||
required this.deadline,
|
|
||||||
required this.title,
|
|
||||||
required this.description,
|
|
||||||
required this.tenderId,
|
|
||||||
required this.location,
|
|
||||||
required this.country,
|
|
||||||
required this.matchPercentage,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory Tender.fromJson(Map<String, dynamic> json) {
|
|
||||||
return Tender(
|
|
||||||
date: json['date'] as String,
|
|
||||||
deadline: json['deadline'] as String,
|
|
||||||
title: json['title'] as String,
|
|
||||||
description: json['description'] as String,
|
|
||||||
tenderId: json['tenderId'] as String,
|
|
||||||
location: json['location'] as String,
|
|
||||||
country: json['country'] as String,
|
|
||||||
matchPercentage: (json['matchPercentage'] as num).toDouble(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'date': date,
|
|
||||||
'deadline': deadline,
|
|
||||||
'title': title,
|
|
||||||
'description': description,
|
|
||||||
'tenderId': tenderId,
|
|
||||||
'location': location,
|
|
||||||
'country': country,
|
|
||||||
'matchPercentage': matchPercentage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Tender> sampleTenders = [
|
|
||||||
Tender(
|
|
||||||
date: '2025-05-20',
|
|
||||||
deadline: '2025-06-10',
|
|
||||||
title: 'Digital Services Tender',
|
|
||||||
description:
|
|
||||||
'A tender for digital services and IT infrastructure development. The project involves modernizing existing systems and implementing new digital solutions for improved efficiency.',
|
|
||||||
tenderId: 'KLF 2025/119',
|
|
||||||
location: 'Stockholm',
|
|
||||||
country: 'SE',
|
|
||||||
matchPercentage: 85.0,
|
|
||||||
),
|
|
||||||
Tender(
|
|
||||||
date: '2025-04-15',
|
|
||||||
deadline: '2025-05-01',
|
|
||||||
title: 'Construction Project',
|
|
||||||
description:
|
|
||||||
'Seeking contractors for a large-scale construction project in the city center. Includes both residential and commercial buildings.',
|
|
||||||
tenderId: 'CST 2025/042',
|
|
||||||
location: 'Gothenburg',
|
|
||||||
country: 'SE',
|
|
||||||
matchPercentage: 72.0,
|
|
||||||
),
|
|
||||||
Tender(
|
|
||||||
date: '2025-03-10',
|
|
||||||
deadline: '2025-04-05',
|
|
||||||
title: 'Healthcare Equipment Supply',
|
|
||||||
description:
|
|
||||||
'Supplying medical and healthcare equipment to regional hospitals. Includes installation and maintenance services.',
|
|
||||||
tenderId: 'HLT 2025/301',
|
|
||||||
location: 'Malmö',
|
|
||||||
country: 'SE',
|
|
||||||
matchPercentage: 90.0,
|
|
||||||
),
|
|
||||||
Tender(
|
|
||||||
date: '2025-02-28',
|
|
||||||
deadline: '2025-03-20',
|
|
||||||
title: 'IT Consulting Services',
|
|
||||||
description:
|
|
||||||
'Looking for experienced IT consultants to support digital transformation initiatives for public sector organizations.',
|
|
||||||
tenderId: 'ITC 2025/210',
|
|
||||||
location: 'Uppsala',
|
|
||||||
country: 'SE',
|
|
||||||
matchPercentage: 78.0,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
@@ -8,6 +8,8 @@ import 'package:tm_app/view_models/tenders_view_model.dart';
|
|||||||
import 'package:tm_app/views/shared/desktop_navigation_widget.dart';
|
import 'package:tm_app/views/shared/desktop_navigation_widget.dart';
|
||||||
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
|
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
|
||||||
class DesktopTendersPage extends StatefulWidget {
|
class DesktopTendersPage extends StatefulWidget {
|
||||||
const DesktopTendersPage({super.key});
|
const DesktopTendersPage({super.key});
|
||||||
|
|
||||||
@@ -91,6 +93,10 @@ class _DesktopTendersPageState extends State<DesktopTendersPage> {
|
|||||||
if (viewModel.errorMessage != null) {
|
if (viewModel.errorMessage != null) {
|
||||||
return Center(child: Text(viewModel.errorMessage!));
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
if (viewModel.tendersResponse?.data?.tenders == null ||
|
||||||
|
viewModel.tendersResponse!.data!.tenders!.isEmpty) {
|
||||||
|
return Center(child: Text(AppStrings.noData));
|
||||||
|
}
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 740,
|
width: 740,
|
||||||
height: 800,
|
height: 800,
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ class _MobileTendersPageState extends State<MobileTendersPage> {
|
|||||||
return Center(child: Text(viewModel.errorMessage!));
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (viewModel.tendersResponse?.data?.tenders == null ||
|
||||||
|
viewModel.tendersResponse!.data!.tenders!.isEmpty) {
|
||||||
|
return Center(child: Text(AppStrings.noData));
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 24.0.h()),
|
padding: EdgeInsets.symmetric(vertical: 24.0.h()),
|
||||||
child: MainTendersSlider(
|
child: MainTendersSlider(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:tm_app/views/shared/tablet_navigation_widget.dart';
|
|||||||
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
|
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
|
||||||
|
|
||||||
import '../../../core/constants/assets.dart';
|
import '../../../core/constants/assets.dart';
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
|
||||||
class TabletTendersPage extends StatelessWidget {
|
class TabletTendersPage extends StatelessWidget {
|
||||||
const TabletTendersPage({super.key});
|
const TabletTendersPage({super.key});
|
||||||
@@ -73,6 +74,10 @@ class TabletTendersPage extends StatelessWidget {
|
|||||||
if (viewModel.errorMessage != null) {
|
if (viewModel.errorMessage != null) {
|
||||||
return Center(child: Text(viewModel.errorMessage!));
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
}
|
}
|
||||||
|
if (viewModel.tendersResponse?.data?.tenders == null ||
|
||||||
|
viewModel.tendersResponse!.data!.tenders!.isEmpty) {
|
||||||
|
return Center(child: Text(AppStrings.noData));
|
||||||
|
}
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(right: 24.0.w(), top: 128.0.h()),
|
padding: EdgeInsets.only(right: 24.0.w(), top: 128.0.h()),
|
||||||
child: MainTendersSlider(
|
child: MainTendersSlider(
|
||||||
|
|||||||
@@ -207,7 +207,10 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
viewModel.feedback(tenderId: tender.id!, feedbackType: 'dislike');
|
viewModel.toogleFeedback(
|
||||||
|
tenderId: tender.id!,
|
||||||
|
feedbackType: 'dislike',
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -251,7 +254,7 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
viewModel.feedback(tenderId: tender.id!, feedbackType: 'like');
|
viewModel.toogleFeedback(tenderId: tender.id!, feedbackType: 'like');
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -154,59 +154,6 @@ class TenderCard extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widget _approvalStatusBadge() {
|
|
||||||
// return Consumer<TendersViewModel>(
|
|
||||||
// builder: (context, viewModel, child) {
|
|
||||||
// final approvalStatus = viewModel.getApprovalStatusForTender(tender.id!);
|
|
||||||
// final statusText = approvalStatus ?? 'Pending';
|
|
||||||
|
|
||||||
// Color statusColor;
|
|
||||||
// switch (approvalStatus) {
|
|
||||||
// case 'approved':
|
|
||||||
// statusColor = AppColors.successColor;
|
|
||||||
// break;
|
|
||||||
// case 'rejected':
|
|
||||||
// statusColor = AppColors.errorColor;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// statusColor = AppColors.grey60;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return Container(
|
|
||||||
// width: double.infinity,
|
|
||||||
// height: 24.0.h(),
|
|
||||||
// padding: EdgeInsets.symmetric(horizontal: 8.0.w()),
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: AppColors.grey20,
|
|
||||||
// borderRadius: BorderRadius.circular(4),
|
|
||||||
// border: Border.all(color: statusColor),
|
|
||||||
// ),
|
|
||||||
// child: Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
// children: [
|
|
||||||
// Text(
|
|
||||||
// 'Approval Status',
|
|
||||||
// style: TextStyle(
|
|
||||||
// color: AppColors.grey80,
|
|
||||||
// fontSize: 14.0.sp(),
|
|
||||||
// fontWeight: FontWeight.w500,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Text(
|
|
||||||
// statusText.toUpperCase(),
|
|
||||||
// style: TextStyle(
|
|
||||||
// color: statusColor,
|
|
||||||
// fontSize: 14.0.sp(),
|
|
||||||
// fontWeight: FontWeight.w500,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
Widget _tenderTitle() {
|
Widget _tenderTitle() {
|
||||||
return Text(
|
return Text(
|
||||||
tender.title ?? '',
|
tender.title ?? '',
|
||||||
|
|||||||
Reference in New Issue
Block a user