contact us details page api integration

This commit is contained in:
jayesh
2024-04-29 19:22:10 +05:30
parent 6c358ce8b6
commit f90f85d2c1
11 changed files with 882 additions and 382 deletions

View File

@@ -1,5 +1,3 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:traderscircuit/controller/contact_us_controller.dart';
@@ -8,14 +6,17 @@ import 'package:traderscircuit/controller/risk_profile_controller.dart';
import '../text.dart';
class CustomDropDownWidget extends StatefulWidget {
const CustomDropDownWidget(
{super.key,
required this.header,
required this.title,
required this.listData});
const CustomDropDownWidget({
super.key,
required this.header,
required this.title,
required this.listData,
required this.type,
});
final String header;
final String title;
final List<String> listData;
final String type;
@override
State<CustomDropDownWidget> createState() => _CustomDropDownWidgetState();
@@ -27,6 +28,9 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
RiskProfileController riskProfileController =
Get.put(RiskProfileController());
RxBool onDropTap = false.obs;
RxString selectedValue = "".obs;
void updateOrAddData(String key, String value) {
bool keyExists = false;
for (int i = 0; i < riskProfileController.selectedData.length; i++) {
@@ -45,6 +49,22 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
}
}
@override
void initState() {
if (widget.type == "risk") {
for (int i = 0; i < riskProfileController.selectedData.length; i++) {
Map<String, String> item = riskProfileController.selectedData[i];
if (item.containsKey(widget.title)) {
selectedValue.value =
riskProfileController.selectedData[i][widget.title]!;
break;
}
}
super.initState();
}
}
@override
Widget build(BuildContext context) {
return Obx(
@@ -58,8 +78,7 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
children: [
InkWell(
onTap: () {
contactUsController.onDropTap.value =
!contactUsController.onDropTap.value;
onDropTap.value = !onDropTap.value;
},
child: SizedBox(
width: 398,
@@ -90,7 +109,7 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
],
),
border: Border(
top: contactUsController.onDropTap.value
top: onDropTap.value
? const BorderSide(
width: 0, color: Color(0xFF393939))
: const BorderSide(
@@ -115,9 +134,13 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
left: 14,
top: 16,
child: Text(
contactUsController.selectedValue.isNotEmpty
? contactUsController.selectedValue.value
: widget.header,
widget.type == "risk"
? (selectedValue.isNotEmpty
? selectedValue.value
: widget.header)
: (contactUsController.selectedValue.isNotEmpty
? contactUsController.selectedValue.value
: widget.header),
style: const TextStyle(
color: Color(0xFFADADAD),
fontSize: 16,
@@ -130,7 +153,7 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
Positioned(
right: 14,
top: 16,
child: contactUsController.onDropTap.value
child: onDropTap.value
? const Icon(
Icons.keyboard_arrow_up_rounded,
color: Colors.white,
@@ -143,7 +166,7 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
),
),
),
!contactUsController.onDropTap.value
!onDropTap.value
? const SizedBox()
: Opacity(
opacity: 0.50,
@@ -174,10 +197,12 @@ class _CustomDropDownWidgetState extends State<CustomDropDownWidget> {
itemBuilder: (context, index) {
return InkWell(
onTap: () {
contactUsController.selectedValue.value =
widget.listData[index];
contactUsController.onDropTap.value =
!contactUsController.onDropTap.value;
widget.type == "risk"
? (selectedValue.value =
widget.listData[index])
: (contactUsController.selectedValue.value =
widget.listData[index]);
onDropTap.value = !onDropTap.value;
updateOrAddData(
widget.title, widget.listData[index]);
},

View File

@@ -58,4 +58,7 @@ class ApiUrls {
static String contactuscategory = "${base}get-ticket-categories";
static String addTicket = "${base}store-ticket";
static String getcontactus = "${base}get-ticket-data";
static String getcontactusDetails =
"${base}get-detailed-ticket-data-with-chats/";
static String sendMessage = "${base}send-message-to-admin";
}

View File

@@ -0,0 +1,56 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:traderscircuit/Utils/text.dart';
import '../view/onBoarding/splashScreen1.dart';
import 'Common/CommonAppBar.dart';
class ImagePreviewScreen extends StatefulWidget {
const ImagePreviewScreen({super.key});
@override
State<ImagePreviewScreen> createState() => _ImagePreviewScreenState();
}
class _ImagePreviewScreenState extends State<ImagePreviewScreen> {
String image = Get.arguments["image"];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar(
height: 75,
titleTxt: "",
customActionWidget: text16W400(""),
),
backgroundColor: Colors.black,
extendBody: true,
body: Stack(children: [
const CommonBlurLeft(),
const CommonBlurRight(),
Stack(children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 18, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
text25W600("Image Preview"),
const Gap(20),
CachedNetworkImage(
imageUrl: image,
placeholder: (context, url) {
return Center(
child: CircularProgressIndicator(
color: Colors.redAccent,
),
);
},
)
])))
])
]));
}
}

View File

@@ -3,6 +3,7 @@ import 'dart:io';
import 'package:get/get.dart';
import 'package:traderscircuit/model/ContactUsModel/contact_us_cat_model.dart';
import 'package:traderscircuit/model/ContactUsModel/contact_us_model.dart';
import 'package:intl/intl.dart';
class ContactUsController extends GetxController {
RxBool isLoading = true.obs;
@@ -17,31 +18,13 @@ class ContactUsController extends GetxController {
ContactUsCatModel contactCatModel = ContactUsCatModel();
ContactUsModel contactModel = ContactUsModel();
RxBool onDropTap = false.obs;
RxString selectedValue = "".obs;
RxList<dynamic> contactUsDetailsChatContent = [
{
"initial_name": "SM",
"date": "16 Feb 2024, 11 : 35PM",
"content": """ Dear Customer,
Thank you for contacting Traders Circuit
String formatedDateTimeMethod(String originalDateTimeString) {
DateTime dateTime = DateTime.parse(originalDateTimeString);
Your Service reference no is 18663765
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime.toLocal());
}
when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to
using 'Content here, content here', making it look like readable English.
Regards,
Centralised Service Desk
Traders Circuit""",
},
{
"initial_name": "AM",
"date": "16 Feb 2024, 11 : 35PM",
"content": "Thank You.......",
}
].obs;
RxList<dynamic> contactUsDetailsChatContent = [].obs;
}

View File

@@ -0,0 +1,210 @@
class TicketDetailsModel {
String? status;
int? statusCode;
String? message;
List<Data>? data;
TicketDetailsModel({this.status, this.statusCode, this.message, this.data});
TicketDetailsModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
statusCode = json['status_code'];
message = json['message'];
if (json['data'] != null) {
data = <Data>[];
json['data'].forEach((v) {
data!.add(Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['status'] = status;
data['status_code'] = statusCode;
data['message'] = message;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
int? id;
String? uniqueTicketId;
int? iamPrincipalXid;
int? ticketCategoryXid;
String? description;
int? status;
int? isActive;
String? createdAt;
TicketCategory? ticketCategory;
List<TicketFiles>? ticketFiles;
List<TicketResponses>? ticketResponses;
Data(
{this.id,
this.uniqueTicketId,
this.iamPrincipalXid,
this.ticketCategoryXid,
this.description,
this.status,
this.isActive,
this.createdAt,
this.ticketCategory,
this.ticketFiles,
this.ticketResponses});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
uniqueTicketId = json['unique_ticket_id'];
iamPrincipalXid = json['iam_principal_xid'];
ticketCategoryXid = json['ticket_category_xid'];
description = json['description'];
status = json['status'];
isActive = json['is_active'];
createdAt = json['created_at'];
ticketCategory = json['ticket_category'] != null
? TicketCategory.fromJson(json['ticket_category'])
: null;
if (json['ticket_files'] != null) {
ticketFiles = <TicketFiles>[];
json['ticket_files'].forEach((v) {
ticketFiles!.add(TicketFiles.fromJson(v));
});
}
if (json['ticket_responses'] != null) {
ticketResponses = <TicketResponses>[];
json['ticket_responses'].forEach((v) {
ticketResponses!.add(TicketResponses.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['unique_ticket_id'] = uniqueTicketId;
data['iam_principal_xid'] = iamPrincipalXid;
data['ticket_category_xid'] = ticketCategoryXid;
data['description'] = description;
data['status'] = status;
data['is_active'] = isActive;
data['created_at'] = createdAt;
if (ticketCategory != null) {
data['ticket_category'] = ticketCategory!.toJson();
}
if (ticketFiles != null) {
data['ticket_files'] = ticketFiles!.map((v) => v.toJson()).toList();
}
if (ticketResponses != null) {
data['ticket_responses'] =
ticketResponses!.map((v) => v.toJson()).toList();
}
return data;
}
}
class TicketResponses {
int? id;
int? iamPrincipalXid;
int? ticketXid;
int? isAdminResponse;
String? response;
String? createdAt;
String? updatedAt;
TicketResponses(
{this.id,
this.iamPrincipalXid,
this.ticketXid,
this.isAdminResponse,
this.response,
this.createdAt,
this.updatedAt});
TicketResponses.fromJson(Map<String, dynamic> json) {
id = json['id'];
iamPrincipalXid = json['iam_principal_xid'];
ticketXid = json['ticket_xid'];
isAdminResponse = json['is_admin_response'];
response = json['response'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['iam_principal_xid'] = iamPrincipalXid;
data['ticket_xid'] = ticketXid;
data['is_admin_response'] = isAdminResponse;
data['response'] = response;
data['created_at'] = createdAt;
data['updated_at'] = updatedAt;
return data;
}
}
class TicketCategory {
int? id;
String? name;
int? isActive;
String? createdAt;
TicketCategory({this.id, this.name, this.isActive, this.createdAt});
TicketCategory.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
isActive = json['is_active'];
createdAt = json['created_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
data['is_active'] = isActive;
data['created_at'] = createdAt;
return data;
}
}
class TicketFiles {
int? id;
int? iamPrincipalXid;
int? ticketXid;
String? file;
int? isActive;
String? createdAt;
TicketFiles(
{this.id,
this.iamPrincipalXid,
this.ticketXid,
this.file,
this.isActive,
this.createdAt});
TicketFiles.fromJson(Map<String, dynamic> json) {
id = json['id'];
iamPrincipalXid = json['iam_principal_xid'];
ticketXid = json['ticket_xid'];
file = json['file'];
isActive = json['is_active'];
createdAt = json['created_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['iam_principal_xid'] = iamPrincipalXid;
data['ticket_xid'] = ticketXid;
data['file'] = file;
data['is_active'] = isActive;
data['created_at'] = createdAt;
return data;
}
}

View File

@@ -120,7 +120,7 @@ class _SideMenuState extends State<SideMenu> {
height: 80.h,
decoration: ShapeDecoration(
image: DecorationImage(
image: NetworkImage(ProfileObj!.data == null
image: NetworkImage(ProfileObj == null
? ""
: ProfileObj!.data!.profilePhoto ?? ""),
fit: BoxFit.fill,

View File

@@ -1,14 +1,18 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/svg.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide FormData;
import 'package:traderscircuit/Utils/dialogs.dart';
import 'package:traderscircuit/Utils/image_preview_screen.dart';
import 'package:traderscircuit/controller/contact_us_controller.dart';
import 'package:traderscircuit/model/ContactUsModel/ticket_details_model.dart';
import 'package:traderscircuit/view_model/ContactUsApi/contact_us_api.dart';
import '../../../Utils/Common/CommonAppbar.dart';
import '../../../Utils/Common/CustomTextFormField.dart';
import '../../../Utils/Common/FilePicker.dart';
import '../../../Utils/Common/commonBotton.dart';
import '../../../Utils/text.dart';
import '../../onBoarding/splashScreen1.dart';
@@ -24,6 +28,27 @@ class ContactUsDetailsScreen extends StatefulWidget {
class _ContactUsDetailsScreenState extends State<ContactUsDetailsScreen> {
ContactUsController contactUsController = Get.put(ContactUsController());
TextEditingController queriesTextController = TextEditingController();
String id = Get.arguments["id"];
RxBool isLoading = true.obs;
TicketDetailsModel? ticketDetailsModel;
@override
void initState() {
contactUsController.contactUsDetailsChatContent.clear();
ContactUsApi().getContactUsDetailsData(id).then((value) {
ticketDetailsModel = TicketDetailsModel.fromJson(value.data);
for (var a in ticketDetailsModel!.data![0].ticketResponses!) {
contactUsController.contactUsDetailsChatContent.add({
"initial_name": "TS",
"date": contactUsController.formatedDateTimeMethod(a.createdAt!),
"content": a.response,
});
}
isLoading.value = false;
});
super.initState();
}
@override
Widget build(BuildContext context) {
final GlobalKey<FormState> queriesForm = GlobalKey<FormState>();
@@ -42,347 +67,467 @@ class _ContactUsDetailsScreenState extends State<ContactUsDetailsScreen> {
children: [
const CommonBlurLeft(),
const CommonBlurRight(),
Stack(children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 18, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
//physics: const NeverScrollableScrollPhysics(),
children: [
text25W600("Contact Us"),
const Gap(20),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
text22W600("#18663765"),
const Gap(10),
text16W500(
"RESOLVED",
clr: const Color(0xFF34C759),
),
],
),
text16W400("16 Feb 2024, 11 : 35 PM"),
],
),
const Gap(15),
const Divider(
thickness: 1,
color: Color(0xFF242424),
),
const Gap(20),
text16W600("Ticket Category"),
const Gap(10),
text16W400(
"It is a long established fact that a reader It is a long established fact that a reader It is a long established fact that a reader"),
contactUsController
.attachmentPathNameDetailsList.isEmpty
? const SizedBox()
: const Gap(15),
contactUsController
.attachmentPathNameDetailsList.isEmpty
? const SizedBox()
: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: contactUsController
.attachmentPathNameDetailsList.length,
itemBuilder: (ctx, index) {
return Container(
width: 1.sw,
height: 42.h,
margin: const EdgeInsets.symmetric(
vertical: 6,
),
decoration: BoxDecoration(
color: const Color(0xFF0C0C0C),
borderRadius:
BorderRadius.circular(4),
border: Border.all(
width: 1,
color: const Color(0xFF3A3A3A))),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
isLoading.value
? const Center(
child:
CircularProgressIndicator(color: Color(0xFF9A0000)),
)
: Stack(children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 18, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
//physics: const NeverScrollableScrollPhysics(),
children: [
text25W600("Contact Us"),
const Gap(20),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
text22W600(
"#${ticketDetailsModel!.data![0].uniqueTicketId}"),
const Gap(10),
text16W500(
ticketDetailsModel!.data![0].status ==
1
? "OPEN"
: ticketDetailsModel!
.data![0].status ==
2
? "CLOSED"
: "RESOLVED",
clr: ticketDetailsModel!
.data![0].status ==
1
? const Color(0xFFFFAD31)
: ticketDetailsModel!
.data![0].status ==
2
? const Color(0xFF95CCFF)
: const Color(0xFF34C759),
),
],
),
text16W400(contactUsController
.formatedDateTimeMethod(
ticketDetailsModel!
.data![0].createdAt!)),
],
),
const Gap(15),
const Divider(
thickness: 1,
color: Color(0xFF242424),
),
const Gap(20),
text16W600(ticketDetailsModel!
.data![0].ticketCategory!.name!),
const Gap(10),
text16W400(
ticketDetailsModel!.data![0].description!),
ListView.builder(
shrinkWrap: true,
itemCount: ticketDetailsModel!
.data![0].ticketFiles!.length,
itemBuilder: (ctx, index) {
return InkWell(
onTap: () {
Get.to(const ImagePreviewScreen(),
arguments: {
"image": ticketDetailsModel!
.data![0]
.ticketFiles![index]
.file,
});
},
child: Container(
width: 1.sw,
height: 42.h,
margin: const EdgeInsets.symmetric(
vertical: 6,
),
decoration: BoxDecoration(
color: const Color(0xFF0C0C0C),
borderRadius:
BorderRadius.circular(4),
border: Border.all(
width: 1,
color:
const Color(0xFF3A3A3A))),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Gap(6),
SvgPicture.asset(
"assets/images/svg/attachment_pin.svg"),
const Gap(6),
Container(
width: 0.7.sw,
child: FittedBox(
child: text12W400(
contactUsController
.attachmentPathNameDetailsList[
index]),
),
Row(
children: [
const Gap(6),
SvgPicture.asset(
"assets/images/svg/attachment_pin.svg"),
const Gap(6),
text12W400(
"Attachment ${index + 1}"),
],
),
],
),
GestureDetector(
onTap: () {
contactUsController
.attachmentPathNameDetailsList
.removeAt(index);
contactUsController
.attachmentFileDetailsList
.removeAt(index);
},
child: Container(
margin: const EdgeInsets.only(
right: 20),
child: SvgPicture.asset(
"assets/images/svg/cross_cancel.svg",
color:
const Color(0xFF818181),
width: 10,
height: 10,
),
)),
],
),
);
}),
contactUsController
.contactUsDetailsChatContent.isEmpty
? const SizedBox()
: const Gap(18),
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: contactUsController
.contactUsDetailsChatContent.length +
1,
itemBuilder: (ctx, index) {
return index ==
contactUsController
.contactUsDetailsChatContent.length
? Container(
margin: EdgeInsets.only(top: 20),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Stack(
),
);
}),
contactUsController
.attachmentPathNameDetailsList.isEmpty
? const SizedBox()
: const Gap(15),
contactUsController
.attachmentPathNameDetailsList.isEmpty
? const SizedBox()
: ListView.builder(
physics:
const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: contactUsController
.attachmentPathNameDetailsList
.length,
itemBuilder: (ctx, index) {
return Container(
width: 1.sw,
height: 42.h,
margin: const EdgeInsets.symmetric(
vertical: 6,
),
decoration: BoxDecoration(
color: const Color(0xFF0C0C0C),
borderRadius:
BorderRadius.circular(4),
border: Border.all(
width: 1,
color: const Color(
0xFF3A3A3A))),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
CustomTextFormField3(
texttype:
TextInputType.multiline,
hintText:
"Enter some text...",
textEditingController:
queriesTextController,
maxlines: 8,
validator: (value) {
if (value.isEmpty) {
return 'Enter your Content';
} else if (value
.toString()
.length <
30) {
return 'Content should be minimum 30 characters';
}
return null;
},
inputFormatters: [
LengthLimitingTextInputFormatter(
200),
Row(
children: [
const Gap(6),
SvgPicture.asset(
"assets/images/svg/attachment_pin.svg"),
const Gap(6),
Container(
width: 0.7.sw,
child: FittedBox(
child: text12W400(
contactUsController
.attachmentPathNameDetailsList[
index]),
),
),
],
),
Positioned(
bottom: 15,
left: 37,
right: 37,
child: SizedBox(
width: 200.w,
child: kycBtn(
text: "Close Ticket",
onTap: () {
CancelTicketBottomSheet()
.bottomSheet(
context);
},
bgClr: const Color(
0xFF111313),
borderClr: const Color(
0xFF990000),
),
),
)
],
),
contactUsController
.attachmentPathNameDetailsList
.length >=
3
? const SizedBox()
: const Gap(10),
contactUsController
.attachmentPathNameDetailsList
.length >=
3
? const SizedBox()
: InkWell(
onTap: () async {
var result =
await FilePickerMethod()
.pickFile();
if (result != null) {
contactUsController
.attachmentPathNameDetailsList
.clear();
for (var a in result) {
contactUsController
.attachmentFileDetailsList
.add(a);
}
for (var a
in contactUsController
.attachmentFileDetailsList) {
contactUsController
.attachmentPathNameDetailsList
.add(FilePickerMethod()
.extractFileName(
a?.path ??
''));
}
}
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
SvgPicture.asset(
"assets/images/svg/attachment_pin.svg"),
const Gap(6),
text12W400(
"Add Attachment (Max 32MB / Optional)"),
],
),
),
const Gap(20),
Padding(
padding:
const EdgeInsets.symmetric(
// horizontal: 10,
vertical: 20),
child: SizedBox(
width: Get.width,
child: kycBtn(
text: "Submit",
onTap: () {
final isValid = queriesForm
.currentState
?.validate();
if (isValid!) {
GestureDetector(
onTap: () {
contactUsController
.contactUsDetailsChatContent
.add({
"initial_name": "AM",
"date":
"16 Feb 2024, 11 : 35PM",
"content":
queriesTextController
.text,
});
queriesTextController
.clear();
}
},
bgClr:
const Color(0xFF6C0000),
borderClr:
const Color(0xFF990000),
),
),
),
],
),
)
: Container(
width: 1.sw,
margin: const EdgeInsets.symmetric(
vertical: 5,
),
decoration: BoxDecoration(
color: const Color(0xFF0C0C0C),
borderRadius:
BorderRadius.circular(8),
gradient: LinearGradient(
begin:
const Alignment(0.98, -0.21),
end: const Alignment(-0.98, 0.21),
colors: [
Colors.white.withOpacity(
0.03999999910593033),
Colors.white.withOpacity(
0.05999999865889549)
.attachmentPathNameDetailsList
.removeAt(index);
contactUsController
.attachmentFileDetailsList
.removeAt(index);
},
child: Container(
margin:
const EdgeInsets.only(
right: 20),
child: SvgPicture.asset(
"assets/images/svg/cross_cancel.svg",
color: const Color(
0xFF818181),
width: 10,
height: 10,
),
)),
],
),
border: Border.all(
width: 1,
color:
const Color(0xFF3A3A3A))),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
);
}),
contactUsController
.contactUsDetailsChatContent.isEmpty
? const SizedBox()
: const Gap(18),
ListView.builder(
physics:
const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: contactUsController
.contactUsDetailsChatContent
.length +
1,
itemBuilder: (ctx, index) {
return index ==
contactUsController
.contactUsDetailsChatContent
.length
? Container(
margin: EdgeInsets.only(top: 20),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
CircleAvatar(
radius: 18,
backgroundColor:
Colors.white,
child: Center(
child: text16W600(
contactUsController
.contactUsDetailsChatContent[
index]
["initial_name"],
clr: const Color(
0xFF535353)),
),
Stack(
children: [
CustomTextFormField3(
texttype: TextInputType
.multiline,
hintText:
"Enter some text...",
textEditingController:
queriesTextController,
maxlines: 8,
validator: (value) {
if (value.isEmpty) {
return 'Enter your Content';
} else if (value
.toString()
.length <
30) {
return 'Content should be minimum 30 characters';
}
return null;
},
inputFormatters: [
LengthLimitingTextInputFormatter(
200),
],
),
Positioned(
bottom: 15,
left: 37,
right: 37,
child: SizedBox(
width: 200.w,
child: kycBtn(
text:
"Close Ticket",
onTap: () {
CancelTicketBottomSheet()
.bottomSheet(
context);
},
bgClr: const Color(
0xFF111313),
borderClr:
const Color(
0xFF990000),
),
),
)
],
),
text14W500(
contactUsController
.contactUsDetailsChatContent[
index]["date"],
// contactUsController
// .attachmentPathNameDetailsList
// .length >=
// 3
// ? const SizedBox()
// : const Gap(10),
// contactUsController
// .attachmentPathNameDetailsList
// .length >=
// 3
// ? const SizedBox()
// : InkWell(
// onTap: () async {
// var result =
// await FilePickerMethod()
// .pickFile();
// if (result !=
// null) {
// contactUsController
// .attachmentPathNameDetailsList
// .clear();
// for (var a
// in result) {
// contactUsController
// .attachmentFileDetailsList
// .add(a);
// }
// for (var a
// in contactUsController
// .attachmentFileDetailsList) {
// contactUsController
// .attachmentPathNameDetailsList
// .add(FilePickerMethod().extractFileName(
// a?.path ??
// ''));
// }
// }
// },
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment
// .end,
// children: [
// SvgPicture.asset(
// "assets/images/svg/attachment_pin.svg"),
// const Gap(6),
// text12W400(
// "Add Attachment (Max 32MB / Optional)"),
// ],
// ),
// ),
const Gap(20),
Padding(
padding: const EdgeInsets
.symmetric(
// horizontal: 10,
vertical: 20),
child: SizedBox(
width: Get.width,
child: kycBtn(
text: "Submit",
onTap: () {
if (queriesTextController
.text.isEmpty) {
utils.showToast(
"Text is required");
} else {
ContactUsApi()
.addTicketMessageApi(
FormData
.fromMap({
"description":
queriesTextController
.text,
"ticket_xid":
ticketDetailsModel!
.data![0]
.id
}))
.then((value) {
Map<String,
dynamic>
responseData =
Map<String,
dynamic>.from(
value
.data);
utils.showToast(
responseData[
"message"]);
contactUsController
.contactUsDetailsChatContent
.add({
"initial_name":
"TS",
"date": contactUsController
.formatedDateTimeMethod(
responseData["data"]
[
"created_at"]),
"content": responseData[
"data"][
"response"],
});
queriesTextController
.clear();
});
}
},
bgClr: const Color(
0xFF6C0000),
borderClr: const Color(
0xFF990000),
),
),
),
],
),
const Gap(18),
text16W400(
contactUsController
.contactUsDetailsChatContent[
index]["content"],
)
],
),
));
}),
]),
),
)
]),
)
: Container(
width: 1.sw,
margin:
const EdgeInsets.symmetric(
vertical: 5,
),
decoration: BoxDecoration(
color:
const Color(0xFF0C0C0C),
borderRadius:
BorderRadius.circular(8),
gradient: LinearGradient(
begin: const Alignment(
0.98, -0.21),
end: const Alignment(
-0.98, 0.21),
colors: [
Colors.white.withOpacity(
0.03999999910593033),
Colors.white.withOpacity(
0.05999999865889549)
],
),
border: Border.all(
width: 1,
color: const Color(
0xFF3A3A3A))),
child: Padding(
padding:
const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisSize:
MainAxisSize.min,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
CircleAvatar(
radius: 18,
backgroundColor:
Colors.white,
child: Center(
child: text16W600(
contactUsController
.contactUsDetailsChatContent[
index][
"initial_name"],
clr: const Color(
0xFF535353)),
),
),
text14W500(
contactUsController
.contactUsDetailsChatContent[
index]["date"],
),
],
),
const Gap(18),
text16W400(
contactUsController
.contactUsDetailsChatContent[
index]["content"],
)
],
),
));
}),
]),
),
)
]),
],
),
),

