EquipmentSchedulesDashboard.xaml.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. using Comal.Classes;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using InABox.DynamicGrid;
  5. using InABox.WPF;
  6. using Microsoft.CodeAnalysis.VisualBasic.Syntax;
  7. using org.omg.PortableInterceptor;
  8. using PRSDesktop.Forms;
  9. using PRSDesktop.WidgetGroups;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.ComponentModel;
  13. using System.Globalization;
  14. using System.Linq;
  15. using System.Runtime.CompilerServices;
  16. using System.Threading.Tasks;
  17. using System.Windows.Controls;
  18. using System.Windows.Data;
  19. using System.Windows.Media;
  20. using System.Windows.Media.Imaging;
  21. using InABox.Configuration;
  22. using Client = InABox.Clients.Client;
  23. namespace PRSDesktop.Dashboards
  24. {
  25. public class EquipmentSchedulesDashboardProperties : IUserConfigurationSettings, IDashboardProperties
  26. {
  27. }
  28. public class ScheduleViewModel : INotifyPropertyChanged
  29. {
  30. private Guid employeeID;
  31. private string? employeeName;
  32. private string? employeeMobile;
  33. private string? employeeEmail;
  34. private BitmapImage? employeeImage;
  35. public bool HasEmployee => EmployeeID != Guid.Empty;
  36. public Guid ID { get; set; }
  37. public string Title { get; set; }
  38. public DateTime DueDate { get; set; }
  39. public BitmapImage? EmployeeImage
  40. {
  41. get => employeeImage;
  42. set
  43. {
  44. employeeImage = value;
  45. NotifyPropertyChanged();
  46. }
  47. }
  48. public Guid EmployeeID
  49. {
  50. get => employeeID;
  51. set
  52. {
  53. employeeID = value;
  54. NotifyPropertyChanged(nameof(HasEmployee));
  55. }
  56. }
  57. public string? EmployeeName
  58. {
  59. get => employeeName;
  60. set
  61. {
  62. employeeName = value;
  63. NotifyPropertyChanged();
  64. }
  65. }
  66. public string? EmployeeMobile
  67. {
  68. get => employeeMobile;
  69. set
  70. {
  71. employeeMobile = value;
  72. NotifyPropertyChanged();
  73. NotifyPropertyChanged(nameof(EmployeeContact));
  74. }
  75. }
  76. public string? EmployeeEmail
  77. {
  78. get => employeeEmail;
  79. set
  80. {
  81. employeeEmail = value;
  82. NotifyPropertyChanged();
  83. NotifyPropertyChanged(nameof(EmployeeContact));
  84. }
  85. }
  86. public string? EmployeeContact
  87. {
  88. get
  89. {
  90. var str = "";
  91. if (EmployeeEmail is not null) str = EmployeeEmail;
  92. if(EmployeeMobile is not null)
  93. {
  94. if (string.IsNullOrWhiteSpace(str))
  95. {
  96. str = EmployeeMobile;
  97. }
  98. else
  99. {
  100. str += $", {EmployeeMobile}";
  101. }
  102. }
  103. return string.IsNullOrWhiteSpace(str) ? null : str;
  104. }
  105. }
  106. public event PropertyChangedEventHandler? PropertyChanged;
  107. private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
  108. {
  109. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  110. }
  111. }
  112. public class EquipmentScheduleViewModel
  113. {
  114. public bool HasLocation { get; set; }
  115. public Guid ID { get; set; }
  116. public string Code { get; set; }
  117. public string Description { get; set; }
  118. public List<ScheduleViewModel> Schedules { get; set; }
  119. }
  120. [ValueConversion(typeof(DateTime), typeof(SolidColorBrush))]
  121. class ScheduleBackgroundConverter : IValueConverter
  122. {
  123. public Color GetColor(DateTime date)
  124. {
  125. var diff = date - DateTime.Today;
  126. if (diff < TimeSpan.Zero)
  127. return Colors.Salmon;
  128. else if (diff.TotalDays <= 7)
  129. return Colors.Orange;
  130. else if (diff.Days <= 30)
  131. return Colors.LightYellow;
  132. else
  133. return Colors.LightGreen;
  134. }
  135. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  136. {
  137. var date = (DateTime)value;
  138. var color = GetColor(date);
  139. return new SolidColorBrush(color);
  140. }
  141. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  142. {
  143. throw new NotImplementedException();
  144. }
  145. }
  146. /// <summary>
  147. /// Interaction logic for EquipmentSchedulesDashboard.xaml
  148. /// </summary>
  149. public partial class EquipmentSchedulesDashboard : UserControl, IDashboardWidget<EquipmentDashboardGroup, EquipmentSchedulesDashboardProperties>
  150. {
  151. public EquipmentSchedulesDashboardProperties Properties { get; set; } = null!;
  152. public event LoadSettings<EquipmentSchedulesDashboardProperties>? LoadSettings;
  153. public event SaveSettings<EquipmentSchedulesDashboardProperties>? SaveSettings;
  154. private Dictionary<Guid, Equipment> Equipment = new();
  155. private Dictionary<Guid, BitmapImage?> EmployeeImages = new();
  156. private Dictionary<Guid, Employee> Employees = new();
  157. private List<EquipmentScheduleViewModel> Models = new();
  158. public EquipmentSchedulesDashboard()
  159. {
  160. InitializeComponent();
  161. }
  162. public void Setup()
  163. {
  164. LoadEmployeeImages();
  165. }
  166. private void LoadEmployeeImages()
  167. {
  168. Task.Run(() =>
  169. {
  170. var employees = new Client<Employee>()
  171. .Query(
  172. LookupFactory.DefineFilter<Employee>(),
  173. new Columns<Employee>(
  174. x => x.ID,
  175. x => x.Thumbnail.ID,
  176. x => x.Name,
  177. x => x.Mobile,
  178. x => x.Email))
  179. .ToObjects<Employee>().ToList();
  180. var documents = new Client<Document>()
  181. .Query(
  182. new Filter<Document>(x => x.ID).InList(employees.Select(x => x.Thumbnail.ID).ToArray()),
  183. new Columns<Document>(x => x.ID).Add(x => x.Data))
  184. .ToDictionary<Document, Guid, byte[]>(x => x.ID, x => x.Data);
  185. return new { Employees = employees, Documents = documents };
  186. }).ContinueWith((task) =>
  187. {
  188. EmployeeImages = task.Result.Employees.ToDictionary(
  189. x => x.ID,
  190. x =>
  191. {
  192. var document = task.Result.Documents.GetValueOrDefault(x.Thumbnail.ID);
  193. if (document is null)
  194. return null;
  195. return ImageUtils.BitmapImageFromBytes(document);
  196. });
  197. Employees = task.Result.Employees.ToDictionary(x => x.ID, x => x);
  198. lock (Models)
  199. {
  200. var anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage();
  201. foreach (var model in Models)
  202. {
  203. foreach (var schedule in model.Schedules)
  204. {
  205. var employee = Employees?.GetValueOrDefault(schedule.EmployeeID);
  206. schedule.EmployeeImage = EmployeeImages?.GetValueOrDefault(schedule.EmployeeID) ?? anonymous;
  207. schedule.EmployeeMobile = employee?.Mobile;
  208. schedule.EmployeeName = employee?.Name;
  209. schedule.EmployeeEmail = employee?.Email;
  210. }
  211. }
  212. }
  213. }, TaskScheduler.FromCurrentSynchronizationContext());
  214. }
  215. public void Refresh()
  216. {
  217. var results = Client.QueryMultiple(
  218. new KeyedQueryDef<Equipment>(
  219. new Filter<Equipment>().All(),
  220. new Columns<Equipment>(x => x.ID)
  221. .Add(x => x.Code)
  222. .Add(x => x.Description)
  223. .Add(x => x.TrackerLink.ID)
  224. .Add(x => x.TrackerLink.Location.Latitude)
  225. .Add(x => x.TrackerLink.Location.Longitude)
  226. .Add(x => x.TrackerLink.Location.Timestamp)),
  227. new KeyedQueryDef<Schedule>(
  228. new Filter<Schedule>(x => x.DocumentClass).IsEqualTo(typeof(Equipment).EntityName()),
  229. new Columns<Schedule>(x => x.ID)
  230. .Add(x => x.Title)
  231. .Add(x => x.DueDate)
  232. .Add(x => x.DocumentID)
  233. .Add(x => x.EmployeeLink.ID)));
  234. var equipmentItems = results.Get<Equipment>().Rows.Select(x => x.ToObject<Equipment>());
  235. Equipment = equipmentItems.ToDictionary(x => x.ID, x => x);
  236. var schedules = results.Get<Schedule>().Rows
  237. .Select(x => x.ToObject<Schedule>())
  238. .GroupBy(x => x.DocumentID)
  239. .ToDictionary(x => x.Key, x => x.OrderBy(x => x.DueDate).ToList());
  240. var anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage();
  241. lock (Models)
  242. {
  243. Models = new List<EquipmentScheduleViewModel>();
  244. foreach (var equipmentItem in equipmentItems)
  245. {
  246. var equipmentSchedules = schedules.GetValueOrDefault(equipmentItem.ID);
  247. if (equipmentSchedules is not null)
  248. {
  249. var model = new EquipmentScheduleViewModel
  250. {
  251. Code = equipmentItem.Code,
  252. Description = equipmentItem.Description,
  253. ID = equipmentItem.ID,
  254. HasLocation = equipmentItem.TrackerLink.ID != Guid.Empty
  255. };
  256. model.Schedules = equipmentSchedules
  257. .Select(x =>
  258. {
  259. var employee = Employees.GetValueOrDefault(x.EmployeeLink.ID);
  260. return new ScheduleViewModel
  261. {
  262. Title = x.Title,
  263. DueDate = x.DueDate,
  264. ID = x.ID,
  265. EmployeeImage = EmployeeImages.GetValueOrDefault(x.EmployeeLink.ID) ?? anonymous,
  266. EmployeeID = x.EmployeeLink.ID,
  267. EmployeeEmail = employee?.Email,
  268. EmployeeMobile = employee?.Mobile,
  269. EmployeeName = employee?.Name
  270. };
  271. })
  272. .ToList() ?? new List<ScheduleViewModel>();
  273. Models.Add(model);
  274. }
  275. }
  276. }
  277. EquipmentList.ItemsSource = Models;
  278. }
  279. public void Shutdown()
  280. {
  281. }
  282. private void ViewEquipment_Click(object sender, System.Windows.RoutedEventArgs e)
  283. {
  284. var equipmentID = (Guid)(sender as MenuItem)!.Tag;
  285. var equipment = new Client<Equipment>().Load(
  286. new Filter<Equipment>(x => x.ID).IsEqualTo(equipmentID)).FirstOrDefault();
  287. if(equipment != null)
  288. {
  289. var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(Equipment));
  290. if(grid.EditItems(new[] { equipment }))
  291. {
  292. new Client<Equipment>().Save(equipment, "Edited by user from schedules dashboard");
  293. Refresh();
  294. }
  295. }
  296. }
  297. private void ViewSchedule_Click(object sender, System.Windows.RoutedEventArgs e)
  298. {
  299. var scheduleID = (Guid)(sender as MenuItem)!.Tag;
  300. var schedule = new Client<Schedule>().Load(
  301. new Filter<Schedule>(x => x.ID).IsEqualTo(scheduleID)).FirstOrDefault();
  302. if (schedule != null)
  303. {
  304. var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(Schedule));
  305. if (grid.EditItems(new[] { schedule }))
  306. {
  307. new Client<Schedule>().Save(schedule, "Edited by user from schedules dashboard");
  308. Refresh();
  309. }
  310. }
  311. }
  312. private void ViewEmployee_Click(object sender, System.Windows.RoutedEventArgs e)
  313. {
  314. var employeeID = (Guid)(sender as MenuItem)!.Tag;
  315. var employee = new Client<Employee>().Load(
  316. new Filter<Employee>(x => x.ID).IsEqualTo(employeeID)).FirstOrDefault();
  317. if (employee != null)
  318. {
  319. var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(Employee));
  320. if (grid.EditItems(new[] { employee }))
  321. {
  322. new Client<Employee>().Save(employee, "Edited by user from schedules dashboard");
  323. Refresh();
  324. }
  325. }
  326. }
  327. private void EquipmentLocation_Click(object sender, System.Windows.RoutedEventArgs e)
  328. {
  329. var equipmentID = (Guid)(sender as Button)!.Tag;
  330. if (!Equipment.TryGetValue(equipmentID, out var equipment))
  331. return;
  332. var form = new MapForm(
  333. equipment.TrackerLink.Location.Latitude,
  334. equipment.TrackerLink.Location.Longitude,
  335. equipment.TrackerLink.Location.Timestamp);
  336. form.ShowDialog();
  337. }
  338. }
  339. public class EquipmentSchedulesDashboardElement :
  340. DashboardElement<EquipmentSchedulesDashboard, EquipmentDashboardGroup, EquipmentSchedulesDashboardProperties> { }
  341. }