From f90f85d2c1a500f2ef9a240bd843e3a2b0a09552 Mon Sep 17 00:00:00 2001 From: jayesh Date: Mon, 29 Apr 2024 19:22:10 +0530 Subject: [PATCH] contact us details page api integration --- lib/Utils/Common/custom_drop_down.dart | 63 +- lib/Utils/api_urls.dart | 3 + lib/Utils/image_preview_screen.dart | 56 ++ lib/controller/contact_us_controller.dart | 29 +- .../ContactUsModel/ticket_details_model.dart | 210 +++++ lib/view/Sidemenu/Sidemenu.dart | 2 +- .../contactUs/contact_us_details.dart | 801 +++++++++++------- .../Sidemenu/contactUs/contact_us_main.dart | 35 +- .../contactUs/create_ticket_bottom_sheet.dart | 26 +- lib/view/login/UpdateRiskProfile.dart | 1 + .../ContactUsApi/contact_us_api.dart | 38 + 11 files changed, 882 insertions(+), 382 deletions(-) create mode 100644 lib/Utils/image_preview_screen.dart create mode 100644 lib/model/ContactUsModel/ticket_details_model.dart diff --git a/lib/Utils/Common/custom_drop_down.dart b/lib/Utils/Common/custom_drop_down.dart index d01cbf5..2493035 100644 --- a/lib/Utils/Common/custom_drop_down.dart +++ b/lib/Utils/Common/custom_drop_down.dart @@ -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 listData; + final String type; @override State createState() => _CustomDropDownWidgetState(); @@ -27,6 +28,9 @@ class _CustomDropDownWidgetState extends State { 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 { } } + @override + void initState() { + if (widget.type == "risk") { + for (int i = 0; i < riskProfileController.selectedData.length; i++) { + Map 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 { 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 { ], ), 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 { 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 { 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 { ), ), ), - !contactUsController.onDropTap.value + !onDropTap.value ? const SizedBox() : Opacity( opacity: 0.50, @@ -174,10 +197,12 @@ class _CustomDropDownWidgetState extends State { 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]); }, diff --git a/lib/Utils/api_urls.dart b/lib/Utils/api_urls.dart index 8a97cda..1904f5c 100644 --- a/lib/Utils/api_urls.dart +++ b/lib/Utils/api_urls.dart @@ -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"; } diff --git a/lib/Utils/image_preview_screen.dart b/lib/Utils/image_preview_screen.dart new file mode 100644 index 0000000..4a0718b --- /dev/null +++ b/lib/Utils/image_preview_screen.dart @@ -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 createState() => _ImagePreviewScreenState(); +} + +class _ImagePreviewScreenState extends State { + 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, + ), + ); + }, + ) + ]))) + ]) + ])); + } +} diff --git a/lib/controller/contact_us_controller.dart b/lib/controller/contact_us_controller.dart index 34559a5..569309e 100644 --- a/lib/controller/contact_us_controller.dart +++ b/lib/controller/contact_us_controller.dart @@ -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 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 contactUsDetailsChatContent = [].obs; } diff --git a/lib/model/ContactUsModel/ticket_details_model.dart b/lib/model/ContactUsModel/ticket_details_model.dart new file mode 100644 index 0000000..346ad5a --- /dev/null +++ b/lib/model/ContactUsModel/ticket_details_model.dart @@ -0,0 +1,210 @@ +class TicketDetailsModel { + String? status; + int? statusCode; + String? message; + List? data; + + TicketDetailsModel({this.status, this.statusCode, this.message, this.data}); + + TicketDetailsModel.fromJson(Map json) { + status = json['status']; + statusCode = json['status_code']; + message = json['message']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data!.add(Data.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + 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; + List? 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 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 = []; + json['ticket_files'].forEach((v) { + ticketFiles!.add(TicketFiles.fromJson(v)); + }); + } + if (json['ticket_responses'] != null) { + ticketResponses = []; + json['ticket_responses'].forEach((v) { + ticketResponses!.add(TicketResponses.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + 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 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 toJson() { + final Map data = {}; + 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 json) { + id = json['id']; + name = json['name']; + isActive = json['is_active']; + createdAt = json['created_at']; + } + + Map toJson() { + final Map data = {}; + 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 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 toJson() { + final Map data = {}; + 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; + } +} diff --git a/lib/view/Sidemenu/Sidemenu.dart b/lib/view/Sidemenu/Sidemenu.dart index 0d11845..bf91a5c 100644 --- a/lib/view/Sidemenu/Sidemenu.dart +++ b/lib/view/Sidemenu/Sidemenu.dart @@ -120,7 +120,7 @@ class _SideMenuState extends State { height: 80.h, decoration: ShapeDecoration( image: DecorationImage( - image: NetworkImage(ProfileObj!.data == null + image: NetworkImage(ProfileObj == null ? "" : ProfileObj!.data!.profilePhoto ?? ""), fit: BoxFit.fill, diff --git a/lib/view/Sidemenu/contactUs/contact_us_details.dart b/lib/view/Sidemenu/contactUs/contact_us_details.dart index 641d7a6..5905ed1 100644 --- a/lib/view/Sidemenu/contactUs/contact_us_details.dart +++ b/lib/view/Sidemenu/contactUs/contact_us_details.dart @@ -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 { 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 queriesForm = GlobalKey(); @@ -42,347 +67,467 @@ class _ContactUsDetailsScreenState extends State { 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 + responseData = + Map.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"], + ) + ], + ), + )); + }), + ]), + ), + ) + ]), ], ), ), diff --git a/lib/view/Sidemenu/contactUs/contact_us_main.dart b/lib/view/Sidemenu/contactUs/contact_us_main.dart index c26a374..ce6bd2b 100644 --- a/lib/view/Sidemenu/contactUs/contact_us_main.dart +++ b/lib/view/Sidemenu/contactUs/contact_us_main.dart @@ -25,6 +25,8 @@ class ContactUsMainScreen extends StatefulWidget { class _ContactUsMainScreenState extends State { ContactUsController contactUsController = Get.put(ContactUsController()); + RxBool isEmpty = false.obs; + @override void initState() { contactUsController.isLoading.value == true; @@ -33,9 +35,15 @@ class _ContactUsMainScreenState extends State { ContactUsCatModel.fromJson(value.data); ContactUsApi().getContactUsData().then((value) { - contactUsController.contactModel = ContactUsModel.fromJson(value.data); + Map responseData = + Map.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 { 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) diff --git a/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart b/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart index 2402585..dbe75c7 100644 --- a/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart +++ b/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart @@ -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( diff --git a/lib/view/login/UpdateRiskProfile.dart b/lib/view/login/UpdateRiskProfile.dart index e06be40..5a84500 100644 --- a/lib/view/login/UpdateRiskProfile.dart +++ b/lib/view/login/UpdateRiskProfile.dart @@ -202,6 +202,7 @@ class _UpdateRiskProfileState extends State { header: headerText, listData: dropHeader[index][tilte]!, title: tilte, + type: "risk", ), SizedBox( height: 35.h, diff --git a/lib/view_model/ContactUsApi/contact_us_api.dart b/lib/view_model/ContactUsApi/contact_us_api.dart index 67020d8..acb6c85 100644 --- a/lib/view_model/ContactUsApi/contact_us_api.dart +++ b/lib/view_model/ContactUsApi/contact_us_api.dart @@ -59,4 +59,42 @@ class ContactUsApi { } return response; } + + Future> getContactUsDetailsData( + String id, + ) async { + final response = await NetworkApiServices() + .getApi(ApiUrls.getcontactusDetails + id, isAuth: true); + log(response.data.toString()); + if (response.status == ResponseStatus.SUCCESS) { + Map responseData = + Map.from(response.data); + if (responseData['status'] == "success") { + return response; + } else { + return ResponseData( + responseData['message'], ResponseStatus.FAILED); + } + } + return response; + } + + Future> addTicketMessageApi(data) async { + final response = await NetworkApiServices().postApi( + data, + ApiUrls.sendMessage, + ); + + if (response.status == ResponseStatus.SUCCESS) { + Map responseData = + Map.from(response.data); + if (responseData['status'] == "success") { + print("token is $response"); + } else { + return ResponseData( + responseData['message'], ResponseStatus.FAILED); + } + } + return response; + } }