You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

445 lines
19 KiB

  1. // ignore_for_file: public_member_api_docs, sort_constructors_first
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_gen/gen_l10n/app_localizations.dart';
  4. import 'package:go_router/go_router.dart';
  5. import 'package:provider/provider.dart';
  6. import 'package:qadirneyriz/diologs/diolog_add_location.dart';
  7. import 'package:qadirneyriz/diologs/diolog_add_subject.dart';
  8. import 'package:qadirneyriz/global/global_class/selected_item.dart';
  9. import 'package:qadirneyriz/global/global_state/global_state.dart';
  10. import 'package:qadirneyriz/screens/meeting_edit/state.dart';
  11. import 'package:qadirneyriz/screens/private_meeting_edit/state.dart';
  12. import 'package:qadirneyriz/utils/enums/status.dart';
  13. import 'package:qadirneyriz/utils/tools/tools.dart';
  14. import 'package:qadirneyriz/widgets/ExpansionTileCustom.dart';
  15. import 'package:qadirneyriz/widgets/checkBox_inTile.dart';
  16. import 'package:qadirneyriz/widgets/custom_appbar.dart';
  17. import 'package:qadirneyriz/widgets/custom_button.dart';
  18. import 'package:qadirneyriz/widgets/custom_textfield.dart';
  19. import 'package:qadirneyriz/widgets/empty_widget.dart';
  20. import 'package:qadirneyriz/widgets/error_widget.dart';
  21. import 'package:qadirneyriz/widgets/loading_widget.dart';
  22. import 'package:qadirneyriz/widgets/picker.dart';
  23. class EditPrivateMeetingScreen extends StatefulWidget {
  24. final int id;
  25. const EditPrivateMeetingScreen({
  26. Key? key,
  27. required this.id,
  28. }) : super(key: key);
  29. @override
  30. State<EditPrivateMeetingScreen> createState() =>
  31. _EditPrivateMeetingScreenState();
  32. }
  33. class _EditPrivateMeetingScreenState extends State<EditPrivateMeetingScreen> {
  34. final _formKey = GlobalKey<FormState>(); // Key for form validation
  35. // all states we have
  36. late EditPrivateMeetingState privateMeetingEditState;
  37. late GlobalState globalState;
  38. TextEditingController visitorName = TextEditingController();
  39. TextEditingController visitorPhoneController = TextEditingController();
  40. TextEditingController visitorRole = TextEditingController();
  41. TextEditingController visitorCompanyNameController = TextEditingController();
  42. @override
  43. void initState() {
  44. super.initState();
  45. //set states
  46. privateMeetingEditState =
  47. Provider.of<EditPrivateMeetingState>(context, listen: false);
  48. globalState = Provider.of<GlobalState>(context, listen: false);
  49. Future.delayed(Duration.zero, () async {
  50. // get items
  51. await privateMeetingEditState.getOnePrivateMeeting(id: widget.id);
  52. await globalState.getAllFiltersItems(refresh: true);
  53. // set variables
  54. if (privateMeetingEditState.onePrivateMeetingStatus[widget.id] ==
  55. Status.ready &&
  56. globalState.allFiltersStatus == Status.ready) {
  57. privateMeetingEditState.setAllVariablesAtStart(id: widget.id);
  58. visitorName.text = privateMeetingEditState.createdName;
  59. visitorPhoneController.text =
  60. privateMeetingEditState.createdPhoneNumber;
  61. visitorRole.text = privateMeetingEditState.createdRole;
  62. visitorCompanyNameController.text =
  63. privateMeetingEditState.createdCompanyName;
  64. }
  65. });
  66. }
  67. @override
  68. Widget build(BuildContext context) {
  69. return Scaffold(
  70. body: Consumer2<EditPrivateMeetingState, GlobalState>(
  71. builder: (context, meetingEditState, globalState, child) {
  72. return CustomScrollView(
  73. slivers: <Widget>[
  74. CustomAppbar(
  75. title: AppLocalizations.of(context)!.editprivatemeeting),
  76. SliverFillRemaining(
  77. child: content(context, meetingEditState, globalState)),
  78. ],
  79. );
  80. },
  81. ),
  82. );
  83. }
  84. Widget content(BuildContext context, EditPrivateMeetingState meetingEditState,
  85. GlobalState globalState) {
  86. final itemOnePrivateMeetingStatus =
  87. meetingEditState.onePrivateMeetingStatus[widget.id];
  88. if (itemOnePrivateMeetingStatus == Status.ready &&
  89. globalState.allFiltersStatus == Status.ready) {
  90. final itemInOneMeeting =
  91. meetingEditState.onePrivateMeetingModel![widget.id]!;
  92. return Padding(
  93. // This is now wrapped inside SliverToBoxAdapter
  94. padding: const EdgeInsets.all(16.0),
  95. child: Form(
  96. key: _formKey,
  97. child: SingleChildScrollView(
  98. child: Column(
  99. crossAxisAlignment: CrossAxisAlignment.start,
  100. children: [
  101. CustomTextField(
  102. paddingHarizon: 0,
  103. paddingVertical: 10,
  104. label: AppLocalizations.of(context)!.visitorname,
  105. hintText: '',
  106. textEditingController: visitorName,
  107. textInputType: TextInputType.text),
  108. CustomTextField(
  109. paddingHarizon: 0,
  110. paddingVertical: 10,
  111. label: AppLocalizations.of(context)!.visitorrole,
  112. hintText: '',
  113. textEditingController: visitorRole,
  114. textInputType: TextInputType.text),
  115. CustomTextField(
  116. paddingHarizon: 0,
  117. paddingVertical: 10,
  118. label: AppLocalizations.of(context)!.phonenumber,
  119. hintText: '',
  120. textEditingController: visitorPhoneController,
  121. textInputType: TextInputType.phone),
  122. CustomTextField(
  123. paddingHarizon: 0,
  124. paddingVertical: 10,
  125. label: AppLocalizations.of(context)!.companyname,
  126. hintText: '',
  127. textEditingController: visitorCompanyNameController,
  128. textInputType: TextInputType.text),
  129. // subject ExpansionTile
  130. Padding(
  131. padding: const EdgeInsets.symmetric(vertical: 8.0),
  132. child: ExpansionTileCustom(
  133. isForm: true,
  134. subTitile: AppLocalizations.of(context)!.meetingsubject,
  135. title: meetingEditState.selectedSubject.id != null
  136. ? meetingEditState.selectedSubject.text ?? ''
  137. : meetingEditState.onePrivateMeetingModel![widget.id]!
  138. .subject!.subject ??
  139. '',
  140. widgets: <Widget>[
  141. CheckBoxInTile(
  142. text: AppLocalizations.of(context)!.newsubject,
  143. onTap: () async {
  144. await showDialog(
  145. context: context, // این باید کانتکست فعلی باشد
  146. builder: (BuildContext context) {
  147. return AddSubjectDiolog();
  148. },
  149. );
  150. },
  151. hasIcon: true,
  152. backColor: Colors.white,
  153. textColor: Colors.black.withOpacity(.5),
  154. ),
  155. Column(
  156. children: globalState.subjectsModel!.map((subject) {
  157. bool isSelected =
  158. meetingEditState.selectedSubject.id == subject.id;
  159. return CheckBoxInTile(
  160. backColor:
  161. isSelected ? Color(0xff06CF64) : Colors.white,
  162. textColor: isSelected ? Colors.white : Colors.black,
  163. text: subject.subject ?? '',
  164. hasIcon: false,
  165. onTap: () {
  166. setState(() {
  167. meetingEditState.selectedSubject = ItemSelected(
  168. text: subject.subject ?? '',
  169. id: subject.id ??
  170. 0); // Update selected location
  171. });
  172. },
  173. );
  174. }).toList(),
  175. ),
  176. ],
  177. ),
  178. ),
  179. // Date Picker
  180. Padding(
  181. padding: const EdgeInsets.symmetric(vertical: 8.0),
  182. child: PickerCustom(
  183. showDate: meetingEditState.fromDate != null
  184. ? meetingEditState.fromDate ?? ''
  185. : itemInOneMeeting.dateJalali ?? '',
  186. onTap: () {
  187. showDialog(
  188. context: context,
  189. builder: (context) {
  190. return Dialog(
  191. child: Tools.shamsiDateCalendarWidget(
  192. context,
  193. (newDate) {
  194. String fromDateString =
  195. '${newDate.year}/${newDate.month}/${newDate.day}';
  196. meetingEditState.setFromDate(
  197. fromDateString); // Update the selected date
  198. },
  199. ),
  200. );
  201. },
  202. );
  203. },
  204. isForm: true,
  205. title: AppLocalizations.of(context)!.date,
  206. ),
  207. ),
  208. // From and To time Range Pickers
  209. Padding(
  210. padding: const EdgeInsets.symmetric(vertical: 15.0),
  211. child: Row(
  212. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  213. crossAxisAlignment: CrossAxisAlignment.end,
  214. children: [
  215. PickerCustom(
  216. showDate: meetingEditState.selectedStartTime != null
  217. ? Tools.formatTime(
  218. meetingEditState.selectedStartTime!.hour,
  219. meetingEditState.selectedStartTime!.minute)
  220. : itemInOneMeeting.azHour ?? '',
  221. onTap: () async {
  222. TimeOfDay? picked = await showTimePicker(
  223. context: context,
  224. initialTime: meetingEditState.selectedStartTime!,
  225. );
  226. if (picked != null &&
  227. picked != meetingEditState.selectedStartTime)
  228. setState(() {
  229. meetingEditState.selectedStartTime = picked;
  230. });
  231. },
  232. isForm: true,
  233. icon: Icons.access_time_outlined,
  234. title: AppLocalizations.of(context)!.clock,
  235. ),
  236. Text(AppLocalizations.of(context)!.to),
  237. PickerCustom(
  238. showDate: meetingEditState.selectedEndTime != null
  239. ? Tools.formatTime(
  240. meetingEditState.selectedEndTime!.hour,
  241. meetingEditState.selectedEndTime!.minute)
  242. : itemInOneMeeting.taHour ?? '',
  243. isForm: true,
  244. icon: Icons.access_time_outlined,
  245. onTap: () async {
  246. TimeOfDay? picked = await showTimePicker(
  247. context: context,
  248. initialTime: meetingEditState.selectedEndTime!,
  249. );
  250. if (picked != null &&
  251. picked != meetingEditState.selectedEndTime)
  252. setState(() {
  253. meetingEditState.selectedEndTime = picked;
  254. });
  255. },
  256. ),
  257. ],
  258. ),
  259. ),
  260. // Location ExpansionTile
  261. Padding(
  262. padding: const EdgeInsets.symmetric(vertical: 8.0),
  263. child: ExpansionTileCustom(
  264. isForm: true,
  265. subTitile: AppLocalizations.of(context)!.location,
  266. title: meetingEditState.selectedLocation.id != null
  267. ? meetingEditState.selectedLocation.text ?? ''
  268. : itemInOneMeeting.location!.address ?? '',
  269. widgets: <Widget>[
  270. CheckBoxInTile(
  271. text: AppLocalizations.of(context)!.newlocation,
  272. onTap: () async {
  273. await showDialog(
  274. context: context, // این باید کانتکست فعلی باشد
  275. builder: (BuildContext context) {
  276. return AddLocationDiolog();
  277. },
  278. );
  279. },
  280. hasIcon: true,
  281. backColor: Colors.white,
  282. textColor: Colors.black.withOpacity(.5),
  283. ),
  284. Column(
  285. children: globalState.locationsModel!.map((location) {
  286. bool isSelected =
  287. meetingEditState.selectedLocation.id ==
  288. location.id;
  289. return CheckBoxInTile(
  290. backColor:
  291. isSelected ? Color(0xff06CF64) : Colors.white,
  292. textColor: isSelected ? Colors.white : Colors.black,
  293. text: location.address ?? '',
  294. hasIcon: false,
  295. onTap: () {
  296. setState(() {
  297. meetingEditState.selectedLocation =
  298. ItemSelected(
  299. text: location.address,
  300. id: location
  301. .id); // Update selected location
  302. });
  303. },
  304. );
  305. }).toList(),
  306. ),
  307. ],
  308. ),
  309. ),
  310. // Final ExpansionTile if required
  311. Padding(
  312. padding: const EdgeInsets.symmetric(vertical: 10.0),
  313. child: ExpansionTileCustom(
  314. isForm: true,
  315. subTitile: AppLocalizations.of(context)!.meetingmanager,
  316. title: meetingEditState.selectedManager.id != null
  317. ? meetingEditState.selectedManager.text ?? ''
  318. : itemInOneMeeting.manager!.name ?? '',
  319. widgets: <Widget>[
  320. Column(
  321. children:
  322. globalState.meetingsManagerModel!.map((manager) {
  323. bool isSelected =
  324. meetingEditState.selectedManager.id == manager.id;
  325. return CheckBoxInTile(
  326. backColor:
  327. isSelected ? Color(0xff06CF64) : Colors.white,
  328. textColor: isSelected ? Colors.white : Colors.black,
  329. text: manager.name ?? '',
  330. hasIcon: false,
  331. onTap: () {
  332. setState(() {
  333. meetingEditState.selectedManager = ItemSelected(
  334. id: manager.id,
  335. text: manager
  336. .name); // Update selected manager
  337. });
  338. },
  339. );
  340. }).toList(),
  341. ),
  342. ],
  343. ),
  344. ),
  345. // Submit Button
  346. SizedBox(
  347. height: 60,
  348. ),
  349. submit(context)
  350. ],
  351. ),
  352. ),
  353. ),
  354. );
  355. } else if (itemOnePrivateMeetingStatus == Status.loading ||
  356. globalState.allFiltersStatus == Status.loading) {
  357. return const LoadingWidget();
  358. } else if (itemOnePrivateMeetingStatus == Status.error ||
  359. globalState.allFiltersStatus == Status.error) {
  360. return CustomErrorWidget(
  361. onPressed: () async {
  362. await privateMeetingEditState.getOnePrivateMeeting(
  363. id: widget.id, refresh: true);
  364. await globalState.getAllFiltersItems(refresh: true);
  365. },
  366. );
  367. } else if (itemOnePrivateMeetingStatus == Status.empty ||
  368. globalState.allFiltersStatus == Status.empty) {
  369. return EmptyStateWidget();
  370. } else {
  371. return Container();
  372. }
  373. }
  374. CustomButton submit(BuildContext context) {
  375. switch (privateMeetingEditState.statusEditPrivateMeeting) {
  376. case Status.loading:
  377. return CustomButton(
  378. width: double.infinity,
  379. hieght: 50,
  380. fontSize: 16,
  381. onPressed: null,
  382. text: AppLocalizations.of(context)!.loading);
  383. default:
  384. return CustomButton(
  385. width: double.infinity,
  386. hieght: 50,
  387. fontSize: 16,
  388. onPressed: () async {
  389. final status = await privateMeetingEditState.editPrivateMeeting(
  390. id: widget.id,
  391. locationId: privateMeetingEditState.selectedLocation.id ?? -1,
  392. subjectId: privateMeetingEditState.selectedSubject.id ?? -1,
  393. managerId: privateMeetingEditState.selectedManager.id ?? -1,
  394. fromHour: Tools.formatTime(
  395. privateMeetingEditState.selectedStartTime!.hour,
  396. privateMeetingEditState.selectedStartTime!.minute),
  397. toHour: Tools.formatTime(
  398. privateMeetingEditState.selectedEndTime!.hour,
  399. privateMeetingEditState.selectedEndTime!.minute),
  400. dateMeeting: privateMeetingEditState.fromDate ?? '',
  401. visitorRole: visitorName.text,
  402. visitorCompany: visitorCompanyNameController.text,
  403. visitorMobile: visitorPhoneController.text,
  404. visitorName: visitorName.text);
  405. if (status == Status.ready) {
  406. context.pop();
  407. Tools.showCustomSnackBar(
  408. text: AppLocalizations.of(context)!.editdone,
  409. isError: false,
  410. context,
  411. );
  412. } else {
  413. Tools.showCustomSnackBar(
  414. text: privateMeetingEditState.errorsEditPrivateMeeting == null
  415. ? privateMeetingEditState.messageEditPrivateMeeting ??
  416. AppLocalizations.of(context)!.haserror
  417. : Tools.combineErrorMessages(
  418. privateMeetingEditState.errorsEditPrivateMeeting ??
  419. {}),
  420. isError: true,
  421. context,
  422. );
  423. }
  424. },
  425. text: AppLocalizations.of(context)!.submit);
  426. }
  427. }
  428. }