View File

@@ -25,6 +25,8 @@ class ContactUsMainScreen extends StatefulWidget {
class _ContactUsMainScreenState extends State<ContactUsMainScreen> {
ContactUsController contactUsController = Get.put(ContactUsController());
RxBool isEmpty = false.obs;
@override
void initState() {
contactUsController.isLoading.value == true;
@@ -33,9 +35,15 @@ class _ContactUsMainScreenState extends State<ContactUsMainScreen> {
ContactUsCatModel.fromJson(value.data);
ContactUsApi().getContactUsData().then((value) {
contactUsController.contactModel = ContactUsModel.fromJson(value.data);
Map<String, dynamic> responseData =
Map<String, dynamic>.from(value.data);
if (responseData["message"] == "Data not found.") {
isEmpty.value = true;
} else {
contactUsController.contactModel =
ContactUsModel.fromJson(value.data);
}
contactUsController.isLoading.value = false;
log(contactUsController.isLoading.value.toString());
});
});
@@ -83,8 +91,8 @@ class _ContactUsMainScreenState extends State<ContactUsMainScreen> {
child: CircularProgressIndicator(
color: Colors.redAccent,
))
: contactUsController.contactModel.data!.isEmpty
? Text("No Data Available")
: isEmpty.value
? Center(child: text18W800("No Data Available"))
: ListView(
physics: const NeverScrollableScrollPhysics(),
children: [
@@ -167,11 +175,17 @@ Widget ticketCardWidget(index, type) {
onTap: () {
contactUsController.attachmentFileDetailsList.clear();
contactUsController.attachmentPathNameDetailsList.clear();
Get.toNamed(RouteName.contactUsMainDetails);
Get.toNamed(RouteName.contactUsMainDetails, arguments: {
"id": contactUsController.contactModel.data!
.elementAt(index)
.id
.toString()
});
},
child: Container(
width: Get.width,
height: 190,
height: 195,
margin: EdgeInsets.only(bottom: 18, top: index == 0 ? 15 : 0),
decoration: ShapeDecoration(
gradient: LinearGradient(
@@ -255,10 +269,11 @@ Widget ticketCardWidget(index, type) {
],
),
const Gap(10),
text16W600(contactUsController.contactModel.data!
.elementAt(index)
.createdAt
.toString()),
text16W600(contactUsController.formatedDateTimeMethod(
contactUsController.contactModel.data!
.elementAt(index)
.createdAt
.toString())),
const Gap(5),
text16W400(contactUsController.contactModel.data!
.elementAt(index)

View File

@@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -8,7 +10,6 @@ import 'package:get/get.dart' hide MultipartFile, FormData;
import 'package:traderscircuit/Utils/base_manager.dart';
import 'package:traderscircuit/Utils/text.dart';
import 'package:traderscircuit/Utils/utils.dart';
import 'package:traderscircuit/resources/routes/route_name.dart';
import 'package:traderscircuit/view_model/ContactUsApi/contact_us_api.dart';
import '../../../Utils/Common/CustomTextFormField.dart';
@@ -16,6 +17,7 @@ import '../../../Utils/Common/FilePicker.dart';
import '../../../Utils/Common/commonBotton.dart';
import '../../../Utils/Common/custom_drop_down.dart';
import '../../../controller/contact_us_controller.dart';
import '../../../model/ContactUsModel/contact_us_model.dart';
import 'ticket_confirmed_bottom_sheet.dart';
import 'package:path/path.dart' as path;
@@ -65,6 +67,20 @@ class CreateTicketBottomSheet {
final isValid = _addTicketform.currentState?.validate();
if (isValid!) {
for (var item in contactUsController.contactCatModel.data!) {
log(item.name!);
log(contactUsController.selectedValue.toString());
if (item.name == contactUsController.selectedValue.toString()) {
ticketid = item.id;
break; // Stop loop once match is found
}
}
log({
"description": descriptionController.text,
"ticket_category_xid": ticketid,
"files[]": ticketlist,
}.toString());
Utils.loader();
FormData formdata = FormData.fromMap({
"description": descriptionController.text,
@@ -75,6 +91,13 @@ class CreateTicketBottomSheet {
final resp = await ContactUsApi().addTicketApi(formdata);
if (resp.status == ResponseStatus.SUCCESS) {
Get.back();
contactUsController.isLoading.value = true;
ContactUsApi().getContactUsData().then((value) {
contactUsController.contactModel =
ContactUsModel.fromJson(value.data);
contactUsController.isLoading.value = false;
});
print("success");
TicketConfirmedBottomSheet().bottomSheet(context);
} else if (resp.status == ResponseStatus.PRIVATE) {
@@ -135,6 +158,7 @@ class CreateTicketBottomSheet {
header: "Choose your query",
listData: namesList,
title: "",
type: "ticket",
),
const Gap(14),
Stack(

View File

@@ -202,6 +202,7 @@ class _UpdateRiskProfileState extends State<UpdateRiskProfile> {
header: headerText,
listData: dropHeader[index][tilte]!,
title: tilte,
type: "risk",
),
SizedBox(
height: 35.h,

View File

@@ -59,4 +59,42 @@ class ContactUsApi {
}
return response;
}
Future<ResponseData<dynamic>> getContactUsDetailsData(
String id,
) async {
final response = await NetworkApiServices()
.getApi(ApiUrls.getcontactusDetails + id, isAuth: true);
log(response.data.toString());
if (response.status == ResponseStatus.SUCCESS) {
Map<String, dynamic> responseData =
Map<String, dynamic>.from(response.data);
if (responseData['status'] == "success") {
return response;
} else {
return ResponseData<dynamic>(
responseData['message'], ResponseStatus.FAILED);
}
}
return response;
}
Future<ResponseData<dynamic>> addTicketMessageApi(data) async {
final response = await NetworkApiServices().postApi(
data,
ApiUrls.sendMessage,
);
if (response.status == ResponseStatus.SUCCESS) {
Map<String, dynamic> responseData =
Map<String, dynamic>.from(response.data);
if (responseData['status'] == "success") {
print("token is $response");
} else {
return ResponseData<dynamic>(
responseData['message'], ResponseStatus.FAILED);
}
}
return response;
}
}