AssignmentList.xaml.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using InABox.Clients;
  5. using InABox.Core;
  6. using Comal.Classes;
  7. using Xamarin.Forms;
  8. using System.Linq;
  9. using System.Threading.Tasks;
  10. using System.Windows.Input;
  11. using InABox.Configuration;
  12. using Syncfusion.SfSchedule.XForms;
  13. using WebSocketSharp;
  14. using XF.Material.Forms;
  15. using XF.Material.Forms.UI.Dialogs;
  16. using XF.Material.Forms.UI.Dialogs.Configurations;
  17. using PRSSecurity = InABox.Core.Security;
  18. namespace comal.timesheets
  19. {
  20. public enum AssignmentView
  21. {
  22. Day,
  23. TimeLine
  24. }
  25. public enum AssignmentLookupType
  26. {
  27. ActiveJobs,
  28. UnbookedJobs,
  29. Tasks
  30. }
  31. public partial class AssignmentList : ContentPage
  32. {
  33. private AssignmentEdit _editor = null;
  34. private Guid[] _employeeids = new Guid[] { };
  35. private AssignmentModuleSettings _settings = null;
  36. private AssignmentView _view = AssignmentView.Day;
  37. private AssignmentLookupType _lookuptype = AssignmentLookupType.UnbookedJobs;
  38. private String _teamname = "";
  39. private AssignmentJobDataModel _jobs = null;
  40. private AssignmentKanbanDataModel _kanbans = null;
  41. public AssignmentList()
  42. {
  43. InitializeComponent();
  44. _settings = new LocalConfiguration<AssignmentModuleSettings>().Load();
  45. _jobs = new AssignmentJobDataModel();
  46. _kanbans = new AssignmentKanbanDataModel();
  47. DatePicker.Date = _settings.Date.IsEmpty() ? DateTime.Today : _settings.Date;
  48. _view = _settings.View;
  49. _employeeids = (_settings.Employees != null)
  50. ? _settings.Employees
  51. : new Guid[] { App.Data.Employee.ID };
  52. _lookuptype = _settings.LookupType;
  53. LookupType.Text = CoreUtils.Neatify(_lookuptype.ToString());
  54. _teamname = _settings.TeamName;
  55. if (!PRSSecurity.IsAllowed<CanViewMobileAssignmentsSidebar>())
  56. CollapseSideBar(true);
  57. }
  58. protected override void OnAppearing()
  59. {
  60. base.OnAppearing();
  61. RefreshLookups();
  62. Reload();
  63. }
  64. private void CollapseSideBar(bool permanent = false)
  65. {
  66. CollapseButton.IsVisible = false;
  67. ExpandButton.IsVisible = true;
  68. JobColumn.Width = 0;
  69. if (permanent)
  70. ExpandButton.IsVisible = false;
  71. Refresh();
  72. }
  73. private void CollapseButton_Tapped(object sender, EventArgs e)
  74. {
  75. CollapseSideBar();
  76. }
  77. private void ExpandButton_Tapped(object sender, EventArgs e)
  78. {
  79. CollapseButton.IsVisible = true;
  80. ExpandButton.IsVisible = false;
  81. JobColumn.Width = 150;
  82. Refresh();
  83. }
  84. private void RefreshLookups()
  85. {
  86. if (_lookuptype == AssignmentLookupType.Tasks)
  87. {
  88. _kanbans.Load(
  89. new Filter<Kanban>(x => x.Completed).IsEqualTo(DateTime.MinValue),
  90. () => Dispatcher.BeginInvokeOnMainThread(() =>
  91. {
  92. Lookups.ItemsSource = new ObservableCollection<AssignmentKanbanItem>(_kanbans.Items);
  93. }));
  94. }
  95. else if (_lookuptype == AssignmentLookupType.ActiveJobs)
  96. {
  97. _jobs.Load(
  98. new Filter<Job>(x => x.JobStatus.Active).IsEqualTo(true),
  99. () => Dispatcher.BeginInvokeOnMainThread(() =>
  100. {
  101. Lookups.ItemsSource = new ObservableCollection<AssignmentJobItem>(_jobs.Items);
  102. }));
  103. }
  104. else if (_lookuptype == AssignmentLookupType.UnbookedJobs)
  105. {
  106. _jobs.Load(
  107. new Filter<Job>(x => x.JobStatus.Active).IsEqualTo(true)
  108. .And(x => x.OpenAssignments).IsEqualTo(0),
  109. () => Dispatcher.BeginInvokeOnMainThread(() =>
  110. {
  111. Lookups.ItemsSource = new ObservableCollection<AssignmentJobItem>(_jobs.Items);
  112. }));
  113. }
  114. }
  115. private void Reload()
  116. {
  117. DayView.DataSource = null;
  118. TimeLineView.DataSource = null;
  119. ScheduleType.Text = _teamname;
  120. if (_view == AssignmentView.Day)
  121. {
  122. DayViewColumn.Width = new GridLength(1, GridUnitType.Star);
  123. TimeLineViewColumn.Width = new GridLength(0, GridUnitType.Absolute);
  124. DayView.DayViewSettings.DayLabelSettings.TimeFormat = "HH:mm";
  125. }
  126. else
  127. {
  128. DayViewColumn.Width = new GridLength(0, GridUnitType.Absolute);
  129. TimeLineViewColumn.Width = new GridLength(1, GridUnitType.Star);
  130. TimeLineView.ResourceViewSettings.VisibleResourceCount = Math.Max(1, Math.Min(16, _employeeids.Length));
  131. TimeLineView.TimelineViewSettings.AppointmentHeight =
  132. (this.Height / TimeLineView.ResourceViewSettings.VisibleResourceCount) + 100;
  133. var resources = new ObservableCollection<object>();
  134. foreach (var empid in _employeeids)
  135. {
  136. var empname = GlobalVariables.EmployeeShells.FirstOrDefault(x => x.ID == empid)?.Name ?? empid.ToString();
  137. if (_employeeids.Length > 10)
  138. empname = String.Join("", empname.Split(' ').Select(x => x.Substring(0, 1)));
  139. else if (_employeeids.Length > 6)
  140. {
  141. var comps = empname.Split(' ').ToArray();
  142. empname = $"{comps.First()} {String.Join("", comps.Skip(1).Select(x => x.Substring(0, 1)))}";
  143. }
  144. resources.Add(
  145. new ScheduleResource()
  146. {
  147. Name = empname,
  148. Id = empid,
  149. Color = Color.Transparent,
  150. Image = ""
  151. }
  152. );
  153. }
  154. TimeLineView.ScheduleResources = resources;
  155. TimeLineView.ShowResourceView = true;
  156. }
  157. Refresh();
  158. }
  159. private void Refresh()
  160. {
  161. Title.Text = $"{DatePicker.Date:dd MMMM yyyy}";
  162. DataModel.Load(
  163. new Filter<Assignment>(x => x.Date).IsEqualTo(DatePicker.Date).And(x => x.EmployeeLink.ID).InList(_employeeids),
  164. () =>
  165. {
  166. Dispatcher.BeginInvokeOnMainThread(() =>
  167. {
  168. if (_view == AssignmentView.Day)
  169. {
  170. DayView.DataSource = new ObservableCollection<AssignmentListDataModelItem>(DataModel.Items);
  171. DayView.MoveToDate = ShowRelevantTime();
  172. }
  173. else
  174. {
  175. TimeLineView.DataSource = new ObservableCollection<AssignmentListDataModelItem>(DataModel.Items);
  176. TimeLineView.MoveToDate = ShowRelevantTime();
  177. }
  178. });
  179. }
  180. );
  181. }
  182. private DateTime ShowRelevantTime()
  183. {
  184. return (DataModel.Items.Count > 0 ? (DataModel.Items.First() as AssignmentListDataModelItem).StartTime : DateTime.Now).AddMinutes(-30);
  185. }
  186. private void SelectedDate_Tapped(object sender, EventArgs e)
  187. {
  188. DatePicker.Focus();
  189. }
  190. private void DatePicker_OnDateSelected(object sender, DateChangedEventArgs e)
  191. {
  192. if (_employeeids.Any())
  193. {
  194. _settings.Date = DatePicker.Date;
  195. new LocalConfiguration<AssignmentModuleSettings>().Save(_settings);
  196. }
  197. DayView.MoveToDate = DatePicker.Date;
  198. TimeLineView.MoveToDate = DatePicker.Date;
  199. Dispatcher.BeginInvokeOnMainThread(() =>
  200. {
  201. Refresh();
  202. });
  203. }
  204. private async void SelectEmployees_Tapped(object sender, EventArgs e)
  205. {
  206. var actions = new List<string>() { "Only Me" };
  207. //actions.AddRange(GlobalVariables.TeamEmployeeShells.Where(x=>x.ID == App.Data.Employee.ID).Select(x=>x.TeamName).Distinct());
  208. actions.AddRange(GlobalVariables.TeamEmployeeShells.Select(x => x.TeamName).Distinct());
  209. var result = await MaterialDialog.Instance.SelectActionAsync(title: "Select a Team",
  210. actions: actions);
  211. if (result == 0)
  212. {
  213. _view = AssignmentView.Day;
  214. _employeeids = new Guid[] { App.Data.Employee.ID };
  215. _teamname = App.Data.Employee.Name;
  216. }
  217. else if (result > 0)
  218. {
  219. _view = AssignmentView.TimeLine;
  220. _employeeids = GlobalVariables.TeamEmployeeShells.Where(x => String.Equals(x.TeamName, actions[result]))
  221. .Select(x => x.ID).Distinct().ToArray();
  222. _teamname = actions[result];
  223. }
  224. _settings.Employees = _employeeids;
  225. _settings.View = _view;
  226. _settings.TeamName = _teamname;
  227. new LocalConfiguration<AssignmentModuleSettings>().Save(_settings);
  228. Dispatcher.BeginInvokeOnMainThread(() =>
  229. {
  230. Reload();
  231. });
  232. }
  233. private void Lookups_OnItemTapped(object sender, ItemTappedEventArgs e)
  234. {
  235. if (e.Item is AssignmentLookupItem lookup)
  236. {
  237. if (lookup.Selected)
  238. lookup.Selected = false;
  239. else
  240. {
  241. IList<AssignmentLookupItem> lookups = _lookuptype == AssignmentLookupType.Tasks
  242. ? _kanbans.Items.ToArray<AssignmentLookupItem>()
  243. : _jobs.Items.ToArray<AssignmentLookupItem>();
  244. {
  245. foreach (var other in lookups.Where(x => x.Selected).ToArray())
  246. other.Selected = false;
  247. }
  248. lookup.Selected = true;
  249. }
  250. }
  251. }
  252. private void LookupsType_Tapped(object sender, EventArgs e)
  253. {
  254. _lookuptype = _lookuptype == AssignmentLookupType.Tasks
  255. ? AssignmentLookupType.ActiveJobs
  256. : _lookuptype == AssignmentLookupType.ActiveJobs
  257. ? AssignmentLookupType.UnbookedJobs
  258. : AssignmentLookupType.Tasks;
  259. _settings.LookupType = _lookuptype;
  260. LookupType.Text = CoreUtils.Neatify(_lookuptype.ToString());
  261. new LocalConfiguration<AssignmentModuleSettings>().Save(_settings);
  262. RefreshLookups();
  263. }
  264. private async void Schedule_OnCellTapped(object sender, CellTappedEventArgs e)
  265. {
  266. if (e.Appointment is AssignmentListDataModelItem item)
  267. {
  268. var editor = new AssignmentEdit(item);
  269. Navigation.PushAsync(editor);
  270. }
  271. }
  272. private async void Schedule_OnCellLongPressed(object sender, CellTappedEventArgs e)
  273. {
  274. if (e.Appointment == null)
  275. {
  276. if (InABox.Core.Security.CanEdit<Assignment>())
  277. {
  278. CreateAssignment(
  279. e.Datetime,
  280. e.Resource as ScheduleResource
  281. );
  282. }
  283. }
  284. else if (InABox.Core.Security.CanDelete<Assignment>()
  285. && e.Appointment is AssignmentListDataModelItem assignment)
  286. {
  287. await DeleteAssignment(assignment.Id);
  288. }
  289. }
  290. private void CreateAssignment(DateTime date, ScheduleResource resource)
  291. {
  292. var assignment = new Assignment()
  293. {
  294. Date = date.Date,
  295. Title = "New Assignment",
  296. };
  297. assignment.Booked.Start = new TimeSpan(date.TimeOfDay.Hours, 0, 0);
  298. assignment.Booked.Finish = date.TimeOfDay.Add(new TimeSpan(1, 0, 0));
  299. assignment.Booked.Duration = new TimeSpan(1, 0, 0);
  300. assignment.EmployeeLink.ID = (resource is ScheduleResource sr)
  301. ? (Guid)sr.Id
  302. : App.Data.Employee.ID;
  303. var job = (_lookuptype == AssignmentLookupType.ActiveJobs) || (_lookuptype == AssignmentLookupType.UnbookedJobs)
  304. ? _jobs.Items.FirstOrDefault(x => x.Selected)
  305. : null;
  306. if (job != null)
  307. {
  308. assignment.JobLink.ID = job.Id;
  309. assignment.JobLink.JobNumber = job.Number;
  310. assignment.JobLink.Name = job.Name;
  311. assignment.Description = job.Description;
  312. assignment.Title = job.Name;
  313. job.Selected = false;
  314. }
  315. var task = _lookuptype == AssignmentLookupType.Tasks
  316. ? _kanbans.Items.FirstOrDefault(x => x.Selected)
  317. : null;
  318. if (task != null)
  319. {
  320. assignment.Task.ID = task.Id;
  321. assignment.Task.Number = int.Parse(task.Number);
  322. assignment.Task.Title = task.Name;
  323. assignment.Title = task.Name;
  324. assignment.Description = task.Description;
  325. task.Selected = false;
  326. }
  327. var editor = new AssignmentEdit(assignment);
  328. Navigation.PushAsync(editor);
  329. }
  330. private async Task DeleteAssignment(Guid id)
  331. {
  332. var confirm = await MaterialDialog.Instance.ConfirmAsync(
  333. "Are you sure you wish to delete this assignment?",
  334. "Confirm Deletion",
  335. "Yes, Delete",
  336. "Cancel",
  337. new MaterialAlertDialogConfiguration()
  338. {
  339. ButtonFontFamily = Material.FontFamily.Body2
  340. }
  341. );
  342. if (confirm == true)
  343. {
  344. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Deleting Assignment"))
  345. {
  346. var assignment = new Assignment() { ID = id };
  347. new Client<Assignment>().Delete(assignment, "Deleted on Mobile Device");
  348. }
  349. Refresh();
  350. }
  351. }
  352. }
  353. }