DigitalFormsPicker.xaml.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. using Comal.Classes;
  2. using comal.timesheets.QAForms;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using Comal.Classes;
  9. using InABox.Clients;
  10. using InABox.Configuration;
  11. using InABox.Core;
  12. using System.Linq;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using comal.timesheets.Data_Classes;
  16. using Xamarin.Forms;
  17. using Xamarin.Forms.Xaml;
  18. using XF.Material.Forms.UI.Dialogs;
  19. namespace comal.timesheets
  20. {
  21. [XamlCompilation(XamlCompilationOptions.Compile)]
  22. public partial class DigitalFormsPicker : ContentPage
  23. {
  24. #region Fields
  25. bool _searching = false;
  26. Kanban addToTaskKanban = new Kanban();
  27. List<DigitalFormLayoutShell> layouts = new List<DigitalFormLayoutShell>();
  28. List<String> types = new List<String>();
  29. private bool firstLoad = true;
  30. private bool incompleteVisible = true;
  31. private bool addingToTask = false;
  32. Guid JobID = Guid.Empty;
  33. List<ExistingFormShell> incompleteForms = new List<ExistingFormShell>();
  34. List<ExistingFormShell> completeForms = new List<ExistingFormShell>();
  35. #endregion
  36. public DigitalFormsPicker(string appliesTo = "Kanban", Guid _jobid = new Guid()) //normal Forms Library - default is kanban type
  37. {
  38. InitializeComponent();
  39. JobID = _jobid;
  40. NavigationPage.SetHasBackButton(this, false);
  41. LoadScreen(appliesTo);
  42. }
  43. public DigitalFormsPicker(Kanban _kanban) //used for adding forms to a task
  44. {
  45. InitializeComponent();
  46. addingToTask = true;
  47. addToTaskKanban = _kanban;
  48. NavigationPage.SetHasBackButton(this, false);
  49. LoadScreen("Kanban");
  50. }
  51. private void ExitBtn_Clicked(object sender, EventArgs e)
  52. {
  53. Navigation.PopAsync();
  54. }
  55. #region OnAppearing and Loading Screen
  56. protected override void OnAppearing()
  57. {
  58. try
  59. {
  60. _searching = false;
  61. if (RetainedResults.IsFormRetained)
  62. {
  63. DigitalFormHost host = new DigitalFormHost(DigitalFormsHelper.LoadModel(RetainedResults.LastDigitalFormLayout, CheckType(), addToTaskKanban, JobID, null, addingToTask), JobID);
  64. Navigation.PushAsync(host);
  65. }
  66. LoadExistingForms();
  67. }
  68. catch { }
  69. base.OnAppearing();
  70. }
  71. private void LoadScreen(string appliesTo)
  72. {
  73. try
  74. {
  75. Task.Run(() =>
  76. {
  77. types.Add("All");
  78. CoreTable table = LoadEmployeeRoleForms(appliesTo);
  79. foreach (CoreRow row in table.Rows)
  80. CreateAndAddShell(row);
  81. GetAverages();
  82. Device.BeginInvokeOnMainThread(() =>
  83. {
  84. layoutsList.ItemsSource = layouts;
  85. filterOptionsControl.Options = types;
  86. filterOptionsControl.CreateRadioButtonsAndSetDefault(types.First());
  87. });
  88. filterOptionsControl.OnFilterOptionChanged += FilterOptionsControl_OnFilterOptionChanged;
  89. firstLoad = false;
  90. });
  91. }
  92. catch (Exception ex)
  93. {
  94. var log = new MobileLogging(LogType.Query, typeof(DigitalFormLayout).ToString(), ex.Message, this.GetType().Name);
  95. }
  96. }
  97. private void CreateAndAddShell(CoreRow row)
  98. {
  99. DigitalFormLayoutShell layout = new DigitalFormLayoutShell();
  100. layout.ID = row.Get<DigitalFormLayout, Guid>(x => x.ID);
  101. layout.Description = row.Get<DigitalFormLayout, string>(x => x.Description);
  102. layout.Code = row.Get<DigitalFormLayout, string>(x => x.Code);
  103. layout.AppliesTo = row.Get<DigitalFormLayout, string>(x => x.Form.AppliesTo);
  104. layout.FormID = row.Get<DigitalFormLayout, Guid>(x => x.Form.ID);
  105. layout.Layout = row.Get<DigitalFormLayout, string>(x => x.Layout);
  106. layout.FormGroupDescription = row.Get<DigitalFormLayout, string>(x => x.Form.Group.Description);
  107. if (string.IsNullOrWhiteSpace(layout.FormGroupDescription))
  108. layout.FormGroupDescription = "All";
  109. layouts.Add(layout);
  110. if (!types.Contains(layout.FormGroupDescription) && !string.IsNullOrWhiteSpace(layout.FormGroupDescription))
  111. {
  112. types.Add(layout.FormGroupDescription);
  113. }
  114. }
  115. private CoreTable LoadEmployeeRoleForms(string appliesTo)
  116. {
  117. CoreTable table = new Client<EmployeeRole>().Query(
  118. new Filter<EmployeeRole>(x => x.EmployeeLink.ID).IsEqualTo(GlobalVariables.EmpID)
  119. , new Columns<EmployeeRole>(x => x.RoleLink.ID));
  120. if (!table.Rows.Any())
  121. {
  122. Device.BeginInvokeOnMainThread(() =>
  123. {
  124. DisplayAlert("Alert", "No Roles found for your employee profile. Please check with your administrator.", "OK");
  125. });
  126. return table;
  127. }
  128. CoreTable roleForms = QueryRoleForms(table);
  129. if (!roleForms.Rows.Any())
  130. {
  131. Device.BeginInvokeOnMainThread(() =>
  132. {
  133. DisplayAlert("Alert", "No Forms found for your employee role. Please check with your administrator.", "OK");
  134. });
  135. return table;
  136. }
  137. return QueryFormLayouts(roleForms, appliesTo);
  138. }
  139. private CoreTable QueryRoleForms(CoreTable table)
  140. {
  141. List<Guid> roleIDS = new List<Guid>();
  142. foreach (CoreRow row in table.Rows)
  143. {
  144. roleIDS.Add(row.Get<EmployeeRole, Guid>(x => x.RoleLink.ID));
  145. }
  146. return new Client<RoleForm>().Query(
  147. new Filter<RoleForm>(x => x.Role.ID).InList(roleIDS.ToArray()),
  148. new Columns<RoleForm>(x => x.Form.ID));
  149. }
  150. private CoreTable QueryFormLayouts(CoreTable roleForms, string appliesTo)
  151. {
  152. List<Guid> formIDs = new List<Guid>();
  153. foreach (CoreRow row in roleForms.Rows)
  154. {
  155. formIDs.Add(row.Get<RoleForm, Guid>(x => x.Form.ID));
  156. }
  157. return new Client<DigitalFormLayout>().Query
  158. (
  159. new Filter<DigitalFormLayout>(x => x.Form.ID).InList(formIDs.ToArray())
  160. .And(x => x.Type).IsEqualTo(DFLayoutType.Mobile)
  161. .And(x => x.Active).IsEqualTo(true)
  162. .And(x => x.Form.Secure).IsEqualTo(false)
  163. .And(x => x.Form.Active).IsEqualTo(true)
  164. .And(x => x.Form.AppliesTo).IsEqualTo(appliesTo),
  165. new Columns<DigitalFormLayout>(
  166. x => x.Description,
  167. x => x.ID,
  168. x => x.Code,
  169. x => x.Form.AppliesTo,
  170. x => x.Form.ID,
  171. x => x.Layout,
  172. x => x.Form.Group.Description),
  173. new SortOrder<DigitalFormLayout>(x => x.Description)
  174. );
  175. }
  176. private void GetAverages()
  177. {
  178. try
  179. {
  180. Task.Run(() =>
  181. {
  182. foreach (var layout in layouts)
  183. {
  184. TimeSpan span = new TimeSpan();
  185. CoreTable table = new Client<KanbanForm>().Query
  186. (
  187. new Filter<KanbanForm>(x => x.Form.ID).IsEqualTo(layout.FormID).And(x => x.FormOpen).IsNotEqualTo(null),
  188. new Columns<KanbanForm>(x => x.FormOpen)
  189. );
  190. if (table.Rows.Any())
  191. {
  192. foreach (CoreRow row in table.Rows)
  193. {
  194. List<object> list = row.Values;
  195. TimeSpan timespan = TimeSpan.Parse(list[0].ToString());
  196. span = span + timespan;
  197. }
  198. TimeSpan average = span / table.Rows.Count();
  199. layout.AverageTime = "Average time to complete: " + average.Minutes.ToString() + "m " + average.Seconds.ToString() + "s";
  200. layout.AverageTimeRow = 30;
  201. layout.ImageRowSpan = 2;
  202. }
  203. }
  204. Device.BeginInvokeOnMainThread(() =>
  205. {
  206. layoutsList.ItemsSource = null;
  207. if (filterOptionsControl.CurrentOption == "All")
  208. {
  209. layoutsList.ItemsSource = layouts;
  210. }
  211. else
  212. {
  213. layoutsList.ItemsSource = layouts.Where(x => x.FormGroupDescription.Equals(filterOptionsControl.CurrentOption));
  214. }
  215. });
  216. });
  217. }
  218. catch { }
  219. }
  220. private void LoadExistingForms()
  221. {
  222. //Task.Run(() =>
  223. //{
  224. try
  225. {
  226. List<IFormPickerQueryLoader> loaderList = new List<IFormPickerQueryLoader>()
  227. {
  228. new FormPickerQueryLoader<Kanban, KanbanLink, KanbanForm>(),
  229. new FormPickerQueryLoader<Job, JobLink, JobForm>()
  230. };
  231. incompleteForms.Clear();
  232. completeForms.Clear();
  233. foreach (var loader in loaderList)
  234. {
  235. List<ExistingFormShell> incomplete = loader.QueryIncomplete();
  236. foreach (var v in incomplete)
  237. {
  238. incompleteForms.Add(v);
  239. }
  240. List<ExistingFormShell> complete = loader.QueryComplete();
  241. foreach (var v in complete)
  242. {
  243. completeForms.Add(v);
  244. }
  245. }
  246. SortForms(completeForms, FormCompletion.Complete);
  247. SortForms(incompleteForms, FormCompletion.Incomplete);
  248. Device.BeginInvokeOnMainThread(() =>
  249. {
  250. ShowOrHideIncompleteFormsNotifications();
  251. RefreshMyForms();
  252. });
  253. }
  254. catch (Exception ex)
  255. {
  256. var log = new MobileLogging(LogType.Query, "Digital Form Instance", ex.Message + ex.StackTrace, this.GetType().Name);
  257. }
  258. //});
  259. }
  260. enum FormCompletion
  261. {
  262. Incomplete,
  263. Complete
  264. }
  265. private void SortForms(List<ExistingFormShell> shells, FormCompletion completion)
  266. {
  267. if (completion == FormCompletion.Complete && shells.Count > 0)
  268. shells.Sort((x, y) => y.DateCompleted.CompareTo(x.DateCompleted)); //descending
  269. else if (completion == FormCompletion.Incomplete && shells.Count > 0)
  270. shells.Sort((x, y) => x.DateStarted.CompareTo(y.DateStarted)); //ascending
  271. }
  272. private void ShowOrHideIncompleteFormsNotifications()
  273. {
  274. if (incompleteForms.Count > 0)
  275. {
  276. notificationFrame.IsVisible = true;
  277. notificationColumn.Width = 40;
  278. numberOfIncompleteFormsLbl.Text = incompleteForms.Count.ToString();
  279. }
  280. else
  281. {
  282. notificationFrame.IsVisible = false;
  283. notificationColumn.Width = 0;
  284. }
  285. }
  286. private void RefreshMyForms()
  287. {
  288. incompleteFormsList.ItemsSource = null;
  289. completeFormsList.ItemsSource = null;
  290. incompleteFormsList.ItemsSource = incompleteForms;
  291. completeFormsList.ItemsSource = completeForms;
  292. incompleteBtn.Text = "Incomplete (" + incompleteForms.Count + ")";
  293. completeBtn.Text = "Complete (" + completeForms.Count + ")";
  294. }
  295. #endregion
  296. #region User Interaction
  297. #region New Forms Section
  298. private void NewButton_Clicked(object sender, EventArgs e)
  299. {
  300. templatesColumn.Width = GridLength.Star;
  301. formsColumn.Width = 0;
  302. existingFormsGrid.IsVisible = false;
  303. templatesGrid.IsVisible = true;
  304. newButton.BackgroundColor = Color.FromHex("#15C7C1");
  305. myFormsButton.BackgroundColor = Color.Default;
  306. }
  307. private void MyFormsButton_Clicked(object sender, EventArgs e)
  308. {
  309. templatesColumn.Width = 0;
  310. formsColumn.Width = GridLength.Star;
  311. existingFormsGrid.IsVisible = true;
  312. templatesGrid.IsVisible = false;
  313. newButton.BackgroundColor = Color.Default;
  314. myFormsButton.BackgroundColor = Color.FromHex("#15C7C1");
  315. }
  316. private void FilterOptionsControl_OnFilterOptionChanged(string filterOption)
  317. {
  318. try
  319. {
  320. if (filterOption == filterOptionsControl.CurrentOption)
  321. return;
  322. filterOptionsControl.CurrentOption = filterOption;
  323. if (filterOption == "All")
  324. {
  325. layoutsList.ItemsSource = layouts;
  326. }
  327. else
  328. {
  329. layoutsList.ItemsSource = layouts.Where(x => x.FormGroupDescription.Equals(filterOption));
  330. }
  331. }
  332. catch { }
  333. }
  334. #endregion
  335. #region My Forms Section
  336. private async void IncompleteFormsList_Tapped(object sender, EventArgs e)
  337. {
  338. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  339. {
  340. var form = incompleteFormsList.SelectedItem as ExistingFormShell;
  341. DigitalFormLayout layout = new Client<DigitalFormLayout>().Query(
  342. new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(form.FormID)
  343. ).Rows.FirstOrDefault().ToObject<DigitalFormLayout>();
  344. if (form.Type == typeof(JobForm))
  345. JobID = form.ParentID;
  346. else
  347. JobID = Guid.Empty;
  348. DigitalFormHost host = new DigitalFormHost(DigitalFormsHelper.LoadModel(layout, form.Type, addToTaskKanban, JobID, form, addingToTask), JobID);
  349. Navigation.PushAsync(host);
  350. }
  351. }
  352. private async void CompleteFormsList_Tapped(object sender, EventArgs e)
  353. {
  354. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  355. {
  356. var form = completeFormsList.SelectedItem as ExistingFormShell;
  357. DigitalFormLayout layout = new Client<DigitalFormLayout>().Query(
  358. new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(form.FormID)
  359. ).Rows.FirstOrDefault().ToObject<DigitalFormLayout>();
  360. if (form.Type == typeof(JobForm))
  361. JobID = form.ParentID;
  362. else
  363. JobID = Guid.Empty;
  364. DigitalFormHost host = new DigitalFormHost(DigitalFormsHelper.LoadModel(layout, form.Type, addToTaskKanban, JobID, form, addingToTask), JobID);
  365. Navigation.PushAsync(host);
  366. }
  367. }
  368. private void Incomplete_Tapped(object sender, EventArgs e)
  369. {
  370. incompleteFormsColumn.Width = GridLength.Star;
  371. completeFormsColumn.Width = 0;
  372. incompleteFormsList.IsVisible = true;
  373. completeFormsList.IsVisible = false;
  374. incompleteBtn.BackgroundColor = Color.FromHex("#15C7C1");
  375. completeBtn.BackgroundColor = Color.Default;
  376. incompleteVisible = true;
  377. searchEnt.Text = "";
  378. }
  379. private void Complete_Tapped(object sender, EventArgs e)
  380. {
  381. completeFormsColumn.Width = GridLength.Star;
  382. incompleteFormsColumn.Width = 0;
  383. completeFormsList.IsVisible = true;
  384. incompleteFormsList.IsVisible = false;
  385. incompleteBtn.BackgroundColor = Color.Default;
  386. completeBtn.BackgroundColor = Color.FromHex("#15C7C1");
  387. incompleteVisible = false;
  388. searchEnt.Text = "";
  389. }
  390. private async void Delete_Tapped(object sender, EventArgs e)
  391. {
  392. var item = ((TappedEventArgs)e).Parameter as ExistingFormShell;
  393. if (item == null) return;
  394. string chosenOption = await DisplayActionSheet("Delete Form?", "Cancel", null, "Yes", "No");
  395. switch (chosenOption)
  396. {
  397. case "Yes":
  398. break;
  399. default:
  400. return;
  401. }
  402. DeleteForm(item);
  403. LoadExistingForms();
  404. }
  405. private void DeleteForm(ExistingFormShell item)
  406. {
  407. if (item.Type == typeof(KanbanForm))
  408. DeleteKanbanForm(item.ID);
  409. if (item.Type == typeof(JobForm))
  410. DeleteJobForm(item.ID);
  411. }
  412. private void DeleteJobForm(Guid id)
  413. {
  414. JobForm form = new JobForm { ID = id };
  415. new Client<JobForm>().Delete(form, "Deleted from Mobile App - My Forms section");
  416. }
  417. private void DeleteKanbanForm(Guid id)
  418. {
  419. KanbanForm form = new KanbanForm { ID = id };
  420. new Client<KanbanForm>().Delete(form, "Deleted from Mobile App - My Forms section");
  421. }
  422. #region Loading From History Section
  423. private void LayoutsList_Tapped(object sender, EventArgs e)
  424. {
  425. if (_searching)
  426. return;
  427. else
  428. LoadHost();
  429. }
  430. private async void LoadHost()
  431. {
  432. try
  433. {
  434. var digitalFormLayoutShell = layoutsList.SelectedItem as DigitalFormLayoutShell;
  435. DigitalFormLayout digitalFormLayout = new DigitalFormLayout();
  436. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  437. {
  438. _searching = true;
  439. digitalFormLayout.ID = digitalFormLayoutShell.ID;
  440. digitalFormLayout.Description = digitalFormLayoutShell.Description;
  441. digitalFormLayout.Code = digitalFormLayoutShell.Code;
  442. digitalFormLayout.Form.AppliesTo = digitalFormLayoutShell.AppliesTo;
  443. digitalFormLayout.Form.ID = digitalFormLayoutShell.FormID;
  444. digitalFormLayout.Layout = digitalFormLayoutShell.Layout;
  445. digitalFormLayout.Form.Group.Description = digitalFormLayoutShell.FormGroupDescription;
  446. RetainedResults.LastDigitalFormLayout = digitalFormLayout;
  447. }
  448. DigitalFormHost host = new DigitalFormHost(DigitalFormsHelper.LoadModel(digitalFormLayout, CheckType(), addToTaskKanban, JobID, null, addingToTask), JobID);
  449. Navigation.PushAsync(host);
  450. }
  451. catch (Exception ex)
  452. {
  453. var log = new MobileLogging(LogType.Query, typeof(IDigitalFormDataModel).ToString(), ex.Message, this.GetType().Name);
  454. }
  455. }
  456. private Type CheckType()
  457. {
  458. if (JobID != Guid.Empty)
  459. return typeof(JobForm);
  460. else
  461. return typeof(KanbanForm);
  462. }
  463. private IDigitalFormHostModel LoadModel(DigitalFormLayout layout, Type type, ExistingFormShell form = null)
  464. {
  465. if (type == typeof(JobForm))
  466. {
  467. var model = new DigitalFormHostModel<Job, JobLink, JobForm>();
  468. var job = new Job();
  469. var jobForm = new JobForm();
  470. jobForm.Form.ID = layout.Form.ID;
  471. if (form == null)
  472. {
  473. job.ID = JobID;
  474. }
  475. else
  476. {
  477. jobForm.ID = form.ID;
  478. job.ID = form.ParentID;
  479. }
  480. model.LoadItems(job, jobForm, layout);
  481. return model;
  482. }
  483. else
  484. {
  485. var model = new DigitalFormHostModel<Kanban, KanbanLink, KanbanForm>();
  486. var kanban = new Kanban();
  487. var kanbanForm = new KanbanForm();
  488. kanbanForm.Form.ID = layout.Form.ID;
  489. if (form != null)
  490. {
  491. kanbanForm.ID = form.ID;
  492. kanban.ID = form.ParentID;
  493. }
  494. if (addingToTask)
  495. {
  496. kanbanForm.Parent.ID = addToTaskKanban.ID;
  497. kanban.ID = addToTaskKanban.ID;
  498. }
  499. model.LoadItems(kanban, kanbanForm, layout);
  500. return model;
  501. }
  502. }
  503. #endregion
  504. #region Searching
  505. private void SearchEnt_Changed(object sender, EventArgs e)
  506. {
  507. if (CheckEmptySearch())
  508. return;
  509. else
  510. {
  511. RunSearch();
  512. }
  513. }
  514. private bool CheckEmptySearch()
  515. {
  516. if (string.IsNullOrWhiteSpace(searchEnt.Text))
  517. {
  518. incompleteFormsList.ItemsSource = incompleteForms;
  519. completeFormsList.ItemsSource = completeForms;
  520. return true;
  521. }
  522. else
  523. return false;
  524. }
  525. private void RunSearch()
  526. {
  527. try
  528. {
  529. if (incompleteVisible)
  530. RunSearchOnIncomplete();
  531. else
  532. RunSearchOnHistory();
  533. }
  534. catch (Exception ex)
  535. {
  536. var log = new MobileLogging(LogType.Query, "Digital Form Instance", ex.Message + ex.StackTrace, this.GetType().Name);
  537. }
  538. }
  539. private void RunSearchOnIncomplete()
  540. {
  541. incompleteFormsList.ItemsSource = incompleteForms.Where(x =>
  542. x.Description.Contains(searchEnt.Text) || x.Description.Contains(searchEnt.Text.ToUpper())
  543. || x.Description.Contains(searchEnt.Text.ToLower()) || x.Description.Contains(SearchUtils.UpperCaseFirst(searchEnt.Text))
  544. );
  545. }
  546. private void RunSearchOnHistory()
  547. {
  548. completeFormsList.ItemsSource = completeForms.Where(x =>
  549. x.Description.Contains(searchEnt.Text) || x.Description.Contains(searchEnt.Text.ToUpper())
  550. || x.Description.Contains(searchEnt.Text.ToLower()) || x.Description.Contains(SearchUtils.UpperCaseFirst(searchEnt.Text))
  551. );
  552. }
  553. #endregion
  554. #endregion
  555. #endregion
  556. }
  557. }