Commit 5ac94fe2 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

New Screen and apis

parent df116895
...@@ -25,7 +25,7 @@ android { ...@@ -25,7 +25,7 @@ android {
applicationId = "in.webgrid.genrentals" applicationId = "in.webgrid.genrentals"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = 23
targetSdk = 36 targetSdk = 36
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:label="Gen Rentals" android:label="Gen Rentals"
android:name="${applicationName}" android:name="${applicationName}"
......
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4376 1.70711C13.8281 1.31658 13.8281 0.683417 13.4376 0.292893C13.0471 -0.0976311 12.4139 -0.097631 12.0234 0.292893L12.7305 1L13.4376 1.70711ZM-3.43156e-05 12.7305C-3.40162e-05 13.2828 0.447681 13.7305 0.999966 13.7305L9.99997 13.7305C10.5523 13.7305 11 13.2828 11 12.7305C11 12.1782 10.5523 11.7305 9.99997 11.7305L1.99997 11.7305L1.99997 3.7305C1.99997 3.17822 1.55225 2.7305 0.999965 2.7305C0.447681 2.7305 -3.46572e-05 3.17822 -3.42735e-05 3.7305L-3.43156e-05 12.7305ZM12.7305 1L12.0234 0.292893L0.292859 12.0234L0.999966 12.7305L1.70707 13.4376L13.4376 1.70711L12.7305 1Z" fill="#4CAF50"/> <path d="M13.4376 1.70711C13.8281 1.31658 13.8281 0.683417 13.4376 0.292893C13.0471 -0.0976311 12.4139 -0.097631 12.0234 0.292893L12.7305 1L13.4376 1.70711ZM-3.43156e-05 12.7305C-3.40162e-05 13.2828 0.447681 13.7305 0.999966 13.7305L9.99997 13.7305C10.5523 13.7305 11 13.2828 11 12.7305C11 12.1782 10.5523 11.7305 9.99997 11.7305L1.99997 11.7305L1.99997 3.7305C1.99997 3.17822 1.55225 2.7305 0.999965 2.7305C0.447681 2.7305 -3.46572e-05 3.17822 -3.42735e-05 3.7305L-3.43156e-05 12.7305ZM12.7305 1L12.0234 0.292893L0.292859 12.0234L0.999966 12.7305L1.70707 13.4376L13.4376 1.70711L12.7305 1Z" fill="#F00000"/>
</svg> </svg>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.292893 12.0234C-0.0976311 12.4139 -0.0976311 13.0471 0.292893 13.4376C0.683418 13.8281 1.31658 13.8281 1.70711 13.4376L1 12.7305L0.292893 12.0234ZM13.7305 0.999965C13.7305 0.44768 13.2828 -3.50516e-05 12.7305 -3.53045e-05L3.7305 -3.45037e-05C3.17822 -3.48408e-05 2.7305 0.447681 2.7305 0.999965C2.7305 1.55225 3.17822 1.99996 3.7305 1.99997L11.7305 1.99996L11.7305 9.99996C11.7305 10.5522 12.1782 11 12.7305 11C13.2828 11 13.7305 10.5522 13.7305 9.99997L13.7305 0.999965ZM1 12.7305L1.70711 13.4376L13.4376 1.70707L12.7305 0.999965L12.0234 0.292858L0.292893 12.0234L1 12.7305Z" fill="#ED3424"/> <path d="M0.292893 12.0234C-0.0976311 12.4139 -0.0976311 13.0471 0.292893 13.4376C0.683418 13.8281 1.31658 13.8281 1.70711 13.4376L1 12.7305L0.292893 12.0234ZM13.7305 0.999965C13.7305 0.44768 13.2828 -3.50516e-05 12.7305 -3.53045e-05L3.7305 -3.45037e-05C3.17822 -3.48408e-05 2.7305 0.447681 2.7305 0.999965C2.7305 1.55225 3.17822 1.99996 3.7305 1.99997L11.7305 1.99996L11.7305 9.99996C11.7305 10.5522 12.1782 11 12.7305 11C13.2828 11 13.7305 10.5522 13.7305 9.99997L13.7305 0.999965ZM1 12.7305L1.70711 13.4376L13.4376 1.70707L12.7305 0.999965L12.0234 0.292858L0.292893 12.0234L1 12.7305Z" fill="#4CAF50"/>
</svg> </svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_591_316)">
<mask id="mask0_591_316" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
<path d="M16 0H0V16H16V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_591_316)">
<path d="M14.6666 8.66699V10.0003C14.6666 13.3337 13.3333 14.667 9.99992 14.667H5.99992C2.66659 14.667 1.33325 13.3337 1.33325 10.0003V8.98699" stroke="#2D2D2D" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.33325 1.33301H5.99992C2.66659 1.33301 1.33325 2.66634 1.33325 5.99967" stroke="#2D2D2D" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.2866 6.00586L13.9866 5.30586C14.8933 4.39919 15.3199 3.34586 13.9866 2.01253C12.6533 0.679192 11.5999 1.10586 10.6933 2.01253L5.43992 7.26587C5.23992 7.46587 5.03992 7.85921 4.99992 8.14587L4.71325 10.1525C4.60659 10.8792 5.11992 11.3859 5.84659 11.2859L7.85327 10.9992C8.13327 10.9592 8.5266 10.7592 8.73327 10.5592L10.8533 8.43921L11.3399 7.95254" stroke="#2D2D2D" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.94019 2.7666C10.3869 4.35993 11.6335 5.6066 13.2335 6.05993" stroke="#2D2D2D" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
<defs>
<clipPath id="clip0_591_316">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_383_1601)">
<path d="M4.00647 4.47004C4.00647 6.93496 6.0116 8.94009 8.47651 8.94009C10.9414 8.94009 12.9466 6.93496 12.9466 4.47004C12.9466 2.00513 10.9414 0 8.47651 0C6.0116 0 4.00647 2.00513 4.00647 4.47004Z" fill="#45C1F1"/>
<path d="M12.9466 4.47004C12.9466 2.00513 10.9415 0 8.47656 0V8.94009C10.9415 8.94009 12.9466 6.93496 12.9466 4.47004Z" fill="#44A4EC"/>
<path d="M1.02649 16.4565C1.02649 16.7311 1.24863 16.9532 1.52316 16.9532H15.43C15.7045 16.9532 15.9266 16.7311 15.9266 16.4565C15.9266 12.8964 13.03 9.93359 9.4699 9.93359H7.48322C3.92308 9.93359 1.02649 12.8964 1.02649 16.4565Z" fill="#45C1F1"/>
<path d="M9.46991 9.93359H8.47656V16.9532H15.43C15.7045 16.9532 15.9266 16.7311 15.9266 16.4565C15.9266 12.8964 13.03 9.93359 9.46991 9.93359Z" fill="#44A4EC"/>
</g>
<defs>
<clipPath id="clip0_383_1601">
<rect width="16.9531" height="16.9531" fill="white"/>
</clipPath>
</defs>
</svg>
...@@ -6,16 +6,17 @@ class CommonResponse { ...@@ -6,16 +6,17 @@ class CommonResponse {
CommonResponse({this.error, this.balance, this.message}); CommonResponse({this.error, this.balance, this.message});
CommonResponse.fromJson(Map<String, dynamic> json) { CommonResponse.fromJson(Map<String, dynamic> json) {
error = json['error']; error = int.tryParse(json['error']?.toString() ?? '');
balance = json['balance']; balance = int.tryParse(json['balance']?.toString() ?? '');
message = json['message']; message = json['message']?.toString();
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); return {
data['error'] = this.error; 'error': error,
data['balance'] = this.balance; 'balance': balance,
data['message'] = this.message; 'message': message,
return data; };
} }
} }
class TicketChatDisplayResponse {
String? status;
String? ticketId;
List<FeedBacks>? feedBacks;
String? error;
String? message;
TicketChatDisplayResponse(
{this.status, this.ticketId, this.feedBacks, this.error, this.message});
TicketChatDisplayResponse.fromJson(Map<String, dynamic> json) {
status = json['status'];
ticketId = json['ticket_id'];
if (json['feed_backs'] != null) {
feedBacks = <FeedBacks>[];
json['feed_backs'].forEach((v) {
feedBacks!.add(new FeedBacks.fromJson(v));
});
}
error = json['error'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['ticket_id'] = this.ticketId;
if (this.feedBacks != null) {
data['feed_backs'] = this.feedBacks!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
return data;
}
}
class FeedBacks {
String? id;
String? text;
List<String>? imgNames;
List<String>? images;
String? user;
String? userName;
String? createdDatetime;
String? userImg;
FeedBacks(
{this.id,
this.text,
this.imgNames,
this.images,
this.user,
this.userName,
this.createdDatetime});
FeedBacks.fromJson(Map<String, dynamic> json) {
id = json['id'];
text = json['text'];
imgNames = json['img_names'].cast<String>();
images = json['images'].cast<String>();
user = json['user'];
userName = json['user_name'];
createdDatetime = json['created_datetime'];
userImg = json['user_img'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['text'] = this.text;
data['img_names'] = this.imgNames;
data['images'] = this.images;
data['user'] = this.user;
data['user_name'] = this.userName;
data['created_datetime'] = this.createdDatetime;
data['user_img'] = this.userImg;
return data;
}
}
class TicketListResponse {
final Tickets? tickets;
final String? error;
final String? message;
TicketListResponse({this.tickets, this.error, this.message});
factory TicketListResponse.fromJson(Map<String, dynamic> json) {
return TicketListResponse(
tickets:
json['tickets'] != null ? Tickets.fromJson(json['tickets']) : null,
error: json['error']?.toString(),
message: json['message']?.toString(),
);
}
Map<String, dynamic> toJson() => {
if (tickets != null) 'tickets': tickets!.toJson(),
'error': error,
'message': message,
};
}
class Tickets {
final List<TicketItem>? closed;
final List<TicketItem>? inProgress;
Tickets({this.closed, this.inProgress});
factory Tickets.fromJson(Map<String, dynamic> json) {
return Tickets(
closed: (json['closed'] as List?)
?.map((v) => TicketItem.fromJson(v))
.toList(),
inProgress: (json['in_progress'] as List?)
?.map((v) => TicketItem.fromJson(v))
.toList(),
);
}
Map<String, dynamic> toJson() => {
if (closed != null)
'closed': closed!.map((v) => v.toJson()).toList(),
if (inProgress != null)
'in_progress': inProgress!.map((v) => v.toJson()).toList(),
};
}
class TicketItem {
final String? id;
final String? ticketNumber;
final String? type;
final String? date;
TicketItem({this.id, this.ticketNumber, this.type, this.date});
factory TicketItem.fromJson(Map<String, dynamic> json) {
return TicketItem(
id: json['id']?.toString(),
ticketNumber: json['ticket_number']?.toString(),
type: json['type']?.toString(),
date: json['date']?.toString(),
);
}
Map<String, dynamic> toJson() => {
'id': id,
'ticket_number': ticketNumber,
'type': type,
'date': date,
};
}
class TicketChatDisplayResponse {
List<Ticket>? ticket;
int? error;
String? message;
TicketChatDisplayResponse({this.ticket, this.error, this.message});
TicketChatDisplayResponse.fromJson(Map<String, dynamic> json) {
if (json['ticket'] != null) {
ticket = <Ticket>[];
json['ticket'].forEach((v) {
ticket!.add(new Ticket.fromJson(v));
});
}
error = json['error'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.ticket != null) {
data['ticket'] = this.ticket!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
return data;
}
}
class Ticket {
String? tid;
String? datetime;
String? msg;
String? type;
Ticket({this.tid, this.datetime, this.msg, this.type});
Ticket.fromJson(Map<String, dynamic> json) {
tid = json['tid'];
datetime = json['datetime'];
msg = json['msg'];
type = json['type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['tid'] = this.tid;
data['datetime'] = this.datetime;
data['msg'] = this.msg;
data['type'] = this.type;
return data;
}
}
class TicketListResponse {
List<Ticket>? ticket;
int? error;
String? message;
TicketListResponse({this.ticket, this.error, this.message});
TicketListResponse.fromJson(Map<String, dynamic> json) {
if (json['ticket'] != null) {
ticket = <Ticket>[];
json['ticket'].forEach((v) {
ticket!.add(new Ticket.fromJson(v));
});
}
error = json['error'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.ticket != null) {
data['ticket'] = this.ticket!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
return data;
}
}
class Ticket {
String? tid;
String? datetime;
String? status;
String? subject;
Ticket({this.tid, this.datetime, this.status, this.subject});
Ticket.fromJson(Map<String, dynamic> json) {
tid = json['tid'];
datetime = json['datetime'];
status = json['status'];
subject = json['subject'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['tid'] = this.tid;
data['datetime'] = this.datetime;
data['status'] = this.status;
data['subject'] = this.subject;
return data;
}
}
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:gen_rentals/Services/api_calling.dart';
import '../Models/HelpAndEnquiryModels/TicketChatDisplayResponse.dart';
import '../Models/HelpAndEnquiryModels/ticketListResponse.dart';
import '../Utility/CustomSnackbar.dart';
class HelpAndEnquiryProvider extends ChangeNotifier {
bool _isLoading = false;
bool get isLoading => _isLoading;
String? _message;
String? get message => _message;
int? _balance;
int? get balance => _balance;
Future<bool> submitEnquiry({
required String sessionId,
required String accId,
required String name,
required String email,
required String mobile,
required String requirement,
required String note,
}) async {
try {
_isLoading = true;
_message = null;
notifyListeners();
final response = await ApiCalling.submitEnquiryApi(
sessionId,
accId,
name,
email,
mobile,
requirement,
note,
);
_isLoading = false;
if (response != null) {
_message = response.message;
_balance = response.balance;
notifyListeners();
if (response.error == 0) {
// success
debugPrint("✅ Enquiry submitted successfully: ${response.message}");
return true;
} else {
// failed
debugPrint("⚠️ Failed to submit enquiry: ${response.message}");
return false;
}
} else {
_isLoading = false;
notifyListeners();
debugPrint("❌ Null response received.");
return false;
}
} catch (e) {
_isLoading = false;
notifyListeners();
debugPrint("❌ Exception in submitEnquiry: $e");
return false;
}
}
String? _errorMessage;
TicketListResponse? _ticketListResponse;
String? get errorMessage => _errorMessage;
TicketListResponse? get ticketListResponse => _ticketListResponse;
/// ✅ Fetch ticket list from API
Future<void> fetchTicketList({
required String sessionId,
required String accId,
}) async {
_isLoading = true;
_errorMessage = null;
notifyListeners();
try {
final response =
await ApiCalling.fetchTicketListApi(sessionId, accId,);
if (response != null && response.error == "0") {
_ticketListResponse = response;
} else {
_errorMessage = response?.message ?? "Something went wrong";
}
} catch (e) {
debugPrint("❌ Provider Error (fetchTicketList): $e");
_errorMessage = e.toString();
} finally {
_isLoading = false;
notifyListeners();
}
}
/// ✅ Optional: Clear state (useful on logout or refresh)
void clearTickets() {
_ticketListResponse = null;
_errorMessage = null;
notifyListeners();
}
TicketChatDisplayResponse? _chatResponse;
TicketChatDisplayResponse? get chatResponse => _chatResponse;
/// Fetch chat details for a specific ticket
Future<void> fetchTicketChatDisplay({
required String sessionId,
required String accId,
required String ticketId,
}) async {
_isLoading = true;
_errorMessage = null;
notifyListeners();
try {
final response = await ApiCalling.fetchTicketChatDisplayApi(
sessionId,
accId,
ticketId,
);
if (response != null && response.error == "0") {
_chatResponse = response;
_errorMessage = null;
} else {
_chatResponse = null;
_errorMessage = response?.message ?? "Something went wrong";
}
} catch (e) {
debugPrint("❌ Provider Error (fetchTicketChatDisplay): $e");
_errorMessage = e.toString();
_chatResponse = null;
} finally {
_isLoading = false;
notifyListeners();
}
}
/// Optional: Clear data (for refresh or reset)
void clearChatData() {
_chatResponse = null;
_errorMessage = null;
notifyListeners();
}
bool _isSending = false;
bool get isSending => _isSending;
void _setSending(bool value) {
_isSending = value;
notifyListeners();
}
Future<void> sendMessage(
BuildContext context, {
required String sessionId,
required String accId,
required String ticketId,
required String msgText,
required List<File> images,
}) async {
_setSending(true);
try {
final response = await ApiCalling.addMessageApi(
sessionId,
accId,
ticketId,
msgText,
images,
);
// Check if widget is still mounted before showing dialogs
if (!context.mounted) return;
if (response != null || response?.error == 0) {
CustomSnackBar.showSuccess(
context: context,
message: response?.message ?? "Message sent successfully!",
);
// Refresh the chat after sending message
if (context.mounted) {
fetchTicketChatDisplay(
sessionId: sessionId,
accId: accId,
ticketId: ticketId,
);
}
} else {
CustomSnackBar.showError(
context: context,
message: response?.message ?? "Failed to send message!",
);
}
} catch (e) {
debugPrint("❌ sendMessage error: $e");
// Check if widget is still mounted before showing error
if (context.mounted) {
CustomSnackBar.showError(
context: context,
message: "Error sending message",
);
}
} finally {
_setSending(false);
}
}
}
...@@ -17,25 +17,24 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -17,25 +17,24 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
top: false, top: false,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.white, backgroundColor: Colors.white,
elevation: 0,
title: Row( title: Row(
children: [ children: [
InkResponse( InkResponse(
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context, true),
child: SvgPicture.asset( child: SvgPicture.asset(
"assets/svg/continue_left_ic.svg", "assets/svg/continue_left_ic.svg",
height: 25, height: 25,
width: 25,
), ),
), ),
const SizedBox(width: 12), const SizedBox(width: 10),
const Text( const Text(
"Bill Details", "Bill List",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontFamily: "Poppins", fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
color: Colors.black87, color: Colors.black87,
), ),
), ),
...@@ -126,16 +125,41 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -126,16 +125,41 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Bill Cycle", "Invoice raised against",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.normalText,
fontWeight: FontWeight.w400,
fontSize: 12,
),
),
Text(
"#1253", // Fixed date range
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.amountText,
fontWeight: FontWeight.w400, // Medium for dates
fontSize: 12,
),
),
],
),
SizedBox(height: 4,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"order ID: 1253",
style: TextStyle( style: TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
color: AppColors.subtitleText, color: AppColors.normalText,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontSize: 12, fontSize: 12,
), ),
), ),
Text( Text(
"7th Sep 2025 - 7th Oct 2025", // Fixed date range "7th Oct 2025", // Fixed date range
style: TextStyle( style: TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
color: AppColors.normalText, color: AppColors.normalText,
...@@ -190,7 +214,8 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -190,7 +214,8 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
} }
Widget _buildBillItem({ Widget _buildBillItem({
String title = "Bill Cycle", String orderId = "#1253",
String title = "Invoice raised against",
required String fromDate, required String fromDate,
required String toDate, required String toDate,
required String amount, required String amount,
...@@ -217,16 +242,42 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -217,16 +242,42 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
children: [ children: [
Text( Text(
title, orderId,
style: TextStyle( style: TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
color: AppColors.subtitleText, color: AppColors.amountText,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12, fontSize: 12,
), ),
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.normalText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 14,
),
),
Text(
"₹$amount",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.amountText,
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 2),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
......
This diff is collapsed.
...@@ -17,6 +17,28 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> { ...@@ -17,6 +17,28 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> {
List<String> _selectedImages = []; List<String> _selectedImages = [];
String _selectedReason = 'Payment Issue'; String _selectedReason = 'Payment Issue';
// Dummy data for help - with proper null safety
final List<Map<String, dynamic>> createNewTickets = [
{
'title': 'Payment Issues',
'description': 'Get help with payment related problems',
'icon': "assets/svg/rupee_coin_ic.svg",
'color': Color(0xFFFFEFBE),
},
{
'title': 'Bill Related Issues',
'description': 'Resolve bill and invoice matters',
'icon': "assets/svg/know_pay.svg",
'color': Color(0xFFCEF9FF),
},
{
'title': 'Other Issues',
'description': 'Any other support you need',
'icon': 'assets/svg/help_ic.svg',
'color': Color(0xFFE4E5FF),
},
];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -27,7 +49,6 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> { ...@@ -27,7 +49,6 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isEditable = widget.reason == null;
final showOtherReasonField = _selectedReason == 'Other Issues'; final showOtherReasonField = _selectedReason == 'Other Issues';
return SafeArea( return SafeArea(
...@@ -66,34 +87,50 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> { ...@@ -66,34 +87,50 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
/// Section Title /// Section Title
const SectionHeading(title: 'Create New Ticket'), Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SectionHeading(title: 'Create New Ticket'),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(10),
),
child: Text(
"order #1235",
style: TextStyle(
fontSize: 14,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
),
],
),
const SizedBox(height: 12), const SizedBox(height: 12),
/// Reason Label /// Reason Label
_fieldLabel("Reason"), _fieldLabel("Reason"),
const SizedBox(height: 6), const SizedBox(height: 6),
/// Reason Dropdown /// Reason Selection Button - Opens Bottom Sheet
Container( GestureDetector(
width: double.infinity, onTap: _showReasonBottomSheet,
padding: child: Container(
const EdgeInsets.symmetric(horizontal: 16, vertical: 10), width: 200,
decoration: BoxDecoration( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
color: Color(0xffE0E0E0), decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), color: Color(0xffFFF3D1),
), borderRadius: BorderRadius.circular(12),
child: isEditable ),
? DropdownButtonFormField<String>( child: Row(
value: _selectedReason, mainAxisAlignment: MainAxisAlignment.spaceBetween,
items: [ children: [
'Payment Issue', Text(
'Bill Related Issues', _selectedReason,
'Other Issues',
].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
fontFamily: "Plus Jakarta Sans", fontFamily: "Plus Jakarta Sans",
...@@ -101,25 +138,11 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> { ...@@ -101,25 +138,11 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> {
color: Colors.black87, color: Colors.black87,
), ),
), ),
); SvgPicture.asset(
}).toList(), "assets/svg/edit_ic.svg",
onChanged: (newValue) { height: 25,
setState(() { ),
_selectedReason = newValue!; ],
});
},
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
),
)
: Text(
_selectedReason,
style: const TextStyle(
fontSize: 14,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w500,
color: Colors.black87,
), ),
), ),
), ),
...@@ -267,7 +290,7 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> { ...@@ -267,7 +290,7 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> {
return Text( return Text(
text, text,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 14,
fontFamily: "Plus Jakarta Sans", fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey[700], color: Colors.grey[700],
...@@ -341,4 +364,120 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> { ...@@ -341,4 +364,120 @@ class _HelpTicketScreenState extends State<HelpTicketScreen> {
_otherReasonController.dispose(); _otherReasonController.dispose();
super.dispose(); super.dispose();
} }
}
void _showReasonBottomSheet() {
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
builder: (context) {
return Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Select Your Reason",
style: TextStyle(
fontSize: 18,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 16),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.99,
),
itemCount: createNewTickets.length,
itemBuilder: (context, index) {
final ticket = createNewTickets[index];
final String title = ticket['title'] ?? 'Unknown';
final String icon = ticket['icon'] ?? 'assets/svg/help_ic.svg';
final Color color = ticket['color'] ?? Colors.grey;
return _buildReasonCard(
title: title,
icon: icon,
color: color,
);
},
),
const SizedBox(height: 24),
],
),
);
},
);
}
Widget _buildReasonCard({
required String title,
required String icon,
required Color color,
}) {
return GestureDetector(
onTap: () {
setState(() {
_selectedReason = title;
});
Navigator.pop(context); // Close the bottom sheet
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 1),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Icon container
Container(
width: 88,
height: 88,
decoration: BoxDecoration(
color: color.withOpacity(0.12), // Fixed opacity
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: SizedBox(
height: 40,
width: 40,
child: SvgPicture.asset(
icon,
fit: BoxFit.fitWidth,
),
),
),
),
const SizedBox(height: 8),
// Title
SizedBox(
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.nearDarkText,
fontSize: 14,
fontWeight: FontWeight.w400,
fontFamily: "Plus Jakarta Sans",
),
),
),
const SizedBox(height: 4),
],
),
),
);
}
}
\ No newline at end of file
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import '../../Notifier/HelpAndEnquiryProvider.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import '../../Utility/Reusablewidgets.dart'; import '../../Utility/CustomSnackbar.dart';
class EnquiryScreen extends StatefulWidget { class EnquiryScreen extends StatefulWidget {
const EnquiryScreen({super.key}); final String sessionId;
final String accId;
const EnquiryScreen({
super.key,
required this.sessionId,
required this.accId,
});
@override @override
State<EnquiryScreen> createState() => _EnquiryScreenState(); State<EnquiryScreen> createState() => _EnquiryScreenState();
} }
class _EnquiryScreenState extends State<EnquiryScreen> { class _EnquiryScreenState extends State<EnquiryScreen> {
final _formKey = GlobalKey<FormState>();
final TextEditingController nameController = TextEditingController(); final TextEditingController nameController = TextEditingController();
final TextEditingController emailController = TextEditingController(); final TextEditingController emailController = TextEditingController();
final TextEditingController phoneController = TextEditingController(); final TextEditingController phoneController = TextEditingController();
...@@ -19,13 +30,15 @@ class _EnquiryScreenState extends State<EnquiryScreen> { ...@@ -19,13 +30,15 @@ class _EnquiryScreenState extends State<EnquiryScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final enquiryProvider = Provider.of<HelpAndEnquiryProvider>(context);
return SafeArea( return SafeArea(
top: false, top: false,
child: Scaffold( child: Scaffold(
backgroundColor: AppColors.backgroundRegular, backgroundColor: Color(0xFFffffff),
appBar: AppBar( appBar: AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
backgroundColor: Colors.white, backgroundColor: Color(0xFFFCFCFC),
elevation: 0, elevation: 0,
title: Row( title: Row(
children: [ children: [
...@@ -53,63 +66,147 @@ class _EnquiryScreenState extends State<EnquiryScreen> { ...@@ -53,63 +66,147 @@ class _EnquiryScreenState extends State<EnquiryScreen> {
// Main Body // Main Body
body: SingleChildScrollView( body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Column( child: Form(
crossAxisAlignment: CrossAxisAlignment.start, key: _formKey,
children: [ child: Column(
_labelText("Name"), crossAxisAlignment: CrossAxisAlignment.start,
_textField(nameController, "Enter Name"), children: [
const SizedBox(height: 16), _labelText("Name"),
_textField(
_labelText("Email Id"), controller: nameController,
_textField(emailController, "Enter Email ID"), hint: "Enter Name",
const SizedBox(height: 16), fieldName: "Name",
),
_labelText("Phone No."), const SizedBox(height: 16),
_textField(phoneController, "Enter Phone Number",
keyboardType: TextInputType.phone), _labelText("Email Id"),
const SizedBox(height: 16), _textField(
controller: emailController,
_labelText("Requirement"), hint: "Enter Email ID",
_textField(requirementController, "Enter Requirement"), fieldName: "Email",
const SizedBox(height: 16), keyboardType: TextInputType.emailAddress,
validator: (value) {
_labelText("Note"), if (value == null || value.trim().isEmpty) {
_textField( return "Please enter your email";
noteController, }
"Write a short note", if (!RegExp(r'^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$')
maxLines: 5, .hasMatch(value.trim())) {
), return "Enter a valid email";
const SizedBox(height: 32), }
return null;
// Submit button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
// Submit action
FocusScope.of(context).unfocus();
}, },
style: ElevatedButton.styleFrom( ),
backgroundColor: AppColors.buttonColor, const SizedBox(height: 16),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16), _labelText("Phone No."),
shape: RoundedRectangleBorder( _textField(
borderRadius: BorderRadius.circular(28), controller: phoneController,
hint: "Enter Phone Number",
fieldName: "Phone Number",
keyboardType: TextInputType.phone,
validator: (value) {
if (value == null || value.trim().isEmpty) {
return "Please enter your phone number";
}
if (value.trim().length < 10) {
return "Enter a valid phone number";
}
return null;
},
),
const SizedBox(height: 16),
_labelText("Requirement"),
_textField(
controller: requirementController,
hint: "Enter Requirement",
fieldName: "Requirement",
),
const SizedBox(height: 16),
_labelText("Note"),
_textField(
controller: noteController,
hint: "Write a short note",
fieldName: "Note",
maxLines: 5,
),
const SizedBox(height: 32),
// Submit button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: enquiryProvider.isLoading
? null
: () async {
FocusScope.of(context).unfocus();
if (!_formKey.currentState!.validate()) return;
final success =
await enquiryProvider.submitEnquiry(
sessionId: widget.sessionId,
accId: widget.accId,
name: nameController.text.trim(),
email: emailController.text.trim(),
mobile: phoneController.text.trim(),
requirement: requirementController.text.trim(),
note: noteController.text.trim(),
);
if (!mounted) return;
if (success) {
CustomSnackBar.showSuccess(
context: context,
message: enquiryProvider.message ??
"Enquiry submitted successfully!",
);
_formKey.currentState!.reset();
nameController.clear();
emailController.clear();
phoneController.clear();
requirementController.clear();
noteController.clear();
} else {
CustomSnackBar.showError(
context: context,
message: enquiryProvider.message ??
"Failed to submit enquiry!",
);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
elevation: 0,
), ),
elevation: 0, child: enquiryProvider.isLoading
), ? const SizedBox(
child: const Text( height: 22,
"Submit", width: 22,
style: TextStyle( child: CircularProgressIndicator(
fontSize: 16, strokeWidth: 2.5,
fontFamily: "Plus Jakarta Sans", color: Colors.white,
fontWeight: FontWeight.w600, ),
)
: const Text(
"Submit",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
),
), ),
), ),
), ),
), ],
const SizedBox(height: 16), ),
],
), ),
), ),
), ),
...@@ -129,34 +226,69 @@ class _EnquiryScreenState extends State<EnquiryScreen> { ...@@ -129,34 +226,69 @@ class _EnquiryScreenState extends State<EnquiryScreen> {
); );
} }
/// Rounded Input Field /// Text Field with error message shown below box
Widget _textField( Widget _textField({
TextEditingController controller, required TextEditingController controller,
String hint, { required String hint,
TextInputType keyboardType = TextInputType.text, required String fieldName,
int maxLines = 1, TextInputType keyboardType = TextInputType.text,
}) { int maxLines = 1,
return Container( String? Function(String?)? validator,
decoration: BoxDecoration( }) {
color: Colors.white, return FormField<String>(
borderRadius: BorderRadius.circular(12), validator: validator ??
), (value) {
child: TextFormField( if (controller.text.trim().isEmpty) {
controller: controller, return '$fieldName is required';
keyboardType: keyboardType, }
maxLines: maxLines, return null;
decoration: InputDecoration( },
hintText: hint, builder: (field) {
hintStyle: TextStyle( return Column(
fontSize: 14, crossAxisAlignment: CrossAxisAlignment.start,
color: Colors.grey[400], children: [
fontFamily: "Plus Jakarta Sans", Container(
), decoration: BoxDecoration(
contentPadding: color: Color(0xffF6F6F8),
const EdgeInsets.symmetric(horizontal: 12, vertical: 14), borderRadius: BorderRadius.circular(12),
border: InputBorder.none, // border: Border.all(
), // color: field.hasError ? Colors.red : Colors.transparent,
), // width: 1,
// ),
),
child: TextFormField(
controller: controller,
keyboardType: keyboardType,
maxLines: maxLines,
onChanged: (_) => field.didChange(controller.text),
decoration: InputDecoration(
hintText: hint,
hintStyle: TextStyle(
fontSize: 14,
color: Colors.grey[400],
fontFamily: "Plus Jakarta Sans",
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
border: InputBorder.none,
),
),
),
if (field.hasError)
Padding(
padding: const EdgeInsets.only(top: 5, left: 4),
child: Text(
field.errorText ?? '',
style: const TextStyle(
color: Colors.red,
fontSize: 12,
fontFamily: "Plus Jakarta Sans",
),
),
),
],
);
},
); );
} }
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_rentals/Screens/HelpScreens/CreateTicketScreen.dart'; import 'package:gen_rentals/Screens/HelpScreens/OrderHelpScreen.dart';
import 'package:gen_rentals/Screens/HelpScreens/ProcessTicketScreen.dart'; import 'package:gen_rentals/Screens/HelpScreens/ProcessTicketScreen.dart';
import 'package:gen_rentals/Utility/Reusablewidgets.dart'; import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import '../../Notifier/HelpAndEnquiryProvider.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import 'package:provider/provider.dart';
class HelpScreen extends StatefulWidget { class HelpScreen extends StatefulWidget {
const HelpScreen({super.key}); final String sessionId;
final String accId;
HelpScreen({
super.key,
required this.sessionId,
required this.accId,
});
@override @override
State<HelpScreen> createState() => _HelpScreenState(); State<HelpScreen> createState() => _HelpScreenState();
} }
class _HelpScreenState extends State<HelpScreen> { class _HelpScreenState extends State<HelpScreen> {
// Dummy data for help - with proper null safety @override
void initState() {
super.initState();
/// ✅ Fetch ticket list on screen load
Future.microtask(() async {
final provider = Provider.of<HelpAndEnquiryProvider>(context, listen: false);
await provider.fetchTicketList(
sessionId: widget.sessionId,
accId: widget.accId,
);
});
}
// ✅ (unchanged)
final List<Map<String, dynamic>> createNewTickets = [ final List<Map<String, dynamic>> createNewTickets = [
{ {
'title': 'Payment Issues', 'title': 'Payment Issues',
...@@ -36,16 +59,6 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -36,16 +59,6 @@ class _HelpScreenState extends State<HelpScreen> {
}, },
]; ];
final List<Map<String, String>> processingTickets = [
{'title': 'Payment Issue', 'date': '25th Jan 2025', 'status': 'In Process'},
];
final List<Map<String, String>> closedTickets = [
{'title': 'Bill Payments', 'date': '25th Jan 2025'},
{'title': 'Others', 'date': '25th Jan 2025'},
{'title': 'Payment Issue', 'date': '25th Jan 2025'},
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return SafeArea(
...@@ -65,7 +78,7 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -65,7 +78,7 @@ class _HelpScreenState extends State<HelpScreen> {
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Text( const Text(
"Help?", "Help?",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
...@@ -77,145 +90,160 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -77,145 +90,160 @@ class _HelpScreenState extends State<HelpScreen> {
], ],
), ),
), ),
// Main content
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Create New Ticket Section
SectionHeading(
title: 'Create New Ticket',
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
),
const SizedBox(height: 12),
_buildCreateNewTicketSection(),
const SizedBox(height: 12),
// Processing Tickets Section // ✅ Provider Consumer used here
SectionHeading( body: Consumer<HelpAndEnquiryProvider>(
title: 'Processing Tickets', builder: (context, provider, _) {
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4), if (provider.isLoading) {
), return const Center(child: CircularProgressIndicator());
const SizedBox(height: 2), }
_buildProcessingTicketsSection(),
const SizedBox(height: 10), if (provider.errorMessage != null) {
return Center(
child: Text(provider.errorMessage!,
style: const TextStyle(color: Colors.red)),
);
}
// Closed Tickets Section final ticketData = provider.ticketListResponse?.tickets;
SectionHeading( final processingTickets = ticketData?.inProgress ?? [];
title: 'Closed Tickets', final closedTickets = ticketData?.closed ?? [];
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Create New Ticket Section
const SectionHeading(
title: 'Create New Ticket',
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
),
const SizedBox(height: 12),
_buildCreateNewTicketSection(),
const SizedBox(height: 12),
// Processing Tickets Section
const SectionHeading(
title: 'Processing Tickets',
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
),
const SizedBox(height: 2),
_buildProcessingTicketsSection(processingTickets),
const SizedBox(height: 10),
// Closed Tickets Section
const SectionHeading(
title: 'Closed Tickets',
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
),
const SizedBox(height: 2),
_buildClosedTicketsSection(closedTickets),
],
), ),
const SizedBox(height: 2), );
_buildClosedTicketsSection(), },
],
),
), ),
), ),
); );
} }
Widget _buildCreateNewTicketSection() { Widget _buildCreateNewTicketSection() {
return GridView.builder( return InkResponse(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.99,
),
itemCount: createNewTickets.length,
itemBuilder: (context, index) {
final ticket = createNewTickets[index];
final String title = ticket['title'] ?? 'Unknown';
final String description = ticket['description'] ?? '';
final String icon = ticket['icon'] ?? 'assets/svg/help_ic.svg';
final Color color = ticket['color'] ?? Colors.grey;
return _buildFeatureCard(
title: title,
description: description,
icon: icon,
color: color,
);
},
);
}
Widget _buildFeatureCard({
required String title,
required String description,
required String icon,
required Color color,
}) {
return GestureDetector(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => HelpTicketScreen(reason: title,)) MaterialPageRoute(builder: (context) => OrderHelpScreen(sessionId: widget.sessionId, accId: widget.accId))
); );
}, },
child: Container( child: Container(
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 1), padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 14),
child: Column( decoration: BoxDecoration(
crossAxisAlignment: CrossAxisAlignment.center, color: Colors.white,
borderRadius: BorderRadius.circular(14),
),
child: Row(
children: [ children: [
// Icon container SizedBox(
Container( height: 42,
width: 88, width: 42,
height: 88, child: SvgPicture.asset(
decoration: BoxDecoration( "assets/svg/help_ic.svg",
color: color.withOpacity(0.7), height: 30,
borderRadius: BorderRadius.circular(12), width: 30,
fit: BoxFit.contain,
), ),
child: Center( ),
child: SizedBox( const SizedBox(width: 12),
height: 40, const Expanded(
width: 40, child: Column(
child: SvgPicture.asset( crossAxisAlignment: CrossAxisAlignment.start,
icon, children: [
fit: BoxFit.fitWidth, Text(
"Get help for an order",
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontFamily: "Poppins",
fontSize: 14,
color: Colors.black,
),
), ),
), SizedBox(height: 4),
Text(
"Select an order",
style: TextStyle(
fontFamily: "Poppins",
fontSize: 12,
color: Colors.grey,
),
),
],
), ),
), ),
const SizedBox(height: 8),
// Title
SizedBox( SizedBox(
child: Text( height: 30,
title, width: 30,
textAlign: TextAlign.center, child: SvgPicture.asset(
style: TextStyle( "assets/svg/continue_ic.svg",
color: AppColors.nearDarkText, color: Color(0xFF000000),
fontSize: 14, height: 18,
fontWeight: FontWeight.w400, width: 18,
fontFamily: "Plus Jakarta Sans",
),
), ),
), ),
const SizedBox(height: 4),
], ],
), ),
), ),
); );
} }
Widget _buildProcessingTicketsSection() { /// ✅ Processing tickets from provider
Widget _buildProcessingTicketsSection(List<dynamic> tickets) {
if (tickets.isEmpty) {
return const Center(child: Text("No processing tickets"));
}
return Container( return Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: Column( child: Column(
children: processingTickets.map((ticket) { children: tickets.map((ticket) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 4), padding: const EdgeInsets.only(bottom: 4),
child: CommonListItem( child: CommonListItem(
title: ticket['title']!, orderId: ticket.ticketNumber ?? '',
date: ticket['date']!, title: ticket.type ?? 'Untitled',
status: ticket['status']!, date: ticket.date ?? '',
status: 'In Process',
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => ProcessTicketChatScreen()) MaterialPageRoute(
builder: (context) => TicketChatScreen(
sessionId: widget.sessionId,
accId: widget.accId,
ticketId: ticket.id,
status: "In Process",
),
),
); );
}, },
), ),
...@@ -225,19 +253,35 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -225,19 +253,35 @@ class _HelpScreenState extends State<HelpScreen> {
); );
} }
Widget _buildClosedTicketsSection() { /// ✅ Closed tickets from provider
Widget _buildClosedTicketsSection(List<dynamic> tickets) {
if (tickets.isEmpty) {
return const Center(child: Text("No closed tickets"));
}
return Container( return Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: Column( child: Column(
children: closedTickets.map((ticket) { children: tickets.map((ticket) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 4), padding: const EdgeInsets.only(bottom: 4),
child: CommonListItem( child: CommonListItem(
title: ticket['title']!, orderId: ticket.ticketNumber ?? '',
date: ticket['date']!, title: ticket.type ?? 'Untitled',
status: "", // Empty status for closed tickets date: ticket.date ?? '',
status: "",
onTap: () { onTap: () {
// Handle closed ticket tap Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TicketChatScreen(
sessionId: widget.sessionId,
accId: widget.accId,
ticketId: ticket.id,
status: "Closed",
),
),
);
}, },
), ),
); );
...@@ -247,7 +291,9 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -247,7 +291,9 @@ class _HelpScreenState extends State<HelpScreen> {
} }
} }
class CommonListItem extends StatelessWidget { class CommonListItem extends StatelessWidget {
final String orderId;
final String title; final String title;
final String date; final String date;
final String status; final String status;
...@@ -255,6 +301,7 @@ class CommonListItem extends StatelessWidget { ...@@ -255,6 +301,7 @@ class CommonListItem extends StatelessWidget {
const CommonListItem({ const CommonListItem({
Key? key, Key? key,
required this.orderId,
required this.title, required this.title,
required this.date, required this.date,
required this.status, required this.status,
...@@ -265,7 +312,7 @@ class CommonListItem extends StatelessWidget { ...@@ -265,7 +312,7 @@ class CommonListItem extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
const SizedBox(height: 4), const SizedBox(height: 6),
Material( Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
...@@ -276,10 +323,20 @@ class CommonListItem extends StatelessWidget { ...@@ -276,10 +323,20 @@ class CommonListItem extends StatelessWidget {
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 17),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(
"#${orderId}",
style: const TextStyle(
fontSize: 12,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w400,
color: AppColors.subtitleText,
),
),
SizedBox(width: 10,),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
...@@ -294,6 +351,7 @@ class CommonListItem extends StatelessWidget { ...@@ -294,6 +351,7 @@ class CommonListItem extends StatelessWidget {
), ),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
if(status.isNotEmpty)
Text( Text(
date, date,
style: TextStyle( style: TextStyle(
...@@ -323,6 +381,16 @@ class CommonListItem extends StatelessWidget { ...@@ -323,6 +381,16 @@ class CommonListItem extends StatelessWidget {
), ),
), ),
), ),
if(status.isEmpty)
Text(
date,
style: TextStyle(
fontSize: 12,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w400,
color: Colors.grey[600],
),
),
], ],
), ),
), ),
......
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_rentals/Screens/HelpScreens/ProcessTicketScreen.dart';
import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import '../../Models/DashboardResponse.dart';
import '../../Notifier/DashboardProvider.dart';
import '../../Notifier/HelpAndEnquiryProvider.dart';
import '../../Utility/AppColors.dart';
import 'package:provider/provider.dart';
import '../ProductsDetailScreen.dart';
import 'CreateTicketScreen.dart';
class OrderHelpScreen extends StatefulWidget {
final String sessionId;
final String accId;
OrderHelpScreen({
super.key,
required this.sessionId,
required this.accId,
});
@override
State<OrderHelpScreen> createState() => _OrderHelpScreenState();
}
class _OrderHelpScreenState extends State<OrderHelpScreen> {
@override
void initState() {
super.initState();
/// ✅ Fetch ticket list on screen load
Future.microtask(() async {
final provider = Provider.of<HelpAndEnquiryProvider>(context, listen: false);
await provider.fetchTicketList(
sessionId: widget.sessionId,
accId: widget.accId,
);
});
}
// ✅ (unchanged)
final List<Map<String, dynamic>> createNewTickets = [
{
'title': 'Payment Issues',
'description': 'Get help with payment related problems',
'icon': "assets/svg/rupee_coin_ic.svg",
'color': Color(0xFFFFEFBE),
},
{
'title': 'Bill Related Issues',
'description': 'Resolve bill and invoice matters',
'icon': "assets/svg/know_pay.svg",
'color': Color(0xFFCEF9FF),
},
{
'title': 'Other Issues',
'description': 'Any other support you need',
'icon': 'assets/svg/help_ic.svg',
'color': Color(0xFFE4E5FF),
},
];
@override
Widget build(BuildContext context) {
final dashboardProvider = Provider.of<DashboardProvider>(context);
final dashboardData = dashboardProvider.dashboardData;
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
double bottomPadding = MediaQuery.of(context).padding.bottom;
return SafeArea(
top: false,
child: Scaffold(
backgroundColor: AppColors.backgroundRegular,
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: Row(
children: [
InkResponse(
onTap: () => Navigator.pop(context, true),
child: SvgPicture.asset(
"assets/svg/continue_left_ic.svg",
height: 25,
),
),
const SizedBox(width: 10),
const Text(
"Help?",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
],
),
),
// ✅ Provider Consumer used here
body: Consumer<HelpAndEnquiryProvider>(
builder: (context, provider, _) {
if (provider.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (provider.errorMessage != null) {
return Center(
child: Text(provider.errorMessage!,
style: const TextStyle(color: Colors.red)),
);
}
final ticketData = provider.ticketListResponse?.tickets;
final processingTickets = ticketData?.inProgress ?? [];
final closedTickets = ticketData?.closed ?? [];
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Create New Ticket Section
const SectionHeading(
title: 'Select the order you are having issues with',
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Section Title
// Text(
// "Subscribed Orders",
// style: TextStyle(
// fontFamily: "Poppins",
// color: Colors.grey.shade800,
// fontSize: 18,
// fontWeight: FontWeight.w600,
// ),
// ),
const SizedBox(height: 16),
// Show loading or products list
if (dashboardProvider.isLoading && dashboardData == null)
const Center(
child: CircularProgressIndicator(),
)
else if (dashboardData?.orders == null || dashboardData!.orders!.isEmpty)
const Text(
"No products subscribed",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey,
fontSize: 14,
),
)
else
// List of subscribed products from API
Column(
children: dashboardData!.orders!.map((product) {
return Column(
children: [
InkResponse(
onTap: () =>_showReasonBottomSheet(),
child: _buildProductItemFromApi(product),
),
const SizedBox(height: 16),
],
);
}).toList(),
),
],
),
),
],
),
);
},
),
),
);
}
// Helper widget for product item from API data
Widget _buildProductItemFromApi(Orders product) {
final bool hasPending = product.hasPendingPayment == true;
final productList = product.products ?? [];
return Container(
margin: const EdgeInsets.symmetric(vertical: 6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.15),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
child: Stack(
children: [
// ===== Red Strip (Behind Card) =====
if (hasPending)
Positioned.fill(
top: null,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 45,
decoration: const BoxDecoration(
color: Color(0xFFFFE2E0),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
),
child: Row(
children: [
const SizedBox(width: 12),
const Icon(Icons.info_outline, color: Colors.red, size: 18),
const SizedBox(width: 6),
Expanded(
child: Text(
product.pendingPaymentText ??
"Payment Pending. Please Pay before incurring fines.",
style: const TextStyle(
fontFamily: "Poppins",
color: Colors.red,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(width: 12),
],
),
),
),
),
// ===== Main White Card =====
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Header Row (image, order id, date, badge)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: const Color(0xffF2F2F2),
borderRadius: BorderRadius.circular(16),
),
child: Image.network(
product.productImage ?? "",
height: 40,
width: 40,
fit: BoxFit.contain,
errorBuilder: (context, error, stack) =>
Image.asset('assets/images/gene_png.png',
height: 40, width: 40),
),
),
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"#${product.orderid ?? "0"}",
style: const TextStyle(
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 16,
fontWeight: FontWeight.w500,
height: 1.2,
),
),
Text(
product.rentedDate ?? "Rented date not available",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey.shade600,
fontSize: 12,
),
),
],
),
],
),
// ✅ Gradient expiry badge
if (product.expiringText != null &&
product.expiringText!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 6),
decoration: BoxDecoration(
gradient: _getGradientByColor(product.expiringInColor),
borderRadius: BorderRadius.circular(8),
),
child: Text(
product.expiringText!,
style: const TextStyle(
color: Colors.black87,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 6),
const Divider(),
/// ===== Product List (with +3 More on same line) =====
Builder(
builder: (context) {
final visibleItems = productList.take(2).toList();
final remaining = productList.length - visibleItems.length;
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Left side → Product list (bulleted)
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < visibleItems.length; i++)
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(width: 8),
const Text(
"• ",
style: TextStyle(color: Colors.black, fontSize: 16),
),
Expanded(
child: Text(
visibleItems[i],
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
),
],
),
),
],
),
),
// Right side → +x More (vertically centered)
if (remaining > 0)
Padding(
padding: const EdgeInsets.only(left: 8, right: 4),
child: Align(
alignment: Alignment.center,
child: Text(
"+$remaining More",
style: const TextStyle(
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
),
],
);
},
),
],
),
),
],
),
);
}
// Gradient helper
LinearGradient _getGradientByColor(String? color) {
switch (color) {
case "Red":
return const LinearGradient(
colors: [Color(0xFFFFE0E0), Color(0xFFFFC0C0)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
case "Green":
default:
return const LinearGradient(
colors: [Color(0xFFE9FFDD), Color(0xFFB5FFD1)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
}
}
void _showReasonBottomSheet() {
// Your existing bottom sheet implementation
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
builder: (context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 14),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Select Your Reason",
style: TextStyle(
fontSize: 18,
fontFamily: "Poppins",
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 24),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.99,
),
itemCount: createNewTickets.length,
itemBuilder: (context, index) {
final ticket = createNewTickets[index];
final String title = ticket['title'] ?? 'Unknown';
final String description = ticket['description'] ?? '';
final String icon = ticket['icon'] ?? 'assets/svg/help_ic.svg';
final Color color = ticket['color'] ?? Colors.grey;
return _buildFeatureCard(
title: title,
description: description,
icon: icon,
color: color,
);
},
),
const SizedBox(height: 24),
],
),
);
},
);
}
Widget _buildFeatureCard({
required String title,
required String description,
required String icon,
required Color color,
}) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HelpTicketScreen(reason: title,))
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 1),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Icon container
Container(
width: 88,
height: 88,
decoration: BoxDecoration(
color: color.withOpacity(0.7),
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: SizedBox(
height: 40,
width: 40,
child: SvgPicture.asset(
icon,
fit: BoxFit.fitWidth,
),
),
),
),
const SizedBox(height: 8),
// Title
SizedBox(
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.nearDarkText,
fontSize: 14,
fontWeight: FontWeight.w400,
fontFamily: "Plus Jakarta Sans",
),
),
),
const SizedBox(height: 4),
],
),
),
);
}
}
...@@ -100,7 +100,40 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -100,7 +100,40 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
], ],
), ),
), ),
backgroundColor: AppColors.backgroundRegular,
body: _buildBody(provider, screenHeight, bottomPadding), body: _buildBody(provider, screenHeight, bottomPadding),
bottomNavigationBar: Container(
height: 80,
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 10),
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailListScreen())
);
// Handle view bill action
FocusScope.of(context).unfocus();
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
elevation: 0,
),
child: const Text(
"View Bill",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
),
),
),
),
), ),
); );
}, },
...@@ -153,7 +186,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -153,7 +186,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
final order = provider.orderDetails!; final order = provider.orderDetails!;
return Container( return Container(
color: const Color(0xFFF3F3F3), color: AppColors.backgroundRegular,
height: screenHeight, height: screenHeight,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
...@@ -192,19 +225,20 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -192,19 +225,20 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
order.rentedDate ?? 'Date not available', order.rentedDate ?? 'Date not available',
style: const TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontFamily: "Poppins", fontFamily: "Poppins",
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.grey, color: AppColors.subtitleText,
), ),
), ),
const SizedBox(height: 14), const SizedBox(height: 14),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getExpiringColor(order.expiringInColor), gradient: _getGradientByColor(order.expiringInColor),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(8),
), ),
child: Text( child: Text(
order.expiringText ?? 'Expiring info not available', order.expiringText ?? 'Expiring info not available',
...@@ -212,7 +246,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -212,7 +246,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
fontSize: 12, fontSize: 12,
fontFamily: "Poppins", fontFamily: "Poppins",
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.white, color: Colors.black87,
), ),
), ),
), ),
...@@ -264,51 +298,29 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -264,51 +298,29 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
onTap: () => _showReasonBottomSheet(), onTap: () => _showReasonBottomSheet(),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset(
"assets/svg/have_compaints.svg",
height: 30,
width: 30,
),
SizedBox(width: 8,),
Text( Text(
"Need help with this order?", "Need help with this order?",
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontFamily: "Poppins", fontFamily: "Poppins",
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
color: Colors.grey, color: AppColors.amountText,
), ),
), ),
], ],
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// View Bill button // View Bill button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailListScreen())
);
// Handle view bill action
FocusScope.of(context).unfocus();
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
elevation: 0,
),
child: const Text(
"View Bill",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
),
),
),
),
], ],
), ),
) )
...@@ -347,12 +359,12 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -347,12 +359,12 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
children: [ children: [
// Product ID and Name // Product ID and Name
Text( Text(
product.idName ?? product.id ?? 'N/A', "#${product.idName}",
style: const TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontFamily: "Poppins", fontFamily: "Poppins",
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey, color: AppColors.amountText,
), ),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
...@@ -381,11 +393,11 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -381,11 +393,11 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
product.dispatchDate != null ? product.dispatchDate != null ?
"Dispatched On ${product.dispatchDate!}" : "Dispatched On ${product.dispatchDate!}" :
"Dispatch date not available", "Dispatch date not available",
style: const TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontFamily: "Poppins", fontFamily: "Poppins",
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.grey, color: AppColors.subtitleText,
), ),
), ),
), ),
...@@ -445,16 +457,21 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -445,16 +457,21 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
); );
} }
Color _getExpiringColor(String? colorString) { LinearGradient _getGradientByColor(String? color) {
if (colorString == null || colorString.isEmpty) { switch (color) {
return const Color(0xFFFFEBEB); // Default color case "Red":
} return const LinearGradient(
colors: [Color(0xFFFFE0E0), Color(0xFFFFC0C0)],
try { begin: Alignment.topLeft,
// Assuming colorString is in format like "FFFF5757" end: Alignment.bottomRight,
return Color(int.parse('FF$colorString', radix: 16)); );
} catch (e) { case "Green":
return const Color(0xFFFFEFEF); // Default color on error default:
return const LinearGradient(
colors: [Color(0xFFE9FFDD), Color(0xFFB5FFD1)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment