Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
gen_services
Commits
97403192
Commit
97403192
authored
Nov 14, 2025
by
Sai Srinivas
Committed by
Sai Srinivas
Nov 15, 2025
Browse files
Icon inserted and few changes
parent
5a62c920
Changes
57
Hide whitespace changes
Inline
Side-by-side
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
deleted
100644 → 0
View file @
5a62c920
586 Bytes
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
deleted
100644 → 0
View file @
5a62c920
862 Bytes
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
deleted
100644 → 0
View file @
5a62c920
862 Bytes
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
deleted
100644 → 0
View file @
5a62c920
1.63 KB
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
deleted
100644 → 0
View file @
5a62c920
762 Bytes
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
deleted
100644 → 0
View file @
5a62c920
1.2 KB
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
deleted
100644 → 0
View file @
5a62c920
1.38 KB
lib/Models/HelpAndComplaintModels/allJobCardListResponse.dart
0 → 100644
View file @
97403192
class
allJobCardListResponse
{
String
?
error
;
List
<
JobCardList
>?
jobCardList
;
String
?
message
;
allJobCardListResponse
({
this
.
error
,
this
.
jobCardList
,
this
.
message
});
allJobCardListResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
if
(
json
[
'job_card_list'
]
!=
null
)
{
jobCardList
=
<
JobCardList
>[];
json
[
'job_card_list'
].
forEach
((
v
)
{
jobCardList
!.
add
(
new
JobCardList
.
fromJson
(
v
));
});
}
message
=
json
[
'message'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
if
(
this
.
jobCardList
!=
null
)
{
data
[
'job_card_list'
]
=
this
.
jobCardList
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
data
[
'message'
]
=
this
.
message
;
return
data
;
}
}
class
JobCardList
{
String
?
id
;
String
?
complaintId
;
String
?
extraDescription
;
String
?
date
;
String
?
totalPrice
;
JobCardList
(
{
this
.
id
,
this
.
complaintId
,
this
.
extraDescription
,
this
.
date
,
this
.
totalPrice
});
JobCardList
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
complaintId
=
json
[
'complaint_id'
];
extraDescription
=
json
[
'extra_description'
];
date
=
json
[
'date'
];
totalPrice
=
json
[
'total_price'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'complaint_id'
]
=
this
.
complaintId
;
data
[
'extra_description'
]
=
this
.
extraDescription
;
data
[
'date'
]
=
this
.
date
;
data
[
'total_price'
]
=
this
.
totalPrice
;
return
data
;
}
}
lib/Models/HelpAndComplaintModels/allServiceListResponse.dart
0 → 100644
View file @
97403192
class
allServiceListResponse
{
String
?
error
;
TechDetails
?
techDetails
;
List
<
AllServiceList
>?
allServiceList
;
String
?
message
;
allServiceListResponse
(
{
this
.
error
,
this
.
techDetails
,
this
.
allServiceList
,
this
.
message
});
allServiceListResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
techDetails
=
json
[
'tech_details'
]
!=
null
?
new
TechDetails
.
fromJson
(
json
[
'tech_details'
])
:
null
;
if
(
json
[
'all_service_list'
]
!=
null
)
{
allServiceList
=
<
AllServiceList
>[];
json
[
'all_service_list'
].
forEach
((
v
)
{
allServiceList
!.
add
(
new
AllServiceList
.
fromJson
(
v
));
});
}
message
=
json
[
'message'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
if
(
this
.
techDetails
!=
null
)
{
data
[
'tech_details'
]
=
this
.
techDetails
!.
toJson
();
}
if
(
this
.
allServiceList
!=
null
)
{
data
[
'all_service_list'
]
=
this
.
allServiceList
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
data
[
'message'
]
=
this
.
message
;
return
data
;
}
}
class
TechDetails
{
String
?
id
;
String
?
empName
;
String
?
techRoleName
;
String
?
mobNum
;
String
?
lat
;
String
?
lng
;
String
?
profileImg
;
TechDetails
(
{
this
.
id
,
this
.
empName
,
this
.
techRoleName
,
this
.
mobNum
,
this
.
lat
,
this
.
lng
,
this
.
profileImg
});
TechDetails
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
empName
=
json
[
'emp_name'
];
techRoleName
=
json
[
'tech_role_name'
];
mobNum
=
json
[
'mob_num'
];
lat
=
json
[
'lat'
];
lng
=
json
[
'lng'
];
profileImg
=
json
[
'profile_img'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'emp_name'
]
=
this
.
empName
;
data
[
'tech_role_name'
]
=
this
.
techRoleName
;
data
[
'mob_num'
]
=
this
.
mobNum
;
data
[
'lat'
]
=
this
.
lat
;
data
[
'lng'
]
=
this
.
lng
;
data
[
'profile_img'
]
=
this
.
profileImg
;
return
data
;
}
}
class
AllServiceList
{
String
?
id
;
String
?
empName
;
String
?
date
;
String
?
techRoleName
;
String
?
mobNum
;
String
?
profileImg
;
String
?
feedback
;
String
?
openStatus
;
String
?
customerServiceRating
;
String
?
inOrOutTime
;
String
?
runningHrs
;
String
?
fsrExt
;
String
?
fsrNo
;
AllServiceList
(
{
this
.
id
,
this
.
empName
,
this
.
date
,
this
.
techRoleName
,
this
.
mobNum
,
this
.
profileImg
,
this
.
feedback
,
this
.
openStatus
,
this
.
customerServiceRating
,
this
.
inOrOutTime
,
this
.
runningHrs
,
this
.
fsrExt
,
this
.
fsrNo
});
AllServiceList
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
empName
=
json
[
'emp_name'
];
date
=
json
[
'date'
];
techRoleName
=
json
[
'tech_role_name'
];
mobNum
=
json
[
'mob_num'
];
profileImg
=
json
[
'profile_img'
];
feedback
=
json
[
'feedback'
];
openStatus
=
json
[
'open_status'
];
customerServiceRating
=
json
[
'customer_service_rating'
];
inOrOutTime
=
json
[
'in_or_out_time'
];
runningHrs
=
json
[
'running_hrs'
];
fsrExt
=
json
[
'fsr_ext'
];
fsrNo
=
json
[
'fsr_no'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'emp_name'
]
=
this
.
empName
;
data
[
'date'
]
=
this
.
date
;
data
[
'tech_role_name'
]
=
this
.
techRoleName
;
data
[
'mob_num'
]
=
this
.
mobNum
;
data
[
'profile_img'
]
=
this
.
profileImg
;
data
[
'feedback'
]
=
this
.
feedback
;
data
[
'open_status'
]
=
this
.
openStatus
;
data
[
'customer_service_rating'
]
=
this
.
customerServiceRating
;
data
[
'in_or_out_time'
]
=
this
.
inOrOutTime
;
data
[
'running_hrs'
]
=
this
.
runningHrs
;
data
[
'fsr_ext'
]
=
this
.
fsrExt
;
data
[
'fsr_no'
]
=
this
.
fsrNo
;
return
data
;
}
}
lib/Models/HelpAndComplaintModels/complaintDetailsResponse.dart
0 → 100644
View file @
97403192
class
complaintDetailsResponse
{
String
?
error
;
List
<
ComplaintDetails
>?
complaintDetails
;
List
<
JobCardList
>?
jobCardList
;
List
<
ServiceDetails
>?
serviceDetails
;
String
?
message
;
String
?
sessionExists
;
complaintDetailsResponse
(
{
this
.
error
,
this
.
complaintDetails
,
this
.
jobCardList
,
this
.
serviceDetails
,
this
.
message
,
this
.
sessionExists
});
complaintDetailsResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
if
(
json
[
'complaint_details'
]
!=
null
)
{
complaintDetails
=
<
ComplaintDetails
>[];
json
[
'complaint_details'
].
forEach
((
v
)
{
complaintDetails
!.
add
(
new
ComplaintDetails
.
fromJson
(
v
));
});
}
if
(
json
[
'job_card_list'
]
!=
null
)
{
jobCardList
=
<
JobCardList
>[];
json
[
'job_card_list'
].
forEach
((
v
)
{
jobCardList
!.
add
(
new
JobCardList
.
fromJson
(
v
));
});
}
if
(
json
[
'service_details'
]
!=
null
)
{
serviceDetails
=
<
ServiceDetails
>[];
json
[
'service_details'
].
forEach
((
v
)
{
serviceDetails
!.
add
(
new
ServiceDetails
.
fromJson
(
v
));
});
}
message
=
json
[
'message'
];
sessionExists
=
json
[
'session_exists'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
if
(
this
.
complaintDetails
!=
null
)
{
data
[
'complaint_details'
]
=
this
.
complaintDetails
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
if
(
this
.
jobCardList
!=
null
)
{
data
[
'job_card_list'
]
=
this
.
jobCardList
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
if
(
this
.
serviceDetails
!=
null
)
{
data
[
'service_details'
]
=
this
.
serviceDetails
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
data
[
'message'
]
=
this
.
message
;
data
[
'session_exists'
]
=
this
.
sessionExists
;
return
data
;
}
}
class
ComplaintDetails
{
String
?
id
;
String
?
openStatus
;
String
?
registredDate
;
String
?
hashId
;
String
?
productName
;
String
?
complaintName
;
String
?
complaintDesc
;
String
?
complaintNote
;
ComplaintDetails
(
{
this
.
id
,
this
.
openStatus
,
this
.
registredDate
,
this
.
hashId
,
this
.
productName
,
this
.
complaintName
,
this
.
complaintDesc
,
this
.
complaintNote
});
ComplaintDetails
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
openStatus
=
json
[
'open_status'
];
registredDate
=
json
[
'registred_date'
];
hashId
=
json
[
'hash_id'
];
productName
=
json
[
'product_name'
];
complaintName
=
json
[
'complaint_name'
];
complaintDesc
=
json
[
'complaint_desc'
];
complaintNote
=
json
[
'complaint_note'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'open_status'
]
=
this
.
openStatus
;
data
[
'registred_date'
]
=
this
.
registredDate
;
data
[
'hash_id'
]
=
this
.
hashId
;
data
[
'product_name'
]
=
this
.
productName
;
data
[
'complaint_name'
]
=
this
.
complaintName
;
data
[
'complaint_desc'
]
=
this
.
complaintDesc
;
data
[
'complaint_note'
]
=
this
.
complaintNote
;
return
data
;
}
}
class
JobCardList
{
String
?
id
;
String
?
complaintId
;
String
?
extraDescription
;
String
?
date
;
String
?
totalPrice
;
JobCardList
(
{
this
.
id
,
this
.
complaintId
,
this
.
extraDescription
,
this
.
date
,
this
.
totalPrice
});
JobCardList
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
complaintId
=
json
[
'complaint_id'
];
extraDescription
=
json
[
'extra_description'
];
date
=
json
[
'date'
];
totalPrice
=
json
[
'total_price'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'complaint_id'
]
=
this
.
complaintId
;
data
[
'extra_description'
]
=
this
.
extraDescription
;
data
[
'date'
]
=
this
.
date
;
data
[
'total_price'
]
=
this
.
totalPrice
;
return
data
;
}
}
class
ServiceDetails
{
String
?
id
;
String
?
empName
;
String
?
lat
;
String
?
lng
;
String
?
paymentStatus
;
String
?
date
;
String
?
techRoleName
;
String
?
mobNum
;
String
?
profileImg
;
String
?
feedback
;
String
?
openStatus
;
String
?
rating
;
String
?
inOrOutTime
;
String
?
runningHrs
;
String
?
fsrExt
;
String
?
fsrNo
;
ServiceDetails
(
{
this
.
id
,
this
.
empName
,
this
.
lat
,
this
.
lng
,
this
.
paymentStatus
,
this
.
date
,
this
.
techRoleName
,
this
.
mobNum
,
this
.
profileImg
,
this
.
feedback
,
this
.
openStatus
,
this
.
rating
,
this
.
inOrOutTime
,
this
.
runningHrs
,
this
.
fsrExt
,
this
.
fsrNo
});
ServiceDetails
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
empName
=
json
[
'emp_name'
];
lat
=
json
[
'lat'
];
lng
=
json
[
'lng'
];
paymentStatus
=
json
[
'payment_status'
];
date
=
json
[
'date'
];
techRoleName
=
json
[
'tech_role_name'
];
mobNum
=
json
[
'mob_num'
];
profileImg
=
json
[
'profile_img'
];
feedback
=
json
[
'feedback'
];
openStatus
=
json
[
'open_status'
];
rating
=
json
[
'rating'
];
inOrOutTime
=
json
[
'in_or_out_time'
];
runningHrs
=
json
[
'running_hrs'
];
fsrExt
=
json
[
'fsr_ext'
];
fsrNo
=
json
[
'fsr_no'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'emp_name'
]
=
this
.
empName
;
data
[
'lat'
]
=
this
.
lat
;
data
[
'lng'
]
=
this
.
lng
;
data
[
'payment_status'
]
=
this
.
paymentStatus
;
data
[
'date'
]
=
this
.
date
;
data
[
'tech_role_name'
]
=
this
.
techRoleName
;
data
[
'mob_num'
]
=
this
.
mobNum
;
data
[
'profile_img'
]
=
this
.
profileImg
;
data
[
'feedback'
]
=
this
.
feedback
;
data
[
'open_status'
]
=
this
.
openStatus
;
data
[
'rating'
]
=
this
.
rating
;
data
[
'in_or_out_time'
]
=
this
.
inOrOutTime
;
data
[
'running_hrs'
]
=
this
.
runningHrs
;
data
[
'fsr_ext'
]
=
this
.
fsrExt
;
data
[
'fsr_no'
]
=
this
.
fsrNo
;
return
data
;
}
}
lib/Models/HelpAndComplaintModels/jobCardProductsResponse.dart
0 → 100644
View file @
97403192
class
jobCardProductsResponse
{
String
?
error
;
List
<
JobCardProducts
>?
jobCardProducts
;
String
?
message
;
jobCardProductsResponse
({
this
.
error
,
this
.
jobCardProducts
,
this
.
message
});
jobCardProductsResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
if
(
json
[
'job_card_products'
]
!=
null
)
{
jobCardProducts
=
<
JobCardProducts
>[];
json
[
'job_card_products'
].
forEach
((
v
)
{
jobCardProducts
!.
add
(
new
JobCardProducts
.
fromJson
(
v
));
});
}
message
=
json
[
'message'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
if
(
this
.
jobCardProducts
!=
null
)
{
data
[
'job_card_products'
]
=
this
.
jobCardProducts
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
data
[
'message'
]
=
this
.
message
;
return
data
;
}
}
class
JobCardProducts
{
String
?
id
;
String
?
partName
;
String
?
qty
;
String
?
price
;
String
?
totalPrice
;
JobCardProducts
(
{
this
.
id
,
this
.
partName
,
this
.
qty
,
this
.
price
,
this
.
totalPrice
});
JobCardProducts
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
partName
=
json
[
'part_name'
];
qty
=
json
[
'qty'
];
price
=
json
[
'price'
];
totalPrice
=
json
[
'total_price'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'part_name'
]
=
this
.
partName
;
data
[
'qty'
]
=
this
.
qty
;
data
[
'price'
]
=
this
.
price
;
data
[
'total_price'
]
=
this
.
totalPrice
;
return
data
;
}
}
lib/Models/ratingResponse.dart
0 → 100644
View file @
97403192
class
ratingResponse
{
String
?
error
;
String
?
message
;
String
?
sessionExists
;
ratingResponse
({
this
.
error
,
this
.
message
,
this
.
sessionExists
});
ratingResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
message
=
json
[
'message'
];
sessionExists
=
json
[
'session_exists'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
data
[
'message'
]
=
this
.
message
;
data
[
'session_exists'
]
=
this
.
sessionExists
;
return
data
;
}
}
lib/Notifiers/HelpAndComplaintProvider.dart
View file @
97403192
import
'dart:convert'
;
import
'dart:convert'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:gen_service/Models/HelpAndComplaintModels/complaintDetailsResponse.dart'
;
import
'package:gen_service/Models/HelpAndComplaintModels/jobCardProductsResponse.dart'
;
import
'package:gen_service/Services/api_calling.dart'
;
import
'package:gen_service/Services/api_calling.dart'
;
import
'package:provider/provider.dart'
;
import
'../Models/CommonResponse.dart'
;
import
'../Models/CommonResponse.dart'
;
import
'../Models/HelpAndComplaintModels/ComplaintListResponse.dart'
;
import
'../Models/HelpAndComplaintModels/ComplaintListResponse.dart'
;
...
@@ -12,6 +16,9 @@ class HelpAndComplaintProvider extends ChangeNotifier {
...
@@ -12,6 +16,9 @@ class HelpAndComplaintProvider extends ChangeNotifier {
String
?
_errorMessage
;
String
?
_errorMessage
;
ComplaintListResponse
?
_complaintListResponse
;
ComplaintListResponse
?
_complaintListResponse
;
complaintDetailsResponse
?
_complaintDetailsResponse
;
jobCardProductsResponse
?
_jobCardResponse
;
bool
get
isLoading
=>
_isLoading
;
bool
get
isLoading
=>
_isLoading
;
String
?
get
errorMessage
=>
_errorMessage
;
String
?
get
errorMessage
=>
_errorMessage
;
ComplaintListResponse
?
get
complaintListResponse
=>
_complaintListResponse
;
ComplaintListResponse
?
get
complaintListResponse
=>
_complaintListResponse
;
...
@@ -23,6 +30,36 @@ class HelpAndComplaintProvider extends ChangeNotifier {
...
@@ -23,6 +30,36 @@ class HelpAndComplaintProvider extends ChangeNotifier {
DropDownsListResponse
?
_dropDownsListResponse
;
DropDownsListResponse
?
_dropDownsListResponse
;
DropDownsListResponse
?
get
dropDownsListResponse
=>
_dropDownsListResponse
;
DropDownsListResponse
?
get
dropDownsListResponse
=>
_dropDownsListResponse
;
complaintDetailsResponse
?
get
compDetailsResponse
=>
_complaintDetailsResponse
;
jobCardProductsResponse
?
get
jobCardResponse
=>
_jobCardResponse
;
List
<
bool
>
_starStates
=
[
false
,
false
,
false
,
false
,
false
];
var
_rating
=
0
;
List
<
bool
>
get
starStates
=>
_starStates
;
int
get
rating
=>
_rating
;
set
rating
(
int
value
)
{
_rating
=
value
;
notifyListeners
();
}
set
starStates
(
List
<
bool
>
value
)
{
_starStates
=
value
;
notifyListeners
();
}
void
updateStarStates
(
int
rating
,
List
<
bool
>
starStates
)
{
starStates
.
fillRange
(
0
,
starStates
.
length
,
false
);
for
(
int
i
=
0
;
i
<
rating
;
i
++)
{
starStates
[
i
]
=
true
;
}
notifyListeners
();
}
///----------------------------------------------
///----------------------------------------------
/// Fetch Complaints List
/// Fetch Complaints List
...
@@ -140,6 +177,80 @@ class HelpAndComplaintProvider extends ChangeNotifier {
...
@@ -140,6 +177,80 @@ class HelpAndComplaintProvider extends ChangeNotifier {
Future
<
void
>
fetchComplaintDetailsAPI
(
String
accId
,
String
sessionId
,
complaintId
)
async
{
_isLoading
=
true
;
_errorMessage
=
null
;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
complaintDetailsAPI
(
accId
,
sessionId
,
complaintId
);
if
(
response
!=
null
)
{
if
(
response
.
error
==
"0"
)
{
_complaintDetailsResponse
=
response
;
updateStarStates
(
int
.
parse
(
response
.
serviceDetails
?.
firstOrNull
?.
rating
.
toString
()??
"0"
),
_starStates
);
}
else
{
_errorMessage
=
response
.
message
??
"Something went wrong!"
;
}
}
else
{
_errorMessage
=
"No response from server."
;
}
}
catch
(
e
)
{
_errorMessage
=
"Failed to fetch dashboard:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
Future
<
void
>
updateRatingForTechnician
(
String
accId
,
String
sessionId
,
complaintId
,
rating
)
async
{
// _errorMessage = null;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
updateTechRatingAPI
(
accId
,
sessionId
,
complaintId
,
rating
);
if
(
response
!=
null
)
{
if
(
response
.
error
==
"0"
)
{
fetchComplaintDetailsAPI
(
accId
,
sessionId
,
complaintId
);
}
else
{
// _errorMessage = response.message ?? "Something went wrong!";
}
}
else
{
// _errorMessage = "No response from server.";
}
}
catch
(
e
)
{
_errorMessage
=
"Failed to fetch dashboard:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
Future
<
void
>
fetchJobCardProductDetails
(
String
accId
,
String
sessionId
,
jobCardId
)
async
{
_errorMessage
=
null
;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
jobCardProductDetailsAPI
(
accId
,
sessionId
,
jobCardId
);
if
(
response
!=
null
)
{
if
(
response
.
error
==
"0"
)
{
_jobCardResponse
=
response
;
}
else
{
_errorMessage
=
response
.
message
??
"Something went wrong!"
;
}
}
else
{
_errorMessage
=
"No response from server."
;
}
}
catch
(
e
)
{
_errorMessage
=
"Failed to fetch dashboard:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
///----------------------------------------------
///----------------------------------------------
/// Private Helpers
/// Private Helpers
...
...
lib/Notifiers/mapProvider.dart
0 → 100644
View file @
97403192
import
'dart:async'
;
import
'dart:io'
;
import
'dart:ui'
as
ui
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:gen_service/Models/GetInTouchListResponse.dart'
;
import
'package:geolocator/geolocator.dart'
;
import
'package:google_maps_flutter/google_maps_flutter.dart'
;
import
'package:geocoding/geocoding.dart'
as
geocoding
;
import
'package:location/location.dart'
as
Location
;
import
'package:permission_handler/permission_handler.dart'
;
import
'package:provider/provider.dart'
;
import
'../Services/api_calling.dart'
;
class
MapProvider
extends
ChangeNotifier
{
GetInTouchListResponse
?
_response
;
List
<
GetInTouchList
>
_locationsList
=
[];
final
String
_googleApikey
=
"AIzaSyBGzvgMMKwPBAANTwaoRsAnrCpiWCj8wVs"
;
GoogleMapController
?
_mapController
;
CameraPosition
?
_cameraPosition
;
final
LatLng
_startLocation
=
const
LatLng
(
17.439112226708446
,
78.43292499146135
,
);
String
_latlongs
=
""
;
List
<
Marker
>
_markers
=
[];
List
<
String
>
_addresses
=
[];
Location
.
LocationData
?
_currentLocation
;
bool
_isLocationEnabled
=
false
;
bool
_hasLocationPermission
=
false
;
Timer
?
_timer
;
bool
_isLoading
=
true
;
Timer
?
_debounceTimer
;
LatLng
?
_mapCenter
;
GetInTouchListResponse
?
get
response
=>
_response
;
List
<
GetInTouchList
>
get
locationsList
=>
_locationsList
;
String
get
googleAPIKey
=>
_googleApikey
;
GoogleMapController
?
get
mapController
=>
_mapController
;
CameraPosition
?
get
cameraPosition
=>
_cameraPosition
;
LatLng
get
startLocation
=>
_startLocation
;
String
get
latlongs
=>
_latlongs
;
List
<
Marker
>
get
markers
=>
_markers
;
List
<
String
>
get
addresses
=>
_addresses
;
Location
.
LocationData
?
get
currentLocation
=>
_currentLocation
;
bool
get
isLocationEnabled
=>
_isLocationEnabled
;
bool
get
hasLocationPermission
=>
_hasLocationPermission
;
bool
get
isLoading
=>
_isLoading
;
Timer
?
get
timer
=>
_timer
;
set
markers
(
List
<
Marker
>
value
)
{
_markers
=
value
;
if
(
value
.
isNotEmpty
)
{
_isLoading
=
false
;
// Mark screen as loaded when markers are added
}
notifyListeners
();
}
set
mapController
(
GoogleMapController
?
value
)
{
_mapController
=
value
;
notifyListeners
();
}
set
mapCenter
(
LatLng
?
value
)
{
_mapCenter
=
value
;
_latlongs
=
value
!=
null
?
'
${value.latitude}
,
${value.longitude}
'
:
''
;
notifyListeners
();
}
set
isLoading
(
bool
value
)
{
_isLoading
=
value
;
notifyListeners
();
}
void
resetAll
()
{
_markers
=
[];
_addresses
=
[];
_mapCenter
=
null
;
_isLoading
=
true
;
notifyListeners
();
}
Future
<
void
>
getLocationPermission
(
BuildContext
context
,
empId
,
session
,)
async
{
_isLocationEnabled
=
await
Geolocator
.
isLocationServiceEnabled
();
LocationPermission
permission
=
await
Geolocator
.
checkPermission
();
_hasLocationPermission
=
permission
==
LocationPermission
.
always
||
permission
==
LocationPermission
.
whileInUse
;
final
Location
.
Location
location
=
Location
.
Location
();
bool
serviceEnabled
;
Location
.
PermissionStatus
permissionGranted
;
serviceEnabled
=
await
location
.
serviceEnabled
();
if
(!
serviceEnabled
)
{
serviceEnabled
=
await
location
.
requestService
();
if
(!
serviceEnabled
)
{
_isLoading
=
false
;
return
;
}
}
permissionGranted
=
await
location
.
hasPermission
();
if
(
permissionGranted
==
Location
.
PermissionStatus
.
denied
)
{
permissionGranted
=
await
location
.
requestPermission
();
if
(
permissionGranted
!=
Location
.
PermissionStatus
.
granted
)
{
// toast(context, 'Location permission denied.');
_isLoading
=
false
;
return
;
}
}
final
Location
.
LocationData
locData
=
await
location
.
getLocation
();
_currentLocation
=
locData
;
if
(
_currentLocation
!=
null
&&
_mapCenter
==
null
)
{
_mapCenter
=
LatLng
(
_currentLocation
!.
latitude
!,
_currentLocation
!.
longitude
!,
);
_latlongs
=
'
${_currentLocation!.latitude}
,
${_currentLocation!.longitude}
'
;
_mapController
?.
animateCamera
(
CameraUpdate
.
newLatLng
(
_mapCenter
!));
await
nearbyServiceLocations
(
context
,
empId
,
session
,);
}
notifyListeners
();
}
void
onCameraMove
(
BuildContext
context
,
CameraPosition
position
,
empId
,
session
)
{
_timer
?.
cancel
();
_mapCenter
=
position
.
target
;
_latlongs
=
'
${_mapCenter!.latitude}
,
${_mapCenter!.longitude}
'
;
_timer
=
Timer
(
Duration
(
seconds:
1
),
()
{
nearbyServiceLocations
(
context
,
empId
,
session
,);
});
notifyListeners
();
}
void
debounce
(
VoidCallback
callback
,
Duration
duration
)
{
_debounceTimer
?.
cancel
();
_debounceTimer
=
Timer
(
duration
,
callback
);
}
Future
<
void
>
nearbyServiceLocations
(
BuildContext
context
,
empId
,
session
,
)
async
{
try
{
final
data
=
await
ApiCalling
.
fetchGetInTouchListApi
(
empId
,
session
,
);
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
_isLoading
=
false
;
_response
=
data
;
_locationsList
=
data
.
getInTouchList
??
[];
await
updateMarkersFromApiResponse
(
context
,
data
.
getInTouchList
??[]);
if
(
_locationsList
.
isEmpty
)
{
// toast(context, 'No leads found within the selected radius.');
}
}
else
{
// toast(context, data.message ?? 'Failed to load leads.');
_isLoading
=
false
;
notifyListeners
();
}
}
else
{
// toast(context, "Something went wrong, please try again.");
_isLoading
=
false
;
notifyListeners
();
}
}
on
Exception
catch
(
e
,
s
)
{
print
(
"nearbyServiceLocations error:
$e
, stack:
$s
"
);
// toast(context, 'An error occurred while loading leads.');
_isLoading
=
false
;
notifyListeners
();
}
}
Future
<
void
>
updateMarkersFromApiResponse
(
BuildContext
context
,
List
<
GetInTouchList
>
locationsList
,
)
async
{
print
(
"markers updating"
);
_markers
=
await
createMarkersFromApiResponse
(
context
,
locationsList
);
_addresses
.
clear
();
await
Future
.
forEach
(
locationsList
,
(
store
)
async
{
String
address
=
await
_getAddressFromLatLng
(
store
.
loc
);
_addresses
.
add
(
address
);
print
(
_addresses
);
});
notifyListeners
();
}
Future
<
List
<
Marker
>>
createMarkersFromApiResponse
(
BuildContext
context
,
List
<
GetInTouchList
>
locationsList
,
)
async
{
List
<
Marker
>
markers
=
[];
ByteData
data
=
await
rootBundle
.
load
(
"assets/images/maps_ic.png"
);
Uint8List
bytes
=
data
.
buffer
.
asUint8List
();
await
Future
.
forEach
(
locationsList
,
(
leads
)
async
{
if
(
leads
.
loc
==
null
||
leads
.
id
==
null
||
leads
.
branchName
==
null
)
{
print
(
'Skipping invalid lead: id=
${leads.id}
, name=
${leads.branchName}
, loc=
${leads.loc}
'
,
);
return
;
}
ui
.
Codec
codec
=
await
ui
.
instantiateImageCodec
(
bytes
);
ui
.
FrameInfo
fi
=
await
codec
.
getNextFrame
();
Uint8List
resizedBytes
=
(
await
fi
.
image
.
toByteData
(
format:
ui
.
ImageByteFormat
.
png
,
))!.
buffer
.
asUint8List
();
markers
.
add
(
Marker
(
markerId:
MarkerId
(
leads
.
id
.
toString
()),
position:
_parseLatLng
(
leads
.
loc
),
icon:
BitmapDescriptor
.
fromBytes
(
resizedBytes
),
infoWindow:
InfoWindow
(
title:
leads
.
branchName
??
'Unknown Lead'
,
snippet:
leads
.
address
??
'No address available'
,
anchor:
const
Offset
(
0.5
,
1.0
),
),
zIndex:
100
,
onTap:
()
{
_mapController
?.
showMarkerInfoWindow
(
MarkerId
(
leads
.
id
.
toString
()));
print
(
'Marker tapped: id=
${leads.id}
, name=
${leads.branchName}
'
);
},
),
);
});
return
markers
;
}
LatLng
_parseLatLng
(
String
?
location
)
{
if
(
location
!=
null
)
{
List
<
String
>
parts
=
location
.
split
(
','
);
if
(
parts
.
length
==
2
)
{
double
lat
=
double
.
tryParse
(
parts
[
0
])
??
0.0
;
double
lng
=
double
.
tryParse
(
parts
[
1
])
??
0.0
;
if
(
lat
!=
0.0
&&
lng
!=
0.0
)
{
return
LatLng
(
lat
,
lng
);
}
}
}
print
(
'Invalid location string:
$location
'
);
return
const
LatLng
(
0.0
,
0.0
);
}
Future
<
String
>
_getAddressFromLatLng
(
String
?
location
)
async
{
if
(
location
!=
null
)
{
List
<
String
>
parts
=
location
.
split
(
','
);
if
(
parts
.
length
==
2
)
{
double
lat
=
double
.
tryParse
(
parts
[
0
])
??
0.0
;
double
lng
=
double
.
tryParse
(
parts
[
1
])
??
0.0
;
if
(
lat
!=
0.0
&&
lng
!=
0.0
)
{
try
{
List
<
geocoding
.
Placemark
>
placemarks
=
await
geocoding
.
placemarkFromCoordinates
(
lat
,
lng
);
if
(
placemarks
.
isNotEmpty
)
{
final
placemark
=
placemarks
.
first
;
String
address
=
'
${placemark.street ?? ''}
, '
'
${placemark.thoroughfare ?? ''}
'
'
${placemark.subLocality ?? ''}
, '
'
${placemark.locality ?? ''}
, '
'
${placemark.administrativeArea ?? ''}
, '
'
${placemark.subAdministrativeArea ?? ''}
'
'
${placemark.postalCode ?? ''}
, '
'
${placemark.country ?? ''}
'
;
return
address
.
trim
();
}
}
catch
(
e
)
{
print
(
'Geocoding error for location
$location
:
$e
'
);
}
}
}
}
return
"Address not found"
;
}
}
lib/Notifiers/serviceAndJobCardListProvier.dart
0 → 100644
View file @
97403192
import
'dart:convert'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:gen_service/Models/HelpAndComplaintModels/allJobCardListResponse.dart'
;
import
'package:gen_service/Models/HelpAndComplaintModels/allServiceListResponse.dart'
;
import
'package:gen_service/Services/api_calling.dart'
;
class
ServiceAndJobCardListProvider
extends
ChangeNotifier
{
bool
_isLoading
=
false
;
String
?
_errorMessage
;
allJobCardListResponse
?
_allJobCardResponse
;
allServiceListResponse
?
_allServiceResponse
;
bool
get
isLoading
=>
_isLoading
;
String
?
get
errorMessage
=>
_errorMessage
;
allJobCardListResponse
?
get
allJobCardResponse
=>
_allJobCardResponse
;
allServiceListResponse
?
get
allServiceResponse
=>
_allServiceResponse
;
Map
<
String
,
int
>
_localRatings
=
{};
Map
<
String
,
List
<
bool
>>
_starStates
=
{};
int
getRating
(
String
serviceId
)
=>
_localRatings
[
serviceId
]
??
0
;
List
<
bool
>
getStarStates
(
String
serviceId
)
{
return
_starStates
.
putIfAbsent
(
serviceId
,
()
=>
List
.
filled
(
5
,
false
));
}
void
setRating
(
String
serviceId
,
int
rating
,
{
bool
notify
=
true
})
{
_localRatings
[
serviceId
]
=
rating
;
final
stars
=
getStarStates
(
serviceId
);
for
(
int
i
=
0
;
i
<
5
;
i
++)
{
stars
[
i
]
=
i
<
rating
;
}
if
(
notify
)
notifyListeners
();
}
void
initRatingsFromData
(
List
<
AllServiceList
>
services
)
{
for
(
var
service
in
services
)
{
final
id
=
service
.
id
?.
toString
()
??
service
.
id
.
toString
();
final
backendRating
=
int
.
parse
(
service
.
customerServiceRating
.
toString
())
??
0
;
setRating
(
id
,
backendRating
,
notify:
false
);
}
notifyListeners
();
}
Future
<
void
>
fetchAllJobCardsListAPI
(
String
accId
,
String
sessionId
,
complaintId
)
async
{
_isLoading
=
true
;
_errorMessage
=
null
;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
jobCardsListAPI
(
accId
,
sessionId
,
complaintId
);
if
(
response
!=
null
)
{
if
(
response
.
error
==
"0"
)
{
_allJobCardResponse
=
response
;
}
else
{
_errorMessage
=
response
.
message
??
"Something went wrong!"
;
}
}
else
{
_errorMessage
=
"No response from server."
;
}
}
catch
(
e
)
{
_errorMessage
=
"Failed to fetch dashboard:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
Future
<
void
>
fetchServiceDetailsAPI
(
String
accId
,
String
sessionId
,
complaintId
)
async
{
_isLoading
=
true
;
_errorMessage
=
null
;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
serviceListAPI
(
accId
,
sessionId
,
complaintId
);
if
(
response
!=
null
)
{
if
(
response
.
error
==
"0"
)
{
_allServiceResponse
=
response
;
initRatingsFromData
(
response
.
allServiceList
??[]);
}
else
{
_errorMessage
=
response
.
message
??
"Something went wrong!"
;
}
}
else
{
_errorMessage
=
"No response from server."
;
}
}
catch
(
e
)
{
_errorMessage
=
"Failed to fetch dashboard:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
Future
<
void
>
updateRatingForTechnician
(
String
accId
,
String
sessionId
,
complaintId
,
rating
)
async
{
// _errorMessage = null;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
updateTechRatingAPI
(
accId
,
sessionId
,
complaintId
,
rating
);
if
(
response
!=
null
)
{
if
(
response
.
error
==
"0"
)
{
fetchServiceDetailsAPI
(
accId
,
sessionId
,
complaintId
);
setRating
(
complaintId
,
rating
);
}
else
{
// _errorMessage = response.message ?? "Something went wrong!";
}
}
else
{
// _errorMessage = "No response from server.";
}
}
catch
(
e
)
{
_errorMessage
=
"Failed to fetch dashboard:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
void
_setLoading
(
bool
value
)
{
_isLoading
=
value
;
notifyListeners
();
}
void
clearData
()
{
_allJobCardResponse
=
null
;
_allServiceResponse
=
null
;
_errorMessage
=
null
;
notifyListeners
();
}
}
lib/Screens/AuthScreen/temp.dart
deleted
100644 → 0
View file @
5a62c920
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
class
LoginScreen
extends
StatefulWidget
{
const
LoginScreen
({
super
.
key
});
@override
State
<
LoginScreen
>
createState
()
=>
_LoginScreenState
();
}
class
_LoginScreenState
extends
State
<
LoginScreen
>
{
final
TextEditingController
_mobileController
=
TextEditingController
();
final
_formKey
=
GlobalKey
<
FormState
>();
@override
Widget
build
(
BuildContext
context
)
{
final
size
=
MediaQuery
.
of
(
context
).
size
;
return
Scaffold
(
resizeToAvoidBottomInset:
true
,
backgroundColor:
Colors
.
blue
,
body:
Stack
(
children:
[
/// 🔹 Background image
Container
(
width:
double
.
infinity
,
height:
double
.
infinity
,
decoration:
const
BoxDecoration
(
image:
DecorationImage
(
image:
AssetImage
(
"assets/images/background_png.png"
),
fit:
BoxFit
.
cover
,
),
),
),
/// 🔹 Main content (scrollable & keyboard-safe)
SafeArea
(
child:
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
return
SingleChildScrollView
(
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
// moves up with keyboard
),
child:
ConstrainedBox
(
constraints:
BoxConstraints
(
minHeight:
constraints
.
maxHeight
,
),
child:
IntrinsicHeight
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
SizedBox
(
height:
80
),
/// 🔹 Logo
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
SizedBox
(
width:
20
,),
SvgPicture
.
asset
(
"assets/svg/genesis_logo_2io.svg"
,
height:
48
,
color:
Colors
.
white
,
),
]
),
const
SizedBox
(
height:
12
),
const
Spacer
(),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
26
,
vertical:
12
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"Login to"
,
style:
TextStyle
(
fontSize:
48
,
fontFamily:
"PoppinsLight"
,
fontWeight:
FontWeight
.
w100
,
color:
Colors
.
white
,
),
),
Text
(
"continue"
,
style:
TextStyle
(
fontSize:
48
,
fontWeight:
FontWeight
.
w500
,
color:
Colors
.
white
,
),
),
],
),
),
],
),
const
SizedBox
(
height:
20
),
/// 🔹 Bottom Sheet style area
Container
(
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
20
,
vertical:
30
),
decoration:
const
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
24
),
topRight:
Radius
.
circular
(
24
),
),
),
child:
Form
(
key:
_formKey
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
const
Text
(
"Enter Registered Mobile No."
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
black54
,
fontWeight:
FontWeight
.
w500
,
),
),
const
SizedBox
(
height:
10
),
/// 🔹 Mobile Field
TextFormField
(
controller:
_mobileController
,
keyboardType:
TextInputType
.
phone
,
maxLength:
10
,
decoration:
InputDecoration
(
hintText:
"Enter Mobile No."
,
counterText:
""
,
contentPadding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
14
),
border:
OutlineInputBorder
(
borderRadius:
BorderRadius
.
circular
(
50
),
borderSide:
BorderSide
(
color:
Colors
.
grey
.
shade300
),
),
focusedBorder:
OutlineInputBorder
(
borderRadius:
BorderRadius
.
circular
(
50
),
borderSide:
const
BorderSide
(
color:
Colors
.
blue
,
width:
1.2
),
),
filled:
true
,
fillColor:
Colors
.
grey
.
shade100
,
),
validator:
(
value
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
return
"Please enter mobile number"
;
}
else
if
(
value
.
length
!=
10
)
{
return
"Enter valid 10-digit number"
;
}
return
null
;
},
),
const
SizedBox
(
height:
20
),
/// 🔹 Continue Button (Always visible)
SizedBox
(
width:
double
.
infinity
,
height:
50
,
child:
ElevatedButton
(
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF0086F1
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
),
onPressed:
()
{
if
(
_formKey
.
currentState
!.
validate
())
{
FocusScope
.
of
(
context
).
unfocus
();
// TODO: Add API call here
}
},
child:
const
Text
(
"Continue"
,
style:
TextStyle
(
fontSize:
16
,
color:
Colors
.
white
,
fontWeight:
FontWeight
.
w600
,
),
),
),
),
],
),
),
),
],
),
),
),
);
},
),
),
],
),
);
}
}
lib/Screens/HelpAndComplaintScreens/ComplaintDetailsScreen.dart
0 → 100644
View file @
97403192
import
'dart:io'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:gen_service/Notifiers/HelpAndComplaintProvider.dart'
;
import
'package:gen_service/Screens/HelpAndComplaintScreens/jobcardListScreen.dart'
;
import
'package:gen_service/Screens/HelpAndComplaintScreens/serviceListScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'package:razorpay_flutter/razorpay_flutter.dart'
;
import
'../../Notifiers/PayAmountProvider.dart'
;
import
'../../Utility/AppColors.dart'
;
import
'../../Utility/CustomSnackbar.dart'
;
import
'../../Utility/SharedpreferencesService.dart'
;
class
ComplaintDetailsScreen
extends
StatefulWidget
{
final
accId
;
final
sessionId
;
final
complaintId
;
const
ComplaintDetailsScreen
({
super
.
key
,
required
this
.
accId
,
required
this
.
sessionId
,
required
this
.
complaintId
,
});
@override
State
<
ComplaintDetailsScreen
>
createState
()
=>
_ComplaintDetailsScreenState
();
}
class
_ComplaintDetailsScreenState
extends
State
<
ComplaintDetailsScreen
>
{
late
Razorpay
_razorpay
;
bool
?
isSuccess
;
var
paymentMethod
=
""
;
var
User_contact
=
"0"
;
bool
bottomSheetButtonClicked
=
false
;
final
prefs
=
SharedPreferencesService
.
instance
;
@override
void
initState
()
{
// TODO: implement initState
super
.
initState
();
_razorpay
=
Razorpay
();
WidgetsBinding
.
instance
.
addPostFrameCallback
((
timeStamp
)
{
final
provider
=
Provider
.
of
<
HelpAndComplaintProvider
>(
context
,
listen:
false
,
);
provider
.
fetchComplaintDetailsAPI
(
widget
.
accId
,
widget
.
sessionId
,
widget
.
complaintId
,
);
});
}
//_________________________________________________________
void
_handlePaymentSuccess
(
PaymentSuccessResponse
response
)
{
setState
(()
async
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
getPaymentStatus
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
razorpayOrderId:
response
.
orderId
.
toString
(),
);
final
data
=
provider
.
statusResponse
;
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
// total: "${data?.amount}",
// date: "${data?.date}",
// payMode: "UPI",
// status: "Success",
// )),
// );
_razorpay
.
clear
();
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
data
?.
message
??
"Payment Success!"
,
);
// buttonLoading = false;
});
}
void
_handlePaymentError
(
PaymentFailureResponse
response
)
{
setState
(()
async
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
});
_razorpay
.
clear
();
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
}
void
_handleExternalWallet
(
ExternalWalletResponse
response
)
{
_razorpay
.
clear
();
}
Future
<
void
>
payAmountFunction
(
String
amount
)
async
{
try
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
payAmount
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
amount:
amount
,
refType:
"Gen Service"
,
refId:
"1"
,
);
final
data
=
provider
.
payResponse
;
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
openCheckout
(
data
.
orderId
,
data
.
razorKey
!);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"
${data.message}
"
,
);
debugPrint
(
"❌ Could not Complete Payment:
${data.message}
"
);
}
}
else
{
debugPrint
(
"❌ No response received from PayAmount API"
);
}
}
catch
(
e
)
{
debugPrint
(
"❌ 'Error occurred:
$e
'"
);
}
}
//razorpay payments__________________________________________________________
void
openCheckout
(
razorPayOrderId
,
String
razorpayKey
)
async
{
final
String
?
mobNumber
=
await
prefs
.
getString
(
"mob_number"
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_SUCCESS
,
_handlePaymentSuccess
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_ERROR
,
_handlePaymentError
);
_razorpay
.
on
(
Razorpay
.
EVENT_EXTERNAL_WALLET
,
_handleExternalWallet
);
// _buildCheckWidget();
Map
<
String
,
dynamic
>
options
=
{
'key'
:
razorpayKey
,
'amount'
:
int
.
parse
(
"
${((0) * 100).round()}
"
),
'name'
:
'Gen Service'
,
'order_id'
:
razorPayOrderId
,
'description'
:
"Bill"
,
'currency'
:
'INR'
,
'method'
:
'upi'
,
'prefill'
:
{
'contact'
:
mobNumber
,
'email'
:
''
},
};
// print(options);
try
{
_razorpay
.
open
(
options
);
}
catch
(
e
,
s
)
{
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint
(
e
.
toString
());
}
}
void
verifyPayment
(
String
orderId
)
{
isSuccess
=
true
;
setState
(()
{
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
_razorpay
.
clear
();
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
@override
Widget
build
(
BuildContext
context
)
{
return
Consumer
<
HelpAndComplaintProvider
>(
builder:
(
context
,
provider
,
child
)
{
final
isLoading
=
provider
.
isLoading
;
final
error
=
provider
.
errorMessage
;
final
data
=
provider
.
compDetailsResponse
;
final
complaintData
=
data
?.
complaintDetails
?.
firstOrNull
;
final
jobCardsData
=
data
?.
jobCardList
?.
firstOrNull
;
final
serviceData
=
data
?.
serviceDetails
?.
firstOrNull
;
List
<
String
>
headings
=
[
"Generator"
,
"Description"
,
"Complaint Note"
];
List
<
String
>
subHeadings
=
[
complaintData
?.
productName
??
"-"
,
complaintData
?.
complaintDesc
??
"-"
,
complaintData
?.
complaintNote
??
"-"
,
];
List
<
String
>
serviceHeadings
=
[
"Date"
,
"In/Out Time"
,
"Running Hrs."
,
"FSR File"
,
"FSR Number"
,
"Feedback"
,
];
List
<
String
>
serviceSubHeadings
=
[
serviceData
?.
date
??
"-"
,
serviceData
?.
inOrOutTime
??
"-"
,
serviceData
?.
runningHrs
??
"-"
,
serviceData
?.
fsrExt
??
"-"
,
serviceData
?.
fsrNo
??
"-"
,
serviceData
?.
feedback
??
"-"
,
];
if
(
isLoading
)
{
return
const
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
child:
CircularProgressIndicator
(
color:
AppColors
.
buttonColor
),
),
);
}
if
(
error
!=
null
)
{
return
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
24.0
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
// Error Icon
Container
(
width:
120
,
height:
120
,
decoration:
BoxDecoration
(
color:
Colors
.
red
.
withOpacity
(
0.1
),
shape:
BoxShape
.
circle
,
),
child:
const
Icon
(
Icons
.
error_outline_rounded
,
size:
60
,
color:
Colors
.
red
,
),
),
const
SizedBox
(
height:
24
),
// Error Title
const
Text
(
"Oops! Something went wrong"
,
style:
TextStyle
(
fontSize:
20
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
12
),
// Error Message
Text
(
error
,
textAlign:
TextAlign
.
center
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
height:
1.4
,
),
),
const
SizedBox
(
height:
32
),
// Retry Button
ElevatedButton
.
icon
(
onPressed:
()
async
{
// Show loading state
setState
(()
{});
await
Future
.
delayed
(
const
Duration
(
milliseconds:
300
));
// Retry fetching data
final
provider
=
Provider
.
of
<
HelpAndComplaintProvider
>(
context
,
listen:
false
,
);
await
provider
.
fetchComplaintDetailsAPI
(
widget
.
accId
,
widget
.
sessionId
,
widget
.
complaintId
,
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
24
,
vertical:
12
,
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
25
),
),
elevation:
2
,
),
icon:
const
Icon
(
Icons
.
refresh_rounded
,
size:
20
),
label:
const
Text
(
"Try Again"
,
style:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
),
const
SizedBox
(
height:
16
),
// Alternative Action
TextButton
(
onPressed:
()
{
// Go back or navigate to home
Navigator
.
maybePop
(
context
);
},
child:
const
Text
(
"Go Back"
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
),
),
),
],
),
),
),
);
}
if
(
data
==
null
)
{
return
SafeArea
(
maintainBottomViewPadding:
true
,
top:
false
,
bottom:
Platform
.
isIOS
?
false
:
true
,
child:
const
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
child:
Text
(
"No data found."
)),
),
);
}
return
SafeArea
(
maintainBottomViewPadding:
true
,
top:
false
,
bottom:
Platform
.
isIOS
?
false
:
true
,
child:
RefreshIndicator
.
adaptive
(
color:
AppColors
.
amountText
,
onRefresh:
()
async
{
await
Future
.
delayed
(
const
Duration
(
milliseconds:
600
));
},
child:
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
CustomScrollView
(
slivers:
[
SliverAppBar
(
stretch:
true
,
pinned:
true
,
expandedHeight:
175
,
backgroundColor:
AppColors
.
backgroundRegular
,
elevation:
0
,
leading:
Container
(),
toolbarHeight:
0
,
collapsedHeight:
0
,
flexibleSpace:
FlexibleSpaceBar
(
stretchModes:
const
[
StretchMode
.
zoomBackground
],
background:
Container
(
decoration:
BoxDecoration
(
gradient:
AppColors
.
balanceBarGradientA
,
),
child:
SafeArea
(
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
20
,
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
0
,
vertical:
20
,
),
child:
SizedBox
(
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
InkResponse
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
Navigator
.
pop
(
context
,
true
);
},
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back.svg"
,
height:
25
,
),
),
SizedBox
(
width:
10
),
Expanded
(
flex:
4
,
child:
InkResponse
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
Navigator
.
pop
(
context
,
true
);
},
child:
Text
(
"Complaint Details"
,
overflow:
TextOverflow
.
ellipsis
,
maxLines:
1
,
style:
TextStyle
(
fontSize:
16
,
color:
Colors
.
white
,
height:
1.1
,
),
),
),
),
],
),
),
),
const
SizedBox
(
height:
20
),
Row
(
children:
[
Expanded
(
flex:
5
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
RichText
(
text:
TextSpan
(
style:
const
TextStyle
(
fontFamily:
'Poppins'
,
color:
Color
(
0xFF48F3FF
),
fontSize:
12
,
),
children:
[
TextSpan
(
text:
"#
${complaintData?.id!}
"
,
),
TextSpan
(
text:
(
complaintData
?.
complaintName
??
""
).
isNotEmpty
?
" |
${complaintData?.complaintName!}
"
:
""
,
),
],
),
),
Text
(
"
${complaintData?.registredDate??""}
"
,
maxLines:
2
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
14
,
),
),
],
),
),
Expanded
(
flex:
2
,
child:
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
15
,
vertical:
7
,
),
decoration:
BoxDecoration
(
color:
complaintData
?.
openStatus
==
"Open"
?
AppColors
.
successBG
:
AppColors
.
yellowBG
,
borderRadius:
BorderRadius
.
circular
(
10
,
),
),
child:
Center
(
child:
Text
(
"
${complaintData?.openStatus}
"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
color:
complaintData
?.
openStatus
==
"Open"
?
AppColors
.
success
:
AppColors
.
normalText
,
),
),
),
),
),
],
),
],
),
),
),
),
),
),
SliverToBoxAdapter
(
child:
Container
(
color:
Color
(
0xFF4076FF
),
child:
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
8
,
),
decoration:
const
BoxDecoration
(
color:
AppColors
.
backgroundRegular
,
borderRadius:
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
30
),
topRight:
Radius
.
circular
(
30
),
),
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
if
(
data
.
jobCardList
!.
isNotEmpty
)
...[
sectionHeading
(
"Job Cards"
),
Container
(
margin:
const
EdgeInsets
.
all
(
5
),
padding:
const
EdgeInsets
.
all
(
14
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xFFFFFFFF
),
borderRadius:
BorderRadius
.
circular
(
16
),
border:
Border
.
all
(
width:
1.1
,
color:
AppColors
.
buttonColor
,
),
),
child:
Column
(
children:
[
Row
(
children:
[
Expanded
(
flex:
5
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"
${jobCardsData?.date}
"
,
maxLines:
2
,
style:
const
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
SizedBox
(
height:
4
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
Text
(
"Job Card"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
InkResponse
(
onTap:
bottomSheetButtonClicked
?
null
:
()
{
HapticFeedback
.
mediumImpact
();
setState
(()
{
bottomSheetButtonClicked
=
true
;
});
provider
.
fetchJobCardProductDetails
(
widget
.
accId
,
widget
.
sessionId
,
jobCardsData
!
.
id
,
);
Future
.
delayed
(
Duration
(
milliseconds:
600
,
),
()
{
_showJobCardProductSheet
(
context
,
);
},
);
},
child:
Text
(
" ⓘ View Details"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
buttonColor
,
),
),
),
],
),
],
),
),
Expanded
(
flex:
2
,
child:
Text
(
"₹
${jobCardsData?.totalPrice}
"
,
textAlign:
TextAlign
.
right
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
nearDarkText
,
),
),
),
],
),
Divider
(
thickness:
0.3
,
color:
AppColors
.
subtitleText
,
),
InkResponse
(
onTap:
()=>
_openPaymentSheet
(
context
,
jobCardsData
!.
totalPrice
.
toString
()),
child:
Container
(
padding:
EdgeInsets
.
symmetric
(
vertical:
16
,
horizontal:
10
,
),
decoration:
BoxDecoration
(
color:
AppColors
.
buttonColor
,
borderRadius:
BorderRadius
.
circular
(
25
,
),
),
child:
Center
(
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
14
,
fontWeight:
FontWeight
.
w600
,
),
),
),
),
),
],
),
),
],
if
(
data
.
complaintDetails
!.
isNotEmpty
)
...[
sectionHeading
(
"Complaint Details"
),
Container
(
margin:
const
EdgeInsets
.
all
(
5
),
padding:
const
EdgeInsets
.
all
(
14
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xFFFFFFFF
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Column
(
children:
[
...
List
.
generate
(
headings
.
length
,
(
i
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
3
,
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Expanded
(
child:
Text
(
headings
[
i
]
??
"-"
,
style:
const
TextStyle
(
fontSize:
14
,
color:
AppColors
.
subtitleText
,
),
),
),
Expanded
(
child:
Text
(
subHeadings
[
i
].
isEmpty
?
"-"
:
subHeadings
[
i
]
??
"-"
,
maxLines:
3
,
overflow:
TextOverflow
.
ellipsis
,
textAlign:
TextAlign
.
end
,
style:
const
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
),
],
),
);
}),
],
),
),
],
if
(
data
.
serviceDetails
!.
isNotEmpty
)
...[
sectionHeading
(
"Service Details"
),
Container
(
margin:
const
EdgeInsets
.
all
(
5
),
padding:
const
EdgeInsets
.
all
(
14
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xFFFFFFFF
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Column
(
children:
[
...
List
.
generate
(
serviceHeadings
.
length
,
(
i
,
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
3
,
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Expanded
(
child:
Text
(
serviceHeadings
[
i
]
??
"-"
,
style:
const
TextStyle
(
fontSize:
14
,
color:
AppColors
.
subtitleText
,
),
),
),
Expanded
(
child:
Text
(
serviceSubHeadings
[
i
].
isEmpty
?
"-"
:
serviceSubHeadings
[
i
]
??
"-"
,
maxLines:
3
,
overflow:
TextOverflow
.
ellipsis
,
textAlign:
TextAlign
.
end
,
style:
const
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
),
],
),
);
}),
SizedBox
(
height:
5
,
),
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
0
,
vertical:
15
,
),
decoration:
BoxDecoration
(
color:
Color
(
0xFFE8F6FF
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Expanded
(
flex:
1
,
child:
CircleAvatar
(
backgroundImage:
serviceData
?.
profileImg
==
"https://erp.gengroup.in/"
?
AssetImage
(
"assets/images/user_img.png"
,
)
:
NetworkImage
(
"
${serviceData?.profileImg}
"
,
),
),
),
Expanded
(
flex:
3
,
child:
SizedBox
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"
${serviceData?.empName}
"
,
maxLines:
2
,
overflow:
TextOverflow
.
ellipsis
,
style:
TextStyle
(
color:
AppColors
.
nearDarkText
,
fontSize:
14
,
),
),
Text
(
"
${serviceData?.techRoleName}
"
,
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
style:
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
],
),
),
),
Expanded
(
flex:
3
,
child:
SizedBox
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
List
.
generate
(
provider
.
starStates
.
length
,
(
index
)
=>
InkWell
(
onTap:
()
{
provider
.
rating
=
index
+
1
;
for
(
int
i
=
0
;
i
<
provider
.
starStates
.
length
;
i
++)
{
provider
.
starStates
[
i
]
=
i
<=
index
;
}
provider
.
notifyListeners
();
provider
.
updateRatingForTechnician
(
widget
.
accId
,
widget
.
sessionId
,
widget
.
complaintId
,
provider
.
rating
);
},
child:
Row
(
children:
[
Icon
(
Icons
.
star_rate_rounded
,
color:
provider
.
starStates
[
index
]
?
Color
(
0xffFFB703
)
:
Color
(
0xffCECECE
),
size:
25
,
),
],
),
),
),
),
Text
(
"Your Rating"
,
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
style:
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
],
),
),
),
],
),
),
],
),
),
],
],
),
),
),
),
],
),
),
),
);
},
);
}
Widget
sectionHeading
(
text
)
{
return
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
text
,
style:
TextStyle
(
color:
AppColors
.
nearDarkText
,
fontSize:
14
),
),
if
(
text
!=
"Complaint Details"
)
...[
InkResponse
(
onTap:
()
async
{
var
redirectScreen
;
switch
(
text
)
{
case
"Job Cards"
:
redirectScreen
=
Jobcardlistscreen
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
complaintId:
widget
.
complaintId
,
);
break
;
case
"Service Details"
:
redirectScreen
=
serviceListScreen
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
complaintId:
widget
.
complaintId
,
);
break
;
default
:
break
;
}
await
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
redirectScreen
),
);
},
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
8.0
),
child:
Text
(
"See All"
,
style:
TextStyle
(
color:
AppColors
.
buttonColor
,
fontSize:
14
),
),
),
),
],
],
),
);
}
Future
<
void
>
_showJobCardProductSheet
(
context
)
{
return
showModalBottomSheet
(
useSafeArea:
true
,
isDismissible:
true
,
isScrollControlled:
true
,
showDragHandle:
true
,
backgroundColor:
Colors
.
white
,
enableDrag:
true
,
context:
context
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
SafeArea
(
child:
Consumer
<
HelpAndComplaintProvider
>(
builder:
(
context
,
provider
,
child
)
{
final
jobcardProductData
=
provider
.
jobCardResponse
;
final
list
=
jobcardProductData
?.
jobCardProducts
;
final
data
=
provider
.
compDetailsResponse
;
final
jobCardsData
=
data
!.
jobCardList
?.
firstOrNull
;
return
Container
(
margin:
EdgeInsets
.
only
(
bottom:
15
,
left:
15
,
right:
15
,
top:
10
,
),
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
),
child:
SingleChildScrollView
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
SizedBox
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"
${jobCardsData?.date}
"
,
style:
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
Text
(
"Job Card Details"
,
style:
TextStyle
(
color:
AppColors
.
nearDarkText
,
fontSize:
14
,
),
),
],
),
),
SizedBox
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
Text
(
"Total Amount"
,
style:
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
Text
(
"₹
${jobCardsData?.totalPrice}
"
,
style:
TextStyle
(
color:
AppColors
.
buttonColor
,
fontSize:
14
,
),
),
],
),
),
],
),
Divider
(
thickness:
0.3
,
color:
AppColors
.
subtitleText
,
),
ListView
.
builder
(
shrinkWrap:
true
,
itemCount:
list
?.
length
,
physics:
NeverScrollableScrollPhysics
(),
itemBuilder:
(
BuildContext
context
,
int
j
)
{
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
vertical:
5
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
"
${j + 1}
.
${list?[j].partName}
"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
Text
(
"₹
${list?[j].price}
*
${list?[j].qty}
"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
Text
(
"₹
${list?[j].totalPrice}
"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
],
),
);
},
),
],
),
),
);
},
),
);
},
);
},
).
whenComplete
(()
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
timeStamp
)
{
setState
(()
{
bottomSheetButtonClicked
=
false
;
});
});
});
}
void
_openPaymentSheet
(
BuildContext
context
,
String
totalAmountStr
)
{
TextEditingController
amountController
=
TextEditingController
();
bool
isPartPayment
=
false
;
final
double
totalAmount
=
double
.
tryParse
(
totalAmountStr
)
??
0
;
showModalBottomSheet
(
isScrollControlled:
true
,
backgroundColor:
Colors
.
white
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
24
)),
),
context:
context
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
top:
16
,
left:
16
,
right:
16
,
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Handle Bar
Center
(
child:
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
[
300
],
borderRadius:
BorderRadius
.
circular
(
4
),
),
),
),
const
SizedBox
(
height:
16
),
// Title
const
Text
(
"Balance Amount Bill"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
10
),
// Pay Total Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
false
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
false
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Pay Total"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
Text
(
"Avoid late payment fees."
,
style:
TextStyle
(
color:
Color
(
0xff5FBB54
),
fontSize:
12
,
fontFamily:
"Poppins"
,
),
),
],
),
const
Spacer
(),
Text
(
"₹
${totalAmount.toStringAsFixed(0)}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
const
SizedBox
(
height:
10
),
// Part Payment Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
true
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
true
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
const
Text
(
"Part Payment"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
const
SizedBox
(
width:
24
),
Expanded
(
child:
Container
(
height:
50
,
alignment:
Alignment
.
center
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade100
,
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
TextFormField
(
controller:
amountController
,
enabled:
isPartPayment
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
black87
,
),
keyboardType:
TextInputType
.
number
,
decoration:
const
InputDecoration
(
hintText:
"Enter amount"
,
hintStyle:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
),
border:
InputBorder
.
none
,
),
),
),
),
],
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
6
),
// Continue Button
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
{
double
enteredAmount
=
isPartPayment
?
double
.
tryParse
(
amountController
.
text
)
??
0
:
totalAmount
;
if
(
enteredAmount
<=
0
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Please enter a valid amount"
),
),
);
return
;
}
if
(
isPartPayment
&&
enteredAmount
>
totalAmount
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Entered amount cannot exceed total amount"
,
),
),
);
return
;
}
Navigator
.
pop
(
context
);
// Pass selected amount to your payAmountFunction
payAmountFunction
(
enteredAmount
.
toStringAsFixed
(
2
));
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF008CDE
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"Continue Payment"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
white
,
fontSize:
16
,
),
),
SvgPicture
.
asset
(
"assets/svg/continue_ic.svg"
,
color:
Colors
.
white
,
height:
25
,
width:
25
,
),
],
),
),
),
),
const
SizedBox
(
height:
16
),
],
),
);
},
);
},
);
}
}
lib/Screens/HelpAndComplaintScreens/ComplaintListScreen.dart
View file @
97403192
...
@@ -5,6 +5,7 @@ import 'package:gen_service/Screens/HelpAndComplaintScreens/SelectOrderHelpScree
...
@@ -5,6 +5,7 @@ import 'package:gen_service/Screens/HelpAndComplaintScreens/SelectOrderHelpScree
import
'package:gen_service/Screens/ProfileScreen.dart'
;
import
'package:gen_service/Screens/ProfileScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Utility/AppColors.dart'
;
import
'../../Utility/AppColors.dart'
;
import
'ComplaintDetailsScreen.dart'
;
class
ComplaintListScreen
extends
StatefulWidget
{
class
ComplaintListScreen
extends
StatefulWidget
{
final
String
accId
;
final
String
accId
;
...
@@ -27,8 +28,10 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -27,8 +28,10 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
Future
.
microtask
(()
{
Future
.
microtask
(()
{
final
provider
=
final
provider
=
Provider
.
of
<
HelpAndComplaintProvider
>(
Provider
.
of
<
HelpAndComplaintProvider
>(
context
,
listen:
false
);
context
,
listen:
false
,
);
provider
.
fetchComplaintsList
(
provider
.
fetchComplaintsList
(
accId:
widget
.
accId
,
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
sessionId:
widget
.
sessionId
,
...
@@ -57,30 +60,135 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -57,30 +60,135 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
return
Scaffold
(
return
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
body:
Center
(
child:
Text
(
child:
Padding
(
error
,
padding:
const
EdgeInsets
.
all
(
24.0
),
style:
const
TextStyle
(
color:
Colors
.
red
,
fontSize:
16
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
// Error Icon
Container
(
width:
120
,
height:
120
,
decoration:
BoxDecoration
(
color:
Colors
.
red
.
withOpacity
(
0.1
),
shape:
BoxShape
.
circle
,
),
child:
const
Icon
(
Icons
.
error_outline_rounded
,
size:
60
,
color:
Colors
.
red
,
),
),
const
SizedBox
(
height:
24
),
// Error Title
const
Text
(
"Oops! Something went wrong"
,
style:
TextStyle
(
fontSize:
20
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
12
),
// Error Message
Text
(
error
,
textAlign:
TextAlign
.
center
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
height:
1.4
,
),
),
const
SizedBox
(
height:
32
),
// Retry Button
ElevatedButton
.
icon
(
onPressed:
()
async
{
// Show loading state
setState
(()
{});
await
Future
.
delayed
(
const
Duration
(
milliseconds:
300
));
// Retry fetching data
final
provider
=
Provider
.
of
<
HelpAndComplaintProvider
>(
context
,
listen:
false
,
);
provider
.
fetchComplaintsList
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
24
,
vertical:
12
,
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
25
),
),
elevation:
2
,
),
icon:
const
Icon
(
Icons
.
refresh_rounded
,
size:
20
),
label:
const
Text
(
"Try Again"
,
style:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
),
const
SizedBox
(
height:
16
),
// Alternative Action
TextButton
(
onPressed:
()
{
// Go back or navigate to home
Navigator
.
pop
(
context
);
},
child:
const
Text
(
"Go Back"
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
),
),
),
],
),
),
),
),
),
);
);
}
}
if
(
data
==
null
)
{
if
(
data
==
null
)
{
return
const
Scaffold
(
return
const
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
body:
Center
(
child:
Text
(
"No data found."
)),
child:
Text
(
"No data found."
),
),
);
);
}
}
// Separate open and closed complaints
// Separate open and closed complaints
final
openComplaints
=
data
.
complaintList
!
final
openComplaints
=
.
where
((
c
)
=>
c
.
openStatus
?.
toLowerCase
()
==
"open"
)
data
.
complaintList
!
.
toList
();
.
where
((
c
)
=>
c
.
openStatus
?.
toLowerCase
()
==
"open"
)
final
closedComplaints
=
data
.
complaintList
!
.
toList
();
.
where
((
c
)
=>
c
.
openStatus
?.
toLowerCase
()
==
"closed"
)
final
closedComplaints
=
.
toList
();
data
.
complaintList
!
.
where
((
c
)
=>
c
.
openStatus
?.
toLowerCase
()
==
"closed"
)
.
toList
();
return
RefreshIndicator
.
adaptive
(
return
RefreshIndicator
.
adaptive
(
color:
AppColors
.
amountText
,
color:
AppColors
.
amountText
,
...
@@ -113,12 +221,12 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -113,12 +221,12 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
StretchMode
.
blurBackground
,
StretchMode
.
blurBackground
,
],
],
background:
Container
(
background:
Container
(
decoration:
decoration:
const
BoxDecoration
(
color:
AppColors
.
primary
),
const
BoxDecoration
(
gradient:
AppColors
.
commonAppBarGradient
),
child:
Padding
(
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
16
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
16
,
),
child:
Row
(
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
children:
[
...
@@ -151,9 +259,12 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -151,9 +259,12 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
SliverToBoxAdapter
(
SliverToBoxAdapter
(
child:
Container
(
child:
Container
(
padding:
const
EdgeInsets
.
only
(
top:
1
),
padding:
const
EdgeInsets
.
only
(
top:
1
),
color:
AppColors
.
backgroundBottom
,
color:
AppColors
.
primary
,
child:
Container
(
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
20
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
20
,
),
decoration:
const
BoxDecoration
(
decoration:
const
BoxDecoration
(
color:
AppColors
.
backgroundRegular
,
color:
AppColors
.
backgroundRegular
,
borderRadius:
BorderRadius
.
only
(
borderRadius:
BorderRadius
.
only
(
...
@@ -168,8 +279,14 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -168,8 +279,14 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
InkResponse
(
InkResponse
(
onTap:
()
{
onTap:
()
{
Navigator
.
push
(
Navigator
.
push
(
context
,
context
,
MaterialPageRoute
(
builder:
(
context
)=>
SelectOrderHelpScreen
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
))
MaterialPageRoute
(
builder:
(
context
)
=>
SelectOrderHelpScreen
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
),
),
).
then
((
_
)
async
{
).
then
((
_
)
async
{
await
provider
.
fetchComplaintsList
(
await
provider
.
fetchComplaintsList
(
accId:
widget
.
accId
,
accId:
widget
.
accId
,
...
@@ -179,7 +296,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -179,7 +296,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
},
},
child:
Container
(
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
,
horizontal:
14
),
vertical:
16
,
horizontal:
14
,
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
14
),
borderRadius:
BorderRadius
.
circular
(
14
),
...
@@ -246,7 +365,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -246,7 +365,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
const
SizedBox
(
height:
8
),
const
SizedBox
(
height:
8
),
...
openComplaints
.
map
(
...
openComplaints
.
map
(
(
c
)
=>
ComplaintCard
(
(
c
)
=>
ComplaintCard
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
title:
c
.
complaintName
??
"-"
,
title:
c
.
complaintName
??
"-"
,
id:
c
.
id
??
"-"
,
id:
c
.
id
??
"-"
,
product:
c
.
productName
??
""
,
product:
c
.
productName
??
""
,
...
@@ -271,7 +392,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -271,7 +392,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
const
SizedBox
(
height:
8
),
const
SizedBox
(
height:
8
),
...
closedComplaints
.
map
(
...
closedComplaints
.
map
(
(
c
)
=>
ComplaintCard
(
(
c
)
=>
ComplaintCard
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
title:
c
.
complaintName
??
"-"
,
title:
c
.
complaintName
??
"-"
,
id:
c
.
id
??
""
,
id:
c
.
id
??
""
,
product:
c
.
productName
??
""
,
product:
c
.
productName
??
""
,
...
@@ -294,7 +417,8 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
...
@@ -294,7 +417,8 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
/// Reusable Complaint Item Card
/// Reusable Complaint Item Card
class
ComplaintCard
extends
StatelessWidget
{
class
ComplaintCard
extends
StatelessWidget
{
final
String
accId
;
final
String
sessionId
;
final
String
title
;
final
String
title
;
final
String
id
;
final
String
id
;
final
String
product
;
final
String
product
;
...
@@ -310,116 +434,138 @@ class ComplaintCard extends StatelessWidget {
...
@@ -310,116 +434,138 @@ class ComplaintCard extends StatelessWidget {
required
this
.
status
,
required
this
.
status
,
required
this
.
date
,
required
this
.
date
,
required
this
.
engModel
,
required
this
.
engModel
,
required
this
.
accId
,
required
this
.
sessionId
,
});
});
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
Container
(
return
InkResponse
(
margin:
const
EdgeInsets
.
symmetric
(
vertical:
6
),
onTap:
()
async
{
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
14
,
vertical:
14
),
await
Navigator
.
push
(
decoration:
BoxDecoration
(
context
,
color:
Colors
.
white
,
MaterialPageRoute
(
borderRadius:
BorderRadius
.
circular
(
12
),
builder:
// border: Border.all(color: Colors.grey.shade200),
(
context
)
=>
ComplaintDetailsScreen
(
// boxShadow: [
accId:
accId
,
// BoxShadow(
sessionId:
sessionId
,
// color: Colors.grey.shade200,
complaintId:
id
,
// blurRadius: 4,
),
// offset: const Offset(0, 2),
),
// )
);
// ],
},
),
child:
Container
(
child:
Column
(
margin:
const
EdgeInsets
.
symmetric
(
vertical:
6
),
children:
[
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
14
,
vertical:
14
),
Row
(
decoration:
BoxDecoration
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
color:
Colors
.
white
,
children:
[
borderRadius:
BorderRadius
.
circular
(
12
),
Column
(
border:
Border
.
all
(
color:
Colors
.
grey
.
shade200
),
crossAxisAlignment:
CrossAxisAlignment
.
start
,
boxShadow:
[
children:
[
BoxShadow
(
Row
(
color:
Colors
.
grey
.
shade200
,
children:
[
blurRadius:
4
,
Text
(
offset:
const
Offset
(
0
,
2
),
"#
${id}
| "
,
),
style:
TextStyle
(
],
fontFamily:
"Poppins"
,
),
fontSize:
14
,
child:
Column
(
fontWeight:
FontWeight
.
w400
,
children:
[
color:
AppColors
.
amountText
,
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
children:
[
Text
(
"#
${id}
| "
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
amountText
,
),
),
),
),
Text
(
Text
(
title
,
tit
le
,
style:
TextSty
le
(
style:
TextStyle
(
fontFamily:
"Poppins"
,
font
Family:
"Poppins"
,
font
Size:
14
,
font
Size:
14
,
font
Weight:
FontWeight
.
w400
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
amountText
,
color:
AppColors
.
amountText
,
)
,
),
),
],
),
const
SizedBox
(
height:
4
),
Text
(
"Date:
$date
"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
subtitleText
,
),
),
],
),
const
SizedBox
(
height:
2
),
],
),
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
15
,
vertical:
7
),
decoration:
BoxDecoration
(
color:
status
==
"Open"
?
AppColors
.
successBG
:
AppColors
.
yellowBG
,
borderRadius:
BorderRadius
.
circular
(
10
),
),
),
const
SizedBox
(
height:
4
),
child:
Text
(
Text
(
status
,
"Date:
$date
"
,
style:
TextStyle
(
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontSize:
1
2
,
fontSize:
1
4
,
fontWeight:
FontWeight
.
w400
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
subtitleText
,
color:
status
==
"Open"
?
AppColors
.
success
:
AppColors
.
normalText
,
),
),
),
),
const
SizedBox
(
height:
2
),
],
),
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
15
,
vertical:
7
),
decoration:
BoxDecoration
(
color:
status
==
"Open"
?
AppColors
.
successBG
:
AppColors
.
yellowBG
,
borderRadius:
BorderRadius
.
circular
(
10
),
),
),
child:
Text
(
],
status
,
),
style:
TextStyle
(
Divider
(),
fontFamily:
"Poppins"
,
Row
(
fontSize:
14
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
fontWeight:
FontWeight
.
w400
,
children:
[
color:
status
==
"Open"
?
AppColors
.
success
:
AppColors
.
normalText
,
Expanded
(
flex:
6
,
child:
Text
(
product
,
maxLines:
2
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
black87
,
),
),
),
),
),
),
Text
(
],
"#
${id}
| Engine :
$engModel
"
,
),
Divider
(),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Expanded
(
flex:
6
,
child:
Text
(
product
,
maxLines:
2
,
style:
TextStyle
(
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontSize:
12
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
black87
,
color:
App
Colors
.
subtitleText
,
),
),
),
),
),
],
Text
(
),
"#
${id}
| Engine :
$engModel
"
,
],
style:
TextStyle
(
),
fontFamily:
"Poppins"
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
subtitleText
,
),
),
],
),
],
),
),
);
);
}
}
...
...
lib/Screens/HelpAndComplaintScreens/SelectOrderHelpScreen.dart
View file @
97403192
...
@@ -58,9 +58,115 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> {
...
@@ -58,9 +58,115 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> {
return
Scaffold
(
return
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
body:
Center
(
child:
Text
(
child:
Padding
(
error
,
padding:
const
EdgeInsets
.
all
(
24.0
),
style:
const
TextStyle
(
color:
Colors
.
red
,
fontSize:
16
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
// Error Icon
Container
(
width:
120
,
height:
120
,
decoration:
BoxDecoration
(
color:
Colors
.
red
.
withOpacity
(
0.1
),
shape:
BoxShape
.
circle
,
),
child:
const
Icon
(
Icons
.
error_outline_rounded
,
size:
60
,
color:
Colors
.
red
,
),
),
const
SizedBox
(
height:
24
),
// Error Title
const
Text
(
"Oops! Something went wrong"
,
style:
TextStyle
(
fontSize:
20
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
12
),
// Error Message
Text
(
error
,
textAlign:
TextAlign
.
center
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
height:
1.4
,
),
),
const
SizedBox
(
height:
32
),
// Retry Button
ElevatedButton
.
icon
(
onPressed:
()
async
{
// Show loading state
setState
(()
{});
await
Future
.
delayed
(
const
Duration
(
milliseconds:
300
));
// Retry fetching data
final
provider
=
Provider
.
of
<
HelpAndComplaintProvider
>(
context
,
listen:
false
,
);
provider
.
fetchGeneratorList
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
,
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
24
,
vertical:
12
,
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
25
),
),
elevation:
2
,
),
icon:
const
Icon
(
Icons
.
refresh_rounded
,
size:
20
),
label:
const
Text
(
"Try Again"
,
style:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
),
const
SizedBox
(
height:
16
),
// Alternative Action
TextButton
(
onPressed:
()
{
// Go back or navigate to home
Navigator
.
pop
(
context
);
},
child:
const
Text
(
"Go Back"
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
),
),
),
],
),
),
),
),
),
);
);
...
...
lib/Screens/HelpAndComplaintScreens/jobcardListScreen.dart
0 → 100644
View file @
97403192
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:provider/provider.dart'
;
import
'package:razorpay_flutter/razorpay_flutter.dart'
;
import
'../../Notifiers/HelpAndComplaintProvider.dart'
;
import
'../../Notifiers/PayAmountProvider.dart'
;
import
'../../Notifiers/serviceAndJobCardListProvier.dart'
;
import
'../../Utility/AppColors.dart'
;
import
'../../Utility/CustomSnackbar.dart'
;
import
'../../Utility/SharedpreferencesService.dart'
;
class
Jobcardlistscreen
extends
StatefulWidget
{
final
accId
;
final
sessionId
;
final
complaintId
;
const
Jobcardlistscreen
({
super
.
key
,
required
this
.
accId
,
required
this
.
sessionId
,
required
this
.
complaintId
,
});
@override
State
<
Jobcardlistscreen
>
createState
()
=>
_JobcardlistscreenState
();
}
class
_JobcardlistscreenState
extends
State
<
Jobcardlistscreen
>
{
late
Razorpay
_razorpay
;
bool
?
isSuccess
;
var
paymentMethod
=
""
;
var
User_contact
=
"0"
;
bool
bottomSheetButtonClicked
=
false
;
final
prefs
=
SharedPreferencesService
.
instance
;
@override
void
initState
()
{
// TODO: implement initState
super
.
initState
();
_razorpay
=
Razorpay
();
WidgetsBinding
.
instance
.
addPostFrameCallback
((
timeStamp
)
{
final
provider
=
Provider
.
of
<
ServiceAndJobCardListProvider
>(
context
,
listen:
false
,
);
provider
.
fetchAllJobCardsListAPI
(
widget
.
accId
,
widget
.
sessionId
,
widget
.
complaintId
,
);
});
}
//_________________________________________________________
void
_handlePaymentSuccess
(
PaymentSuccessResponse
response
)
{
setState
(()
async
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
getPaymentStatus
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
razorpayOrderId:
response
.
orderId
.
toString
(),
);
final
data
=
provider
.
statusResponse
;
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
// total: "${data?.amount}",
// date: "${data?.date}",
// payMode: "UPI",
// status: "Success",
// )),
// );
_razorpay
.
clear
();
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
data
?.
message
??
"Payment Success!"
,
);
// buttonLoading = false;
});
}
void
_handlePaymentError
(
PaymentFailureResponse
response
)
{
setState
(()
async
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
});
_razorpay
.
clear
();
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
}
void
_handleExternalWallet
(
ExternalWalletResponse
response
)
{
_razorpay
.
clear
();
}
Future
<
void
>
payAmountFunction
(
String
amount
)
async
{
try
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
payAmount
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
amount:
amount
,
refType:
"Gen Service"
,
refId:
"1"
,
);
final
data
=
provider
.
payResponse
;
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
openCheckout
(
data
.
orderId
,
data
.
razorKey
!);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"
${data.message}
"
,
);
debugPrint
(
"❌ Could not Complete Payment:
${data.message}
"
);
}
}
else
{
debugPrint
(
"❌ No response received from PayAmount API"
);
}
}
catch
(
e
)
{
debugPrint
(
"❌ 'Error occurred:
$e
'"
);
}
}
//razorpay payments__________________________________________________________
void
openCheckout
(
razorPayOrderId
,
String
razorpayKey
)
async
{
final
String
?
mobNumber
=
await
prefs
.
getString
(
"mob_number"
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_SUCCESS
,
_handlePaymentSuccess
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_ERROR
,
_handlePaymentError
);
_razorpay
.
on
(
Razorpay
.
EVENT_EXTERNAL_WALLET
,
_handleExternalWallet
);
// _buildCheckWidget();
Map
<
String
,
dynamic
>
options
=
{
'key'
:
razorpayKey
,
'amount'
:
int
.
parse
(
"
${((0) * 100).round()}
"
),
'name'
:
'Gen Service'
,
'order_id'
:
razorPayOrderId
,
'description'
:
"Bill"
,
'currency'
:
'INR'
,
'method'
:
'upi'
,
'prefill'
:
{
'contact'
:
mobNumber
,
'email'
:
''
},
};
// print(options);
try
{
_razorpay
.
open
(
options
);
}
catch
(
e
,
s
)
{
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint
(
e
.
toString
());
}
}
void
verifyPayment
(
String
orderId
)
{
isSuccess
=
true
;
setState
(()
{
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
_razorpay
.
clear
();
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
@override
Widget
build
(
BuildContext
context
)
{
return
Consumer2
<
ServiceAndJobCardListProvider
,
HelpAndComplaintProvider
>(
builder:
(
context
,
provider
,
hcProvider
,
child
)
{
final
isLoading
=
provider
.
isLoading
;
final
error
=
provider
.
errorMessage
;
final
response
=
provider
.
allJobCardResponse
;
final
data
=
response
?.
jobCardList
??
[];
if
(
isLoading
)
{
return
const
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
child:
CircularProgressIndicator
(
color:
AppColors
.
buttonColor
),
),
);
}
if
(
error
!=
null
)
{
return
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
24.0
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
// Error Icon
Container
(
width:
120
,
height:
120
,
decoration:
BoxDecoration
(
color:
Colors
.
red
.
withOpacity
(
0.1
),
shape:
BoxShape
.
circle
,
),
child:
const
Icon
(
Icons
.
error_outline_rounded
,
size:
60
,
color:
Colors
.
red
,
),
),
const
SizedBox
(
height:
24
),
// Error Title
const
Text
(
"Oops! Something went wrong"
,
style:
TextStyle
(
fontSize:
20
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
12
),
// Error Message
Text
(
error
,
textAlign:
TextAlign
.
center
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
height:
1.4
,
),
),
const
SizedBox
(
height:
32
),
// Retry Button
ElevatedButton
.
icon
(
onPressed:
()
async
{
// Show loading state
setState
(()
{});
await
Future
.
delayed
(
const
Duration
(
milliseconds:
300
));
// Retry fetching data
final
provider
=
Provider
.
of
<
ServiceAndJobCardListProvider
>(
context
,
listen:
false
,
);
await
provider
.
fetchAllJobCardsListAPI
(
widget
.
accId
,
widget
.
sessionId
,
widget
.
complaintId
,
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
24
,
vertical:
12
,
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
25
),
),
elevation:
2
,
),
icon:
const
Icon
(
Icons
.
refresh_rounded
,
size:
20
),
label:
const
Text
(
"Try Again"
,
style:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
),
const
SizedBox
(
height:
16
),
// Alternative Action
TextButton
(
onPressed:
()
{
// Go back or navigate to home
Navigator
.
maybePop
(
context
);
},
child:
const
Text
(
"Go Back"
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
fontFamily:
"Poppins"
,
),
),
),
],
),
),
),
);
}
if
(
data
==
null
)
{
return
const
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
Center
(
child:
Text
(
"No data found."
)),
);
}
return
RefreshIndicator
.
adaptive
(
color:
AppColors
.
amountText
,
onRefresh:
()
async
{
await
Future
.
delayed
(
const
Duration
(
milliseconds:
600
));
},
child:
Scaffold
(
backgroundColor:
AppColors
.
backgroundRegular
,
body:
CustomScrollView
(
physics:
const
BouncingScrollPhysics
(),
slivers:
[
SliverAppBar
(
stretch:
true
,
pinned:
true
,
expandedHeight:
75
,
backgroundColor:
AppColors
.
backgroundRegular
,
elevation:
0
,
// Remove shadow
automaticallyImplyLeading:
false
,
toolbarHeight:
0
,
// Remove toolbar space
collapsedHeight:
0
,
// Completely collapse to 0 height
flexibleSpace:
FlexibleSpaceBar
(
stretchModes:
const
[
StretchMode
.
fadeTitle
],
background:
Container
(
decoration:
BoxDecoration
(
gradient:
AppColors
.
balanceBarGradientA
,
),
child:
SafeArea
(
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
20
,
),
child:
SizedBox
(
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
InkResponse
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
Navigator
.
pop
(
context
,
true
);
},
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back.svg"
,
height:
25
,
),
),
SizedBox
(
width:
10
),
Expanded
(
flex:
4
,
child:
InkResponse
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
Navigator
.
pop
(
context
,
true
);
},
child:
Text
(
"Job Cards List"
,
overflow:
TextOverflow
.
ellipsis
,
maxLines:
1
,
style:
TextStyle
(
fontSize:
16
,
color:
Colors
.
white
,
height:
1.1
,
),
),
),
),
],
),
),
),
),
),
),
),
SliverToBoxAdapter
(
child:
Container
(
color:
Color
(
0xFF4076FF
),
child:
Container
(
decoration:
const
BoxDecoration
(
color:
AppColors
.
backgroundRegular
,
borderRadius:
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
30
),
topRight:
Radius
.
circular
(
30
),
),
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
SizedBox
(
height:
4
),
ListView
.
builder
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
itemCount:
data
!.
length
,
itemBuilder:
(
context
,
j
)
{
return
Container
(
margin:
const
EdgeInsets
.
all
(
5
),
padding:
const
EdgeInsets
.
all
(
14
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xFFFFFFFF
),
borderRadius:
BorderRadius
.
circular
(
16
),
border:
Border
.
all
(
width:
1.1
,
color:
AppColors
.
buttonColor
,
),
),
child:
Column
(
children:
[
Row
(
children:
[
Expanded
(
flex:
5
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
data
[
j
].
date
!,
maxLines:
2
,
style:
const
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
SizedBox
(
height:
4
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
Text
(
"Job Card"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
InkResponse
(
onTap:
()
{
hcProvider
.
fetchJobCardProductDetails
(
widget
.
accId
,
widget
.
sessionId
,
data
[
j
]!.
id
,
);
Future
.
delayed
(
Duration
(
milliseconds:
400
,
),
()
{
_showJobCardProductSheet
(
context
,
data
[
j
]!.
date
,
data
[
j
]!.
totalPrice
);
},
);
},
child:
Text
(
" ⓘ View Details"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
buttonColor
,
),
),
),
],
),
],
),
),
Expanded
(
flex:
2
,
child:
Text
(
"₹
${data[j].totalPrice}
"
,
textAlign:
TextAlign
.
right
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
nearDarkText
,
),
),
),
],
),
Divider
(
thickness:
0.3
,
color:
AppColors
.
subtitleText
,
),
InkResponse
(
onTap:
()
=>
_openPaymentSheet
(
context
,
data
[
j
].
totalPrice
.
toString
()),
child:
Container
(
padding:
EdgeInsets
.
symmetric
(
vertical:
16
,
horizontal:
10
,
),
decoration:
BoxDecoration
(
color:
AppColors
.
buttonColor
,
borderRadius:
BorderRadius
.
circular
(
25
,
),
),
child:
Center
(
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
14
,
fontWeight:
FontWeight
.
w600
,
),
),
),
),
),
],
),
);
},
),
],
),
),
),
),
],
),
),
);
},
);
}
Future
<
void
>
_showJobCardProductSheet
(
context
,
date
,
amount
)
{
return
showModalBottomSheet
(
useSafeArea:
true
,
isDismissible:
true
,
isScrollControlled:
true
,
showDragHandle:
true
,
backgroundColor:
Colors
.
white
,
enableDrag:
true
,
context:
context
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
SafeArea
(
child:
Consumer
<
HelpAndComplaintProvider
>(
builder:
(
context
,
provider
,
child
)
{
final
jobcardProductData
=
provider
.
jobCardResponse
;
final
list
=
jobcardProductData
?.
jobCardProducts
;
final
data
=
provider
.
compDetailsResponse
;
final
jobCardsData
=
data
!.
jobCardList
?.
firstOrNull
;
return
Container
(
margin:
EdgeInsets
.
only
(
bottom:
15
,
left:
15
,
right:
15
,
top:
10
,
),
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
),
child:
SingleChildScrollView
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
SizedBox
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"
${date}
"
,
style:
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
Text
(
"Job Card Details"
,
style:
TextStyle
(
color:
AppColors
.
nearDarkText
,
fontSize:
14
,
),
),
],
),
),
SizedBox
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
Text
(
"Total Amount"
,
style:
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
12
,
),
),
Text
(
"₹
${amount}
"
,
style:
TextStyle
(
color:
AppColors
.
buttonColor
,
fontSize:
14
,
),
),
],
),
),
],
),
Divider
(
thickness:
0.3
,
color:
AppColors
.
subtitleText
,
),
ListView
.
builder
(
shrinkWrap:
true
,
itemCount:
list
?.
length
,
physics:
NeverScrollableScrollPhysics
(),
itemBuilder:
(
BuildContext
context
,
int
j
)
{
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
vertical:
5
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
"
${j + 1}
.
${list?[j].partName}
"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
Text
(
"₹
${list?[j].price}
*
${list?[j].qty}
"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
Text
(
"₹
${list?[j].totalPrice}
"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
nearDarkText
,
),
),
],
),
);
},
),
],
),
),
);
},
),
);
},
);
},
).
whenComplete
(()
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
timeStamp
)
{
setState
(()
{});
});
});
}
void
_openPaymentSheet
(
BuildContext
context
,
String
totalAmountStr
)
{
TextEditingController
amountController
=
TextEditingController
();
bool
isPartPayment
=
false
;
final
double
totalAmount
=
double
.
tryParse
(
totalAmountStr
)
??
0
;
showModalBottomSheet
(
isScrollControlled:
true
,
backgroundColor:
Colors
.
white
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
24
)),
),
context:
context
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
top:
16
,
left:
16
,
right:
16
,
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Handle Bar
Center
(
child:
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
[
300
],
borderRadius:
BorderRadius
.
circular
(
4
),
),
),
),
const
SizedBox
(
height:
16
),
// Title
const
Text
(
"Balance Amount Bill"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
10
),
// Pay Total Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
false
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
false
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Pay Total"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
Text
(
"Avoid late payment fees."
,
style:
TextStyle
(
color:
Color
(
0xff5FBB54
),
fontSize:
12
,
fontFamily:
"Poppins"
,
),
),
],
),
const
Spacer
(),
Text
(
"₹
${totalAmount.toStringAsFixed(0)}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
const
SizedBox
(
height:
10
),
// Part Payment Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
true
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
true
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
const
Text
(
"Part Payment"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
const
SizedBox
(
width:
24
),
Expanded
(
child:
Container
(
height:
50
,
alignment:
Alignment
.
center
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade100
,
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
TextFormField
(
controller:
amountController
,
enabled:
isPartPayment
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
black87
,
),
keyboardType:
TextInputType
.
number
,
decoration:
const
InputDecoration
(
hintText:
"Enter amount"
,
hintStyle:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
),
border:
InputBorder
.
none
,
),
),
),
),
],
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
6
),
// Continue Button
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
{
double
enteredAmount
=
isPartPayment
?
double
.
tryParse
(
amountController
.
text
)
??
0
:
totalAmount
;
if
(
enteredAmount
<=
0
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Please enter a valid amount"
),
),
);
return
;
}
if
(
isPartPayment
&&
enteredAmount
>
totalAmount
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Entered amount cannot exceed total amount"
,
),
),
);
return
;
}
Navigator
.
pop
(
context
);
// Pass selected amount to your payAmountFunction
payAmountFunction
(
enteredAmount
.
toStringAsFixed
(
2
));
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF008CDE
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"Continue Payment"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
white
,
fontSize:
16
,
),
),
SvgPicture
.
asset
(
"assets/svg/continue_ic.svg"
,
color:
Colors
.
white
,
height:
25
,
width:
25
,
),
],
),
),
),
),
const
SizedBox
(
height:
16
),
],
),
);
},
);
},
);
}
}
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment