@plusscommunities/pluss-maintenance-web-a 1.1.35 → 1.1.37-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -6,12 +6,12 @@ var _defineProperty = require('@babel/runtime/helpers/defineProperty');
6
6
  var React = require('react');
7
7
  var reactRedux = require('react-redux');
8
8
  var reactRouter = require('react-router');
9
- var _ = require('lodash');
10
- var moment = require('moment');
11
- var FontAwesome = require('react-fontawesome');
12
9
  var PlussCore = require('@plusscommunities/pluss-core-web');
13
10
  var reactBootstrap = require('react-bootstrap');
14
11
  var reactRouterDom = require('react-router-dom');
12
+ var FontAwesome = require('react-fontawesome');
13
+ var moment = require('moment');
14
+ var _ = require('lodash');
15
15
  var Textarea = require('react-textarea-autosize');
16
16
  var freeSolidSvgIcons = require('@fortawesome/free-solid-svg-icons');
17
17
 
@@ -37,10 +37,10 @@ function _interopNamespace(e) {
37
37
 
38
38
  var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
39
39
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
40
- var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
41
- var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
42
- var FontAwesome__default = /*#__PURE__*/_interopDefaultLegacy(FontAwesome);
43
40
  var PlussCore__namespace = /*#__PURE__*/_interopNamespace(PlussCore);
41
+ var FontAwesome__default = /*#__PURE__*/_interopDefaultLegacy(FontAwesome);
42
+ var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
43
+ var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
44
44
  var Textarea__default = /*#__PURE__*/_interopDefaultLegacy(Textarea);
45
45
 
46
46
  const values = {
@@ -101,7 +101,13 @@ const values = {
101
101
  forceCustomFields: false,
102
102
  textEntityName: 'Job',
103
103
  stringConfigJobStatus: 'maintenanceJobStatusA',
104
- stringConfigHideSeen: 'maintenanceDisableSeenA'
104
+ stringConfigHideSeen: 'maintenanceDisableSeenA',
105
+ // Comment subscription notification preference
106
+ notificationPreference: {
107
+ key: 'maintenancerequestAComments',
108
+ label: 'Maintenance A comments',
109
+ permission: 'maintenanceTrackingA'
110
+ }
105
111
  };
106
112
 
107
113
  // import * as PlussCore from '../../pluss-core/src';
@@ -230,7 +236,8 @@ const FeatureConfig = {
230
236
  init: environment => {
231
237
  FeatureConfig.env = environment;
232
238
  PlussCore__namespace.Config.init(environment);
233
- }
239
+ },
240
+ notificationPreference: values.notificationPreference
234
241
  };
235
242
 
236
243
  const JOBS_LOADED = values.actionJobsLoaded;
@@ -243,12 +250,12 @@ const JOBS_HIDE_SEEN = values.actionJobsHideSeen;
243
250
  function ownKeys$7(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
244
251
  function _objectSpread$7(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$7(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$7(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
245
252
  const {
246
- Helper: Helper$5,
253
+ Helper: Helper$4,
247
254
  Session: Session$9
248
255
  } = PlussCore__namespace;
249
- const maintenanceActions = {
256
+ const maintenanceActions$1 = {
250
257
  getJobType: (site, typeId) => {
251
- let url = Helper$5.getUrl(values.serviceKey, 'getjobtype');
258
+ let url = Helper$4.getUrl(values.serviceKey, 'getjobtype');
252
259
  return Session$9.authedFunction({
253
260
  method: 'POST',
254
261
  url,
@@ -259,7 +266,7 @@ const maintenanceActions = {
259
266
  });
260
267
  },
261
268
  getJobTypes: (site, id) => {
262
- let url = Helper$5.getUrl(values.serviceKey, 'getjobtypes');
269
+ let url = Helper$4.getUrl(values.serviceKey, 'getjobtypes');
263
270
  return Session$9.authedFunction({
264
271
  method: 'POST',
265
272
  url,
@@ -269,7 +276,7 @@ const maintenanceActions = {
269
276
  });
270
277
  },
271
278
  getJob: (site, id) => {
272
- let url = Helper$5.getUrl(values.serviceKey, 'getJob');
279
+ let url = Helper$4.getUrl(values.serviceKey, 'getJob');
273
280
  return Session$9.authedFunction({
274
281
  method: 'POST',
275
282
  url,
@@ -280,7 +287,7 @@ const maintenanceActions = {
280
287
  });
281
288
  },
282
289
  getJobByJobId: (site, jobId) => {
283
- let url = Helper$5.getUrl(values.serviceKey, 'getJob');
290
+ let url = Helper$4.getUrl(values.serviceKey, 'getJob');
284
291
  return Session$9.authedFunction({
285
292
  method: 'POST',
286
293
  url,
@@ -295,7 +302,7 @@ const maintenanceActions = {
295
302
  let type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
296
303
  return Session$9.authedFunction({
297
304
  method: 'POST',
298
- url: Helper$5.getUrl(values.serviceKey, 'getJobs'),
305
+ url: Helper$4.getUrl(values.serviceKey, 'getJobs'),
299
306
  data: {
300
307
  site,
301
308
  status,
@@ -303,7 +310,7 @@ const maintenanceActions = {
303
310
  }
304
311
  });
305
312
  },
306
- getJobs2: (site, status, type, lastKey) => {
313
+ getJobs2: (site, status, type, priority, assignee, startTime, endTime, search, lastKey) => {
307
314
  const query = {
308
315
  site
309
316
  };
@@ -313,37 +320,57 @@ const maintenanceActions = {
313
320
  if (type) {
314
321
  query.type = type;
315
322
  }
323
+ if (priority) {
324
+ query.priority = priority;
325
+ }
326
+ if (assignee) {
327
+ query.assignee = assignee;
328
+ }
329
+ if (startTime) {
330
+ query.startTime = startTime;
331
+ }
332
+ if (endTime) {
333
+ query.endTime = endTime;
334
+ }
335
+ if (search) {
336
+ query.search = search;
337
+ }
316
338
  if (lastKey) {
317
339
  query.lastKey = JSON.stringify(lastKey);
318
340
  }
319
341
  return Session$9.authedFunction({
320
342
  method: 'GET',
321
- url: Helper$5.getUrl(values.serviceKey, 'get/requests', query)
343
+ url: Helper$4.getUrl(values.serviceKey, 'get/requests', query)
322
344
  });
323
345
  },
346
+ /**
347
+ * @deprecated Use getJobs2 with pagination instead.
348
+ * This method recursively fetches ALL pages which can be slow for large datasets.
349
+ * Only use for CSV export where all data is needed.
350
+ */
324
351
  getJobsRecursive: function (site, status, type, lastKey) {
325
352
  let jobs = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
326
- return new Promise(resolve => {
327
- maintenanceActions.getJobs2(site, status, type, lastKey).then(jobRes => {
353
+ return new Promise((resolve, reject) => {
354
+ maintenanceActions$1.getJobs2(site, status, type, undefined, undefined, undefined, undefined, undefined, lastKey).then(jobRes => {
328
355
  const newJobs = [...jobs, ...jobRes.data.Items];
329
356
  if (!jobRes.data.LastKey) {
330
357
  return resolve(newJobs);
331
358
  }
332
- return resolve(maintenanceActions.getJobsRecursive(site, status, type, jobRes.data.LastKey, newJobs));
333
- });
359
+ maintenanceActions$1.getJobsRecursive(site, status, type, jobRes.data.LastKey, newJobs).then(resolve).catch(reject);
360
+ }).catch(reject);
334
361
  });
335
362
  },
336
363
  createJob: job => {
337
364
  return Session$9.authedFunction({
338
365
  method: 'POST',
339
- url: Helper$5.getUrl(values.serviceKey, 'sendMaintenance'),
366
+ url: Helper$4.getUrl(values.serviceKey, 'sendMaintenance'),
340
367
  data: _objectSpread$7({}, job)
341
368
  });
342
369
  },
343
370
  editJob: (job, site) => {
344
371
  return Session$9.authedFunction({
345
372
  method: 'POST',
346
- url: Helper$5.getUrl(values.serviceKey, 'editJob'),
373
+ url: Helper$4.getUrl(values.serviceKey, 'editJob'),
347
374
  data: {
348
375
  job,
349
376
  site
@@ -353,7 +380,7 @@ const maintenanceActions = {
353
380
  deleteJob: (site, id) => {
354
381
  return Session$9.authedFunction({
355
382
  method: 'POST',
356
- url: Helper$5.getUrl(values.serviceKey, 'requests/remove'),
383
+ url: Helper$4.getUrl(values.serviceKey, 'requests/remove'),
357
384
  data: {
358
385
  site,
359
386
  id
@@ -363,7 +390,7 @@ const maintenanceActions = {
363
390
  editJobStatus: (id, status) => {
364
391
  return Session$9.authedFunction({
365
392
  method: 'POST',
366
- url: Helper$5.getUrl(values.serviceKey, 'editJobStatus'),
393
+ url: Helper$4.getUrl(values.serviceKey, 'editJobStatus'),
367
394
  data: {
368
395
  id,
369
396
  status
@@ -373,7 +400,7 @@ const maintenanceActions = {
373
400
  editJobPriority: (id, priority) => {
374
401
  return Session$9.authedFunction({
375
402
  method: 'POST',
376
- url: Helper$5.getUrl(values.serviceKey, 'update/priority'),
403
+ url: Helper$4.getUrl(values.serviceKey, 'update/priority'),
377
404
  data: {
378
405
  id,
379
406
  priority
@@ -383,7 +410,7 @@ const maintenanceActions = {
383
410
  assignJob: (jobId, userId) => {
384
411
  return Session$9.authedFunction({
385
412
  method: 'POST',
386
- url: Helper$5.getUrl(values.serviceKey, 'update/assign'),
413
+ url: Helper$4.getUrl(values.serviceKey, 'update/assign'),
387
414
  data: {
388
415
  id: jobId,
389
416
  userId
@@ -393,7 +420,7 @@ const maintenanceActions = {
393
420
  getAssignees: site => {
394
421
  return Session$9.authedFunction({
395
422
  method: 'GET',
396
- url: Helper$5.getUrl(values.serviceKey, 'get/assignees', {
423
+ url: Helper$4.getUrl(values.serviceKey, 'get/assignees', {
397
424
  site
398
425
  })
399
426
  });
@@ -401,7 +428,7 @@ const maintenanceActions = {
401
428
  addNote: (jobId, note, attachments, images) => {
402
429
  return Session$9.authedFunction({
403
430
  method: 'POST',
404
- url: Helper$5.getUrl(values.serviceKey, 'requests/note'),
431
+ url: Helper$4.getUrl(values.serviceKey, 'requests/note'),
405
432
  data: {
406
433
  id: jobId,
407
434
  note,
@@ -414,7 +441,7 @@ const maintenanceActions = {
414
441
  editNote: (jobId, noteId, note, attachments, images) => {
415
442
  return Session$9.authedFunction({
416
443
  method: 'POST',
417
- url: Helper$5.getUrl(values.serviceKey, 'requests/note'),
444
+ url: Helper$4.getUrl(values.serviceKey, 'requests/note'),
418
445
  data: {
419
446
  id: jobId,
420
447
  note,
@@ -428,7 +455,7 @@ const maintenanceActions = {
428
455
  deleteNote: (jobId, noteId) => {
429
456
  return Session$9.authedFunction({
430
457
  method: 'POST',
431
- url: Helper$5.getUrl(values.serviceKey, 'requests/note'),
458
+ url: Helper$4.getUrl(values.serviceKey, 'requests/note'),
432
459
  data: {
433
460
  id: jobId,
434
461
  noteId,
@@ -448,7 +475,7 @@ const maintenanceActions = {
448
475
  };
449
476
  return Session$9.authedFunction({
450
477
  method: 'POST',
451
- url: Helper$5.getUrl(values.serviceKey, 'createJobType'),
478
+ url: Helper$4.getUrl(values.serviceKey, 'createJobType'),
452
479
  data
453
480
  });
454
481
  },
@@ -466,14 +493,14 @@ const maintenanceActions = {
466
493
  if (hasCustomFields && customFields) data.customFields = customFields;
467
494
  return Session$9.authedFunction({
468
495
  method: 'POST',
469
- url: Helper$5.getUrl(values.serviceKey, 'editJobType'),
496
+ url: Helper$4.getUrl(values.serviceKey, 'editJobType'),
470
497
  data
471
498
  });
472
499
  },
473
500
  deleteJobType: (site, id) => {
474
501
  return Session$9.authedFunction({
475
502
  method: 'POST',
476
- url: Helper$5.getUrl(values.serviceKey, 'deleteJobType'),
503
+ url: Helper$4.getUrl(values.serviceKey, 'deleteJobType'),
477
504
  data: {
478
505
  site,
479
506
  id
@@ -483,7 +510,7 @@ const maintenanceActions = {
483
510
  getExternalSync: jobId => {
484
511
  return Session$9.authedFunction({
485
512
  method: 'GET',
486
- url: Helper$5.getUrl(values.serviceKey, 'get/externalsync', {
513
+ url: Helper$4.getUrl(values.serviceKey, 'get/externalsync', {
487
514
  id: jobId
488
515
  })
489
516
  });
@@ -491,7 +518,7 @@ const maintenanceActions = {
491
518
  retrySync: jobId => {
492
519
  return Session$9.authedFunction({
493
520
  method: 'POST',
494
- url: Helper$5.getUrl(values.serviceKey, 'update/retrysync'),
521
+ url: Helper$4.getUrl(values.serviceKey, 'update/retrysync'),
495
522
  data: {
496
523
  id: jobId
497
524
  }
@@ -500,7 +527,7 @@ const maintenanceActions = {
500
527
  };
501
528
 
502
529
  const {
503
- Helper: Helper$4,
530
+ Helper: Helper$3,
504
531
  Session: Session$8
505
532
  } = PlussCore__namespace;
506
533
  const reactionActions = {
@@ -518,7 +545,7 @@ const reactionActions = {
518
545
  }
519
546
  return Session$8.authedFunction({
520
547
  method: 'POST',
521
- url: Helper$4.getUrl('reactions', 'comments/add'),
548
+ url: Helper$3.getUrl('reactions', 'comments/add'),
522
549
  data
523
550
  });
524
551
  },
@@ -541,7 +568,7 @@ const reactionActions = {
541
568
  }
542
569
  return Session$8.authedFunction({
543
570
  method: 'GET',
544
- url: Helper$4.getUrl('reactions', 'comments/get', query)
571
+ url: Helper$3.getUrl('reactions', 'comments/get', query)
545
572
  });
546
573
  }
547
574
  };
@@ -574,30 +601,6 @@ var jobStatusOptions = [
574
601
  }
575
602
  ];
576
603
 
577
- const {
578
- Helper: Helper$3
579
- } = PlussCore__namespace;
580
- const jobsUpdate = (site, isdashboard) => {
581
- return dispatch => {
582
- if (isdashboard) dispatch({
583
- type: JOBS_LOADING
584
- });
585
- maintenanceActions.getJobsRecursive(site).then(res => {
586
- const currentSite = Helper$3.readStorageWithCookie('site');
587
- if (!___default["default"].isEmpty(res) && res[0].site === currentSite) {
588
- dispatch({
589
- type: JOBS_LOADED,
590
- payload: res
591
- });
592
- } else {
593
- dispatch({
594
- type: JOBS_LOADED,
595
- payload: []
596
- });
597
- }
598
- });
599
- };
600
- };
601
604
  const jobsLoaded = events => {
602
605
  return {
603
606
  type: JOBS_LOADED,
@@ -744,7 +747,171 @@ const {
744
747
  } = PlussCore__namespace;
745
748
  class JobList extends React.Component {
746
749
  constructor(props) {
750
+ var _this;
747
751
  super(props);
752
+ _this = this;
753
+ _defineProperty__default["default"](this, "getAssignees", async () => {
754
+ try {
755
+ const res = await maintenanceActions$1.getAssignees(this.props.auth.site);
756
+ this.setState({
757
+ assignees: res.data.Users
758
+ });
759
+ } catch (error) {
760
+ console.error('getAssignees', error);
761
+ }
762
+ });
763
+ /**
764
+ * Build server-side filter params from current filter state.
765
+ * Translates UI filter selections into API query parameters.
766
+ */
767
+ _defineProperty__default["default"](this, "buildFilterParams", () => {
768
+ const {
769
+ selectedStatusFilter,
770
+ selectedTypeFilter,
771
+ selectedPriorityFilter,
772
+ selectedUserFilter,
773
+ selectedTimeFilterStart,
774
+ selectedTimeFilterEnd,
775
+ searchTerm
776
+ } = this.state;
777
+ const {
778
+ statusTypes
779
+ } = this.props;
780
+ const params = {};
781
+
782
+ // Status filter: translate "All Incomplete" into the actual incomplete statuses
783
+ if (selectedStatusFilter) {
784
+ if (selectedStatusFilter === STATUS_IMCOMPLETE) {
785
+ // Exclude completed statuses - pass all non-completed status texts
786
+ const incompleteStatuses = statusTypes.filter(s => s.category !== STATUS_COMPLETED).map(s => s.text);
787
+ if (incompleteStatuses.length > 0) {
788
+ params.status = incompleteStatuses.join(',');
789
+ }
790
+ } else {
791
+ params.status = selectedStatusFilter;
792
+ }
793
+ }
794
+ if (selectedTypeFilter) {
795
+ params.type = selectedTypeFilter;
796
+ }
797
+ if (selectedPriorityFilter) {
798
+ params.priority = selectedPriorityFilter;
799
+ }
800
+ if (selectedUserFilter) {
801
+ params.assignee = selectedUserFilter;
802
+ }
803
+ if (selectedTimeFilterStart) {
804
+ params.startTime = selectedTimeFilterStart;
805
+ }
806
+ if (selectedTimeFilterEnd) {
807
+ params.endTime = selectedTimeFilterEnd;
808
+ }
809
+ if (searchTerm) {
810
+ params.search = searchTerm;
811
+ }
812
+ return params;
813
+ });
814
+ /**
815
+ * Minimum number of items to show before stopping auto-pagination.
816
+ * DynamoDB returns unfiltered pages; the backend filters after query.
817
+ * A single DynamoDB page may yield very few matching results,
818
+ * so we auto-fetch additional pages until we have enough to display.
819
+ */
820
+ _defineProperty__default["default"](this, "MIN_PAGE_SIZE", 50);
821
+ /**
822
+ * Fetch a single page from the server using the given lastKey.
823
+ */
824
+ _defineProperty__default["default"](this, "fetchPage", async function () {
825
+ let lastKey = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
826
+ const {
827
+ auth
828
+ } = _this.props;
829
+ const filters = _this.buildFilterParams();
830
+ return maintenanceActions$1.getJobs2(auth.site, filters.status, filters.type, filters.priority, filters.assignee, filters.startTime, filters.endTime, filters.search, lastKey);
831
+ });
832
+ /**
833
+ * Fetch the first page of jobs with current filters.
834
+ * Auto-paginates if the server returns fewer items than MIN_PAGE_SIZE
835
+ * (because DynamoDB pages are unfiltered — a single page may yield
836
+ * very few results after server-side filtering).
837
+ */
838
+ _defineProperty__default["default"](this, "fetchJobs", async () => {
839
+ this.setState({
840
+ loading: true
841
+ }, async () => {
842
+ try {
843
+ let allJobs = [];
844
+ let lastKey = null;
845
+
846
+ // Keep fetching pages until we have enough items or run out of data
847
+ do {
848
+ const res = await this.fetchPage(lastKey);
849
+ const items = res.data.Items || [];
850
+ lastKey = res.data.LastKey || null;
851
+ allJobs = [...allJobs, ...items];
852
+ } while (lastKey && allJobs.length < this.MIN_PAGE_SIZE);
853
+ this.setState({
854
+ jobs: allJobs,
855
+ lastKey,
856
+ hasMore: !!lastKey,
857
+ loading: false
858
+ });
859
+
860
+ // Sync to Redux so other components (e.g. Job detail) can access
861
+ this.props.jobsLoaded(allJobs);
862
+
863
+ // Update requesters list for the requester filter
864
+ this.setRequesters(allJobs);
865
+ } catch (error) {
866
+ console.error('fetchJobs', error);
867
+ this.setState({
868
+ loading: false
869
+ });
870
+ }
871
+ });
872
+ });
873
+ /**
874
+ * Load the next page of jobs and append to the existing list.
875
+ * Also auto-paginates to fill up to MIN_PAGE_SIZE new items.
876
+ */
877
+ _defineProperty__default["default"](this, "loadMore", async () => {
878
+ const {
879
+ lastKey
880
+ } = this.state;
881
+ this.setState({
882
+ loadingMore: true
883
+ }, async () => {
884
+ try {
885
+ let newJobs = [];
886
+ let currentLastKey = lastKey;
887
+ const existingCount = this.state.jobs.length;
888
+
889
+ // Keep fetching pages until we have enough new items or run out of data
890
+ do {
891
+ const res = await this.fetchPage(currentLastKey);
892
+ const items = res.data.Items || [];
893
+ currentLastKey = res.data.LastKey || null;
894
+ newJobs = [...newJobs, ...items];
895
+ } while (currentLastKey && existingCount + newJobs.length < existingCount + this.MIN_PAGE_SIZE);
896
+ this.setState(prevState => ({
897
+ jobs: [...prevState.jobs, ...newJobs],
898
+ lastKey: currentLastKey,
899
+ hasMore: !!currentLastKey,
900
+ loadingMore: false
901
+ }));
902
+
903
+ // Sync newly loaded jobs to Redux (append)
904
+ if (newJobs.length > 0) {
905
+ this.props.jobsLoaded(newJobs);
906
+ }
907
+ } catch (error) {
908
+ console.error('loadMore', error);
909
+ this.setState({
910
+ loadingMore: false
911
+ });
912
+ }
913
+ });
914
+ });
748
915
  _defineProperty__default["default"](this, "setRequesters", jobs => {
749
916
  const requesters = ___default["default"].orderBy(___default["default"].uniqBy(jobs.map(j => ({
750
917
  id: j.userID,
@@ -755,30 +922,6 @@ class JobList extends React.Component {
755
922
  requesters
756
923
  });
757
924
  });
758
- _defineProperty__default["default"](this, "getJobs", async () => {
759
- const {
760
- auth
761
- } = this.props;
762
- try {
763
- const res = await maintenanceActions.getJobsRecursive(auth.site);
764
- if (!___default["default"].isEmpty(res) && res[0].site === auth.site) {
765
- this.setRequesters(res);
766
- this.props.jobsLoaded(res);
767
- }
768
- } catch (error) {
769
- console.error('getJobs', error);
770
- }
771
- });
772
- _defineProperty__default["default"](this, "getAssignees", async () => {
773
- try {
774
- const res = await maintenanceActions.getAssignees(this.props.auth.site);
775
- this.setState({
776
- assignees: res.data.Users
777
- });
778
- } catch (error) {
779
- console.error('getAssignees', error);
780
- }
781
- });
782
925
  _defineProperty__default["default"](this, "sortByCol", col => {
783
926
  const {
784
927
  sortColumn,
@@ -798,9 +941,12 @@ class JobList extends React.Component {
798
941
  _defineProperty__default["default"](this, "onRemoveRequest", async request => {
799
942
  if (window.confirm(values.textAreYouSureYouWantToDelete)) {
800
943
  this.props.removeJob(request.id);
944
+ // Remove from local state immediately
945
+ this.setState(prevState => ({
946
+ jobs: prevState.jobs.filter(j => j.id !== request.id)
947
+ }));
801
948
  try {
802
- await maintenanceActions.deleteJob(this.props.auth.site, request.id);
803
- this.getJobs();
949
+ await maintenanceActions$1.deleteJob(this.props.auth.site, request.id);
804
950
  } catch (error) {
805
951
  console.log('onRemoveRequest', error);
806
952
  alert('Something went wrong with the request. Please try again.');
@@ -819,20 +965,20 @@ class JobList extends React.Component {
819
965
  });
820
966
  _defineProperty__default["default"](this, "selectTypeFilter", filter => {
821
967
  this.setState({
822
- selectedTypeFilter: filter
823
- });
968
+ selectedTypeFilter: filter || null
969
+ }, () => this.fetchJobs());
824
970
  this.closeFilter();
825
971
  });
826
972
  _defineProperty__default["default"](this, "selectPriorityFilter", filter => {
827
973
  this.setState({
828
- selectedPriorityFilter: filter
829
- });
974
+ selectedPriorityFilter: filter || null
975
+ }, () => this.fetchJobs());
830
976
  this.closeFilter();
831
977
  });
832
978
  _defineProperty__default["default"](this, "selectStatusFilter", filter => {
833
979
  this.setState({
834
- selectedStatusFilter: filter
835
- });
980
+ selectedStatusFilter: filter || null
981
+ }, () => this.fetchJobs());
836
982
  this.closeFilter();
837
983
  });
838
984
  _defineProperty__default["default"](this, "timeFilterChanged", selectedTimeFilter => {
@@ -876,7 +1022,7 @@ class JobList extends React.Component {
876
1022
  selectedTimeFilterStart: startTime,
877
1023
  selectedTimeFilterEnd: endTime,
878
1024
  selectedTimeFilterText: text
879
- });
1025
+ }, () => this.fetchJobs());
880
1026
  this.closeFilter();
881
1027
  });
882
1028
  _defineProperty__default["default"](this, "removeTimeFilter", () => {
@@ -884,7 +1030,7 @@ class JobList extends React.Component {
884
1030
  selectedTimeFilterStart: null,
885
1031
  selectedTimeFilterEnd: null,
886
1032
  selectedTimeFilterText: null
887
- });
1033
+ }, () => this.fetchJobs());
888
1034
  });
889
1035
  _defineProperty__default["default"](this, "onHandleChange", event => {
890
1036
  var stateChange = {};
@@ -900,7 +1046,7 @@ class JobList extends React.Component {
900
1046
  this.setState({
901
1047
  selectedUserFilter: null,
902
1048
  selectedUserFilterText: null
903
- });
1049
+ }, () => this.fetchJobs());
904
1050
  });
905
1051
  _defineProperty__default["default"](this, "saveUserFilter", () => {
906
1052
  if (!this.state.selectedAssignee) {
@@ -910,7 +1056,7 @@ class JobList extends React.Component {
910
1056
  selectedUserFilter: this.state.selectedAssignee.id,
911
1057
  selectedUserFilterText: this.state.selectedAssignee.displayName,
912
1058
  selectedAssignee: null
913
- });
1059
+ }, () => this.fetchJobs());
914
1060
  }
915
1061
  this.closeFilter();
916
1062
  });
@@ -923,7 +1069,7 @@ class JobList extends React.Component {
923
1069
  this.setState({
924
1070
  selectedRequesterFilter: null,
925
1071
  selectedRequesterFilterText: null
926
- });
1072
+ }, () => this.fetchJobs());
927
1073
  });
928
1074
  _defineProperty__default["default"](this, "saveRequesterFilter", () => {
929
1075
  if (!this.state.selectedRequester) {
@@ -933,7 +1079,7 @@ class JobList extends React.Component {
933
1079
  selectedRequesterFilter: this.state.selectedRequester.id,
934
1080
  selectedRequesterFilterText: this.state.selectedRequester.displayName,
935
1081
  selectedRequester: null
936
- });
1082
+ }, () => this.fetchJobs());
937
1083
  }
938
1084
  this.closeFilter();
939
1085
  });
@@ -944,77 +1090,33 @@ class JobList extends React.Component {
944
1090
  lastSearch: thisSearchTime
945
1091
  });
946
1092
  setTimeout(() => {
947
- // delayed setter to avoid filtering on every keypress
1093
+ // delayed setter to avoid searching on every keypress
948
1094
  if (this.state.lastSearch === thisSearchTime) {
949
1095
  this.setState({
950
1096
  searchTerm: this.state.search
951
- });
1097
+ }, () => this.fetchJobs());
952
1098
  }
953
1099
  }, 500);
954
1100
  });
1101
+ /**
1102
+ * Get the source array for rendering.
1103
+ * With server-side filtering, this is simply the local jobs array
1104
+ * sorted by the user's selected sort column.
1105
+ * The requester filter still applies client-side since the backend
1106
+ * doesn't have a requester/userID filter param.
1107
+ */
955
1108
  _defineProperty__default["default"](this, "getSource", () => {
956
- let source = this.props.source;
957
-
958
- // filter by time
959
- if (this.state.selectedTimeFilterStart && this.state.selectedTimeFilterEnd) {
960
- source = ___default["default"].filter(source, r => {
961
- return r.createdUnix >= this.state.selectedTimeFilterStart && r.createdUnix <= this.state.selectedTimeFilterEnd;
962
- });
963
- }
964
-
965
- // filter by type
966
- if (this.state.selectedTypeFilter) {
967
- source = ___default["default"].filter(source, r => {
968
- return r.type === this.state.selectedTypeFilter;
969
- });
970
- }
1109
+ let source = this.state.jobs;
971
1110
 
972
- // filter by priority
973
- if (this.state.selectedPriorityFilter) {
974
- const defaultPriority = getDefaultPriority().name;
975
- source = ___default["default"].filter(source, r => {
976
- return r.priority === this.state.selectedPriorityFilter || this.state.selectedPriorityFilter === defaultPriority && ___default["default"].isNil(r.priority);
977
- });
978
- }
1111
+ // Filter out deleted items
1112
+ source = ___default["default"].filter(source, ev => ev != null && !ev.Deleted);
979
1113
 
980
- // filter by status
981
- if (this.state.selectedStatusFilter) {
982
- const {
983
- statusTypes
984
- } = this.props;
985
- const defaultStatus = statusTypes.find(s => s.category === STATUS_NOT_ACTIONED);
986
- source = ___default["default"].filter(source, r => {
987
- const status = statusTypes.find(s => s.text === r.status) || defaultStatus;
988
- if (this.state.selectedStatusFilter === STATUS_IMCOMPLETE) {
989
- return status.category !== STATUS_COMPLETED;
990
- }
991
- return status.text === this.state.selectedStatusFilter;
992
- });
993
- }
994
- if (this.state.selectedUserFilter) {
995
- source = ___default["default"].filter(source, r => {
996
- return r.AssigneeId === this.state.selectedUserFilter;
997
- });
998
- }
1114
+ // Requester filter still client-side (no backend param for userID filtering)
999
1115
  if (this.state.selectedRequesterFilter) {
1000
1116
  source = ___default["default"].filter(source, r => {
1001
1117
  return r.userID === this.state.selectedRequesterFilter;
1002
1118
  });
1003
1119
  }
1004
- if (!___default["default"].isEmpty(this.state.searchTerm)) {
1005
- source = ___default["default"].filter(source, r => {
1006
- if (r.jobId && r.jobId === this.state.searchTerm) {
1007
- return true;
1008
- }
1009
- if (r.room && r.room.toLowerCase().indexOf(this.state.searchTerm.toLowerCase()) > -1) {
1010
- return true;
1011
- }
1012
- if (r.title && r.title.toLowerCase().indexOf(this.state.searchTerm.toLowerCase()) > -1) {
1013
- return true;
1014
- }
1015
- return false;
1016
- });
1017
- }
1018
1120
  source = ___default["default"].sortBy(source, event => {
1019
1121
  if (this.state.sortColumn === 'assigned') {
1020
1122
  return event.Assignee ? event.Assignee.displayName : 'Unassigned';
@@ -1134,13 +1236,60 @@ class JobList extends React.Component {
1134
1236
  exportCsvOpen: false
1135
1237
  });
1136
1238
  });
1239
+ _defineProperty__default["default"](this, "hasActiveFilters", () => {
1240
+ const {
1241
+ selectedTypeFilter,
1242
+ selectedPriorityFilter,
1243
+ selectedStatusFilter,
1244
+ selectedTimeFilterStart,
1245
+ selectedUserFilter,
1246
+ selectedRequesterFilter,
1247
+ searchTerm
1248
+ } = this.state;
1249
+ return !!(selectedTypeFilter || selectedPriorityFilter || selectedStatusFilter || selectedTimeFilterStart || selectedUserFilter || selectedRequesterFilter || searchTerm);
1250
+ });
1251
+ _defineProperty__default["default"](this, "clearAllFilters", () => {
1252
+ this.setState({
1253
+ selectedTypeFilter: null,
1254
+ selectedPriorityFilter: null,
1255
+ selectedStatusFilter: null,
1256
+ selectedTimeFilterStart: null,
1257
+ selectedTimeFilterEnd: null,
1258
+ selectedTimeFilterText: null,
1259
+ selectedUserFilter: null,
1260
+ selectedUserFilterText: null,
1261
+ selectedRequesterFilter: null,
1262
+ selectedRequesterFilterText: null,
1263
+ search: '',
1264
+ searchTerm: ''
1265
+ }, () => this.fetchJobs());
1266
+ });
1137
1267
  this.state = {
1138
- showCompleted: false,
1139
1268
  sortColumn: 'createdUnix',
1140
1269
  sortDesc: true,
1141
1270
  selectedTimeFilter: Analytics$2.getAnalyticsFilterOptions()[1],
1142
1271
  assignees: [],
1143
- requesters: []
1272
+ requesters: [],
1273
+ // Server-side pagination state
1274
+ jobs: [],
1275
+ lastKey: null,
1276
+ hasMore: false,
1277
+ loading: false,
1278
+ loadingMore: false,
1279
+ // Filters (applied to server-side queries)
1280
+ selectedTypeFilter: null,
1281
+ selectedPriorityFilter: null,
1282
+ selectedStatusFilter: null,
1283
+ selectedTimeFilterStart: null,
1284
+ selectedTimeFilterEnd: null,
1285
+ selectedTimeFilterText: null,
1286
+ selectedUserFilter: null,
1287
+ selectedUserFilterText: null,
1288
+ selectedRequesterFilter: null,
1289
+ selectedRequesterFilterText: null,
1290
+ search: '',
1291
+ searchTerm: '',
1292
+ lastSearch: null
1144
1293
  };
1145
1294
  this.exportColumns = [{
1146
1295
  label: 'Select All',
@@ -1200,7 +1349,7 @@ class JobList extends React.Component {
1200
1349
  }
1201
1350
  componentDidMount() {
1202
1351
  this.props.jobStatusesUpdate(this.props.auth.site);
1203
- this.getJobs();
1352
+ this.fetchJobs();
1204
1353
  this.getAssignees();
1205
1354
  }
1206
1355
  renderFilterPopup() {
@@ -1214,7 +1363,7 @@ class JobList extends React.Component {
1214
1363
  minWidth: 400,
1215
1364
  hasPadding: true,
1216
1365
  onClose: this.closeFilter
1217
- }, ___default["default"].sortBy(___default["default"].uniq(this.props.source.map(r => r.type)), t => t.toLowerCase()).map(type => {
1366
+ }, ___default["default"].sortBy(___default["default"].uniq(this.state.jobs.map(r => r.type)), t => t.toLowerCase()).map(type => {
1218
1367
  return /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
1219
1368
  key: type,
1220
1369
  onClick: () => {
@@ -1405,7 +1554,7 @@ class JobList extends React.Component {
1405
1554
  const status = ev.status && statusTypes.find(s => s.text === ev.status) || defaultStatus;
1406
1555
  const priority = getJobPriority(ev.priority);
1407
1556
  return /*#__PURE__*/React__default["default"].createElement("tr", {
1408
- key: index
1557
+ key: ev.id || index
1409
1558
  }, /*#__PURE__*/React__default["default"].createElement("td", null, ev.jobId), /*#__PURE__*/React__default["default"].createElement("td", {
1410
1559
  className: "table-TitleColumn"
1411
1560
  }, /*#__PURE__*/React__default["default"].createElement(reactRouterDom.Link, {
@@ -1486,8 +1635,28 @@ class JobList extends React.Component {
1486
1635
  if (col !== this.state.sortColumn) return '';
1487
1636
  return ' table--columnActive';
1488
1637
  }
1638
+ renderLoading() {
1639
+ return /*#__PURE__*/React__default["default"].createElement("div", {
1640
+ className: "flex flex-center-row",
1641
+ style: {
1642
+ padding: 40
1643
+ }
1644
+ }, /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
1645
+ style: {
1646
+ fontSize: 32,
1647
+ color: PlussCore.Colours.COLOUR_DUSK_LIGHT
1648
+ },
1649
+ name: "spinner fa-pulse fa-fw"
1650
+ }), /*#__PURE__*/React__default["default"].createElement("span", {
1651
+ className: "marginLeft-16 fontRegular fontSize-14",
1652
+ style: {
1653
+ color: PlussCore.Colours.TEXT_MID
1654
+ }
1655
+ }, "Loading ", values.textTitleRequests, "\u2026"));
1656
+ }
1489
1657
  renderEmpty() {
1490
1658
  const title = this.props.strings["".concat(values.featureKey, "_textTitleRequests")] || values.textTitleRequests;
1659
+ const hasFilters = this.hasActiveFilters();
1491
1660
  return /*#__PURE__*/React__default["default"].createElement("div", {
1492
1661
  style: {
1493
1662
  display: 'flex',
@@ -1499,7 +1668,22 @@ class JobList extends React.Component {
1499
1668
  }
1500
1669
  }, /*#__PURE__*/React__default["default"].createElement("div", {
1501
1670
  className: "emptyState"
1502
- }), /*#__PURE__*/React__default["default"].createElement("div", {
1671
+ }), hasFilters ? /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("div", {
1672
+ className: "marginTop-32",
1673
+ style: {
1674
+ maxWidth: 500,
1675
+ textAlign: 'center'
1676
+ }
1677
+ }, /*#__PURE__*/React__default["default"].createElement("span", {
1678
+ className: "fontRegular fontSize-13"
1679
+ }, "No ", title.toLowerCase(), " match your current filters.")), /*#__PURE__*/React__default["default"].createElement("div", {
1680
+ className: "marginTop-16"
1681
+ }, /*#__PURE__*/React__default["default"].createElement(Components$7.Button, {
1682
+ inline: true,
1683
+ buttonType: "tertiary",
1684
+ onClick: this.clearAllFilters,
1685
+ isActive: true
1686
+ }, "Clear All Filters"))) : /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("div", {
1503
1687
  className: "marginTop-32",
1504
1688
  style: {
1505
1689
  maxWidth: 500,
@@ -1515,11 +1699,39 @@ class JobList extends React.Component {
1515
1699
  maxWidth: 500,
1516
1700
  textAlign: 'center'
1517
1701
  }
1518
- }, values.textEmptyExample));
1702
+ }, values.textEmptyExample)));
1703
+ }
1704
+ renderLoadMore() {
1705
+ const {
1706
+ hasMore,
1707
+ loadingMore
1708
+ } = this.state;
1709
+ if (!hasMore) return null;
1710
+ return /*#__PURE__*/React__default["default"].createElement("div", {
1711
+ className: "flex flex-center-row",
1712
+ style: {
1713
+ padding: '16px 0'
1714
+ }
1715
+ }, /*#__PURE__*/React__default["default"].createElement(Components$7.Button, {
1716
+ inline: true,
1717
+ buttonType: "tertiary",
1718
+ onClick: this.loadMore,
1719
+ isActive: !loadingMore
1720
+ }, loadingMore ? /*#__PURE__*/React__default["default"].createElement("span", null, /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
1721
+ name: "spinner fa-pulse fa-fw",
1722
+ style: {
1723
+ marginRight: 8
1724
+ }
1725
+ }), "Loading more\u2026") : 'Load More'));
1519
1726
  }
1520
1727
  renderContent() {
1521
- if (___default["default"].isEmpty(this.props.source)) return this.renderEmpty();
1522
- return /*#__PURE__*/React__default["default"].createElement(reactBootstrap.Table, {
1728
+ const {
1729
+ loading,
1730
+ jobs
1731
+ } = this.state;
1732
+ if (loading) return this.renderLoading();
1733
+ if (___default["default"].isEmpty(jobs)) return this.renderEmpty();
1734
+ return /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement(reactBootstrap.Table, {
1523
1735
  className: "plussTable",
1524
1736
  striped: true,
1525
1737
  bordered: true,
@@ -1602,7 +1814,7 @@ class JobList extends React.Component {
1602
1814
  style: {
1603
1815
  width: 50
1604
1816
  }
1605
- }))), /*#__PURE__*/React__default["default"].createElement("tbody", null, this.renderRequests()));
1817
+ }))), /*#__PURE__*/React__default["default"].createElement("tbody", null, this.renderRequests())), this.renderLoadMore());
1606
1818
  }
1607
1819
  renderFilters() {
1608
1820
  let typeFilter = /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
@@ -1651,13 +1863,9 @@ class JobList extends React.Component {
1651
1863
  typeFilter = /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
1652
1864
  className: "marginRight-10",
1653
1865
  onClick: () => {
1654
- this.openFilter('type');
1655
- },
1656
- rightIcon: "close",
1657
- rightClick: e => {
1658
- e.stopPropagation();
1659
1866
  this.selectTypeFilter();
1660
1867
  },
1868
+ rightIcon: "close",
1661
1869
  text: this.state.selectedTypeFilter
1662
1870
  });
1663
1871
  }
@@ -1665,13 +1873,9 @@ class JobList extends React.Component {
1665
1873
  priorityFilter = /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
1666
1874
  className: "marginRight-10",
1667
1875
  onClick: () => {
1668
- this.openFilter('priority');
1669
- },
1670
- rightIcon: "close",
1671
- rightClick: e => {
1672
- e.stopPropagation();
1673
1876
  this.selectPriorityFilter();
1674
1877
  },
1878
+ rightIcon: "close",
1675
1879
  text: this.state.selectedPriorityFilter
1676
1880
  });
1677
1881
  }
@@ -1679,13 +1883,9 @@ class JobList extends React.Component {
1679
1883
  statusFilter = /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
1680
1884
  className: "marginRight-10",
1681
1885
  onClick: () => {
1682
- this.openFilter('status');
1683
- },
1684
- rightIcon: "close",
1685
- rightClick: e => {
1686
- e.stopPropagation();
1687
1886
  this.selectStatusFilter();
1688
1887
  },
1888
+ rightIcon: "close",
1689
1889
  text: this.state.selectedStatusFilter
1690
1890
  });
1691
1891
  }
@@ -1707,13 +1907,9 @@ class JobList extends React.Component {
1707
1907
  userFilter = /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
1708
1908
  className: "marginRight-10",
1709
1909
  onClick: () => {
1710
- this.openFilter('user');
1711
- },
1712
- rightIcon: "close",
1713
- rightClick: e => {
1714
- e.stopPropagation();
1715
1910
  this.removeUserFilter();
1716
1911
  },
1912
+ rightIcon: "close",
1717
1913
  text: this.state.selectedUserFilterText
1718
1914
  });
1719
1915
  }
@@ -1721,13 +1917,9 @@ class JobList extends React.Component {
1721
1917
  requesterFilter = /*#__PURE__*/React__default["default"].createElement(Components$7.Tag, {
1722
1918
  className: "marginRight-10",
1723
1919
  onClick: () => {
1724
- this.openFilter('requester');
1725
- },
1726
- rightIcon: "close",
1727
- rightClick: e => {
1728
- e.stopPropagation();
1729
1920
  this.removeRequesterFilter();
1730
1921
  },
1922
+ rightIcon: "close",
1731
1923
  text: this.state.selectedRequesterFilterText
1732
1924
  });
1733
1925
  }
@@ -1805,7 +1997,7 @@ class JobTypes extends React.Component {
1805
1997
  super(props);
1806
1998
  _defineProperty__default["default"](this, "getJobTypes", async () => {
1807
1999
  try {
1808
- const res = await maintenanceActions.getJobTypes(this.props.auth.site);
2000
+ const res = await maintenanceActions$1.getJobTypes(this.props.auth.site);
1809
2001
  if (res.data != null) this.props.jobTypesLoaded(res.data);
1810
2002
  } catch (error) {
1811
2003
  console.error('getJobTypes', error);
@@ -1830,7 +2022,7 @@ class JobTypes extends React.Component {
1830
2022
  _defineProperty__default["default"](this, "onRemoveJobType", async ev => {
1831
2023
  if (!window.confirm("Are you sure you want to delete ".concat(ev.typeName, "?"))) return;
1832
2024
  try {
1833
- await maintenanceActions.deleteJobType(this.props.auth.site, ev.id);
2025
+ await maintenanceActions$1.deleteJobType(this.props.auth.site, ev.id);
1834
2026
  const index = ___default["default"].findIndex(this.state.jobList, job => {
1835
2027
  return job != null && job.id === ev.id;
1836
2028
  });
@@ -2231,43 +2423,43 @@ class Configuration extends React.Component {
2231
2423
  return /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement("p", {
2232
2424
  className: "fontMedium fontSize-36 text-dark"
2233
2425
  }, "Statuses"), /*#__PURE__*/React__default["default"].createElement("div", {
2234
- style: styles$6.statusCategoryHeading
2426
+ style: styles$5.statusCategoryHeading
2235
2427
  }, /*#__PURE__*/React__default["default"].createElement("span", {
2236
2428
  className: "fontMedium fontSize-16 text-bold"
2237
2429
  }, "Status Category")), statusTypes.map((status, index) => {
2238
2430
  return /*#__PURE__*/React__default["default"].createElement("div", {
2239
2431
  key: "".concat(status.text, "_").concat(index),
2240
- style: styles$6.statusTypeContainer
2432
+ style: styles$5.statusTypeContainer
2241
2433
  }, /*#__PURE__*/React__default["default"].createElement("div", {
2242
2434
  key: status.text,
2243
2435
  className: "statusLabel",
2244
- style: _objectSpread$5(_objectSpread$5({}, styles$6.statusTextContainer), {}, {
2436
+ style: _objectSpread$5(_objectSpread$5({}, styles$5.statusTextContainer), {}, {
2245
2437
  backgroundColor: status.color
2246
2438
  })
2247
2439
  }, /*#__PURE__*/React__default["default"].createElement("span", {
2248
2440
  className: "statusLabel_text"
2249
2441
  }, status.text)), /*#__PURE__*/React__default["default"].createElement("div", {
2250
- style: styles$6.statusCategoryContainer
2442
+ style: styles$5.statusCategoryContainer
2251
2443
  }, /*#__PURE__*/React__default["default"].createElement("span", {
2252
2444
  className: "fontMedium fontSize-16 text-dark"
2253
2445
  }, status.category)), /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
2254
- style: _objectSpread$5(_objectSpread$5({}, styles$6.statusIcon), {}, {
2446
+ style: _objectSpread$5(_objectSpread$5({}, styles$5.statusIcon), {}, {
2255
2447
  visibility: index === 0 ? 'hidden' : 'visible'
2256
2448
  }),
2257
2449
  name: 'arrow-up',
2258
2450
  onClick: () => this.onMoveStatus(index, true)
2259
2451
  }), /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
2260
- style: _objectSpread$5(_objectSpread$5({}, styles$6.statusIcon), {}, {
2452
+ style: _objectSpread$5(_objectSpread$5({}, styles$5.statusIcon), {}, {
2261
2453
  visibility: index === statusTypes.length - 1 ? 'hidden' : 'visible'
2262
2454
  }),
2263
2455
  name: 'arrow-down',
2264
2456
  onClick: () => this.onMoveStatus(index, false)
2265
2457
  }), /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
2266
- style: _objectSpread$5({}, styles$6.statusIcon),
2458
+ style: _objectSpread$5({}, styles$5.statusIcon),
2267
2459
  name: "pencil",
2268
2460
  onClick: () => this.onEditStatus(index)
2269
2461
  }), /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
2270
- style: _objectSpread$5({}, styles$6.statusIcon),
2462
+ style: _objectSpread$5({}, styles$5.statusIcon),
2271
2463
  name: "minus-circle",
2272
2464
  onClick: () => this.onDeleteStatus(index)
2273
2465
  }));
@@ -2316,7 +2508,7 @@ class Configuration extends React.Component {
2316
2508
  renderSuccess() {
2317
2509
  if (!this.state.success) return null;
2318
2510
  return /*#__PURE__*/React__default["default"].createElement("span", {
2319
- style: _objectSpread$5(_objectSpread$5({}, styles$6.savedText), {}, {
2511
+ style: _objectSpread$5(_objectSpread$5({}, styles$5.savedText), {}, {
2320
2512
  color: Colours$2.COLOUR_GREEN
2321
2513
  })
2322
2514
  }, "Saved");
@@ -2433,7 +2625,7 @@ class Configuration extends React.Component {
2433
2625
  }, this.renderSubmit(), this.renderSuccess()), this.renderNewStatusPopup());
2434
2626
  }
2435
2627
  }
2436
- const styles$6 = {
2628
+ const styles$5 = {
2437
2629
  statusCategoryHeading: {
2438
2630
  marginLeft: 130,
2439
2631
  width: 160,
@@ -2492,52 +2684,6 @@ const {
2492
2684
  class RequestsHub extends React.Component {
2493
2685
  constructor(props) {
2494
2686
  super(props);
2495
- _defineProperty__default["default"](this, "setData", () => {
2496
- const allList = [];
2497
- this.state.allList.forEach(ev => {
2498
- if (ev != null && !ev.Deleted) allList.push(ev);
2499
- });
2500
- const upcoming = ___default["default"].filter(allList, ev => {
2501
- if (!ev) return false;
2502
- if (ev.status && ev.status === 'Completed') return false;
2503
- return true;
2504
- });
2505
- const completed = ___default["default"].filter(allList, ev => {
2506
- if (!ev) return false;
2507
- if (ev.status && ev.status === 'Completed') return true;
2508
- return false;
2509
- });
2510
-
2511
- // console.log('setData', upcoming, completed);
2512
- this.setState({
2513
- allList,
2514
- upcoming,
2515
- completed
2516
- });
2517
- });
2518
- _defineProperty__default["default"](this, "getData", () => {
2519
- const {
2520
- auth
2521
- } = this.props;
2522
- this.setState({
2523
- loadingAll: true
2524
- }, async () => {
2525
- try {
2526
- const res = await maintenanceActions.getJobsRecursive(auth.site);
2527
- this.setState({
2528
- loadingAll: false
2529
- });
2530
- if (!___default["default"].isEmpty(res) && res[0].site === auth.site) {
2531
- this.props.jobsLoaded(res);
2532
- }
2533
- } catch (error) {
2534
- console.error('getData', error);
2535
- this.setState({
2536
- loadingAll: false
2537
- });
2538
- }
2539
- });
2540
- });
2541
2687
  _defineProperty__default["default"](this, "onAddNew", () => {
2542
2688
  const {
2543
2689
  auth
@@ -2564,38 +2710,10 @@ class RequestsHub extends React.Component {
2564
2710
  _defineProperty__default["default"](this, "getSideBarSectionColour", id => this.state.selectedSection === id ? {
2565
2711
  backgroundColor: '#fff'
2566
2712
  } : {});
2567
- _defineProperty__default["default"](this, "renderStats", (stat, loading) => loading ? /*#__PURE__*/React__default["default"].createElement(FontAwesome__default["default"], {
2568
- style: styles$5.spinner,
2569
- name: "spinner fa-pulse fa-fw"
2570
- }) : stat);
2571
2713
  this.state = {
2572
- selectedSection: 'all',
2573
- location: '',
2574
- loadingAll: false,
2575
- loadingSubmissions: false,
2576
- submissionEntries: [],
2577
- allList: [],
2578
- completed: [],
2579
- upcoming: [],
2580
- now: moment__default["default"].utc(),
2581
- onlyFuture: true,
2582
- search: ''
2714
+ selectedSection: 'all'
2583
2715
  };
2584
2716
  }
2585
- UNSAFE_componentWillMount() {
2586
- this.updateProps(this.props);
2587
- }
2588
- componentDidMount() {
2589
- this.getData();
2590
- }
2591
- UNSAFE_componentWillReceiveProps(nextProps) {
2592
- if (!___default["default"].isEqual(this.props.jobs, nextProps.jobs)) this.updateProps(nextProps);
2593
- }
2594
- updateProps(props) {
2595
- this.setState({
2596
- allList: props.jobs
2597
- }, this.setData);
2598
- }
2599
2717
  renderLeftBar() {
2600
2718
  const sectionItems = [];
2601
2719
  if (this.canAddNew()) {
@@ -2665,9 +2783,7 @@ class RequestsHub extends React.Component {
2665
2783
  } else if (this.state.selectedSection === 'config') {
2666
2784
  return /*#__PURE__*/React__default["default"].createElement(Configuration$1, null);
2667
2785
  }
2668
- return /*#__PURE__*/React__default["default"].createElement(JobList$1, {
2669
- source: this.state.allList
2670
- });
2786
+ return /*#__PURE__*/React__default["default"].createElement(JobList$1, null);
2671
2787
  }
2672
2788
  render() {
2673
2789
  return /*#__PURE__*/React__default["default"].createElement("div", {
@@ -2679,42 +2795,16 @@ class RequestsHub extends React.Component {
2679
2795
  }, this.renderRight())));
2680
2796
  }
2681
2797
  }
2682
- const styles$5 = {
2683
- sideBarTitleSection: {
2684
- lineHeight: '40px',
2685
- marginTop: 30,
2686
- marginBottom: 30,
2687
- paddingLeft: 24,
2688
- paddingRight: 24
2689
- },
2690
- sideBarSection: {
2691
- weight: '100%',
2692
- minWidth: 200,
2693
- padding: 32,
2694
- paddingLeft: 24,
2695
- cursor: 'pointer',
2696
- display: 'flex',
2697
- flexDirection: 'column',
2698
- justifyContent: 'center'
2699
- },
2700
- spinner: {
2701
- fontSize: 32,
2702
- color: FeatureConfig.env.colourBrandingOff
2703
- }
2704
- };
2705
2798
  const mapStateToProps$4 = state => {
2706
2799
  const {
2707
2800
  auth
2708
2801
  } = state;
2709
2802
  return {
2710
- jobs: state[values.reducerKey].jobs,
2711
2803
  auth,
2712
2804
  strings: state.strings && state.strings.config || {}
2713
2805
  };
2714
2806
  };
2715
- var RequestsHub$1 = reactRedux.connect(mapStateToProps$4, {
2716
- jobsLoaded
2717
- })(reactRouter.withRouter(RequestsHub));
2807
+ var RequestsHub$1 = reactRedux.connect(mapStateToProps$4)(reactRouter.withRouter(RequestsHub));
2718
2808
 
2719
2809
  function ownKeys$4(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2720
2810
  function _objectSpread$4(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$4(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$4(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -2731,7 +2821,7 @@ class Job extends React.Component {
2731
2821
  super(props);
2732
2822
  _defineProperty__default["default"](this, "getJob", async () => {
2733
2823
  try {
2734
- const res = await maintenanceActions.getJob(this.props.auth.site, this.state.jobId);
2824
+ const res = await maintenanceActions$1.getJob(this.props.auth.site, this.state.jobId);
2735
2825
  this.setState({
2736
2826
  updating: false
2737
2827
  });
@@ -2743,7 +2833,7 @@ class Job extends React.Component {
2743
2833
  });
2744
2834
  _defineProperty__default["default"](this, "getAssignees", async () => {
2745
2835
  try {
2746
- const res = await maintenanceActions.getAssignees(this.props.auth.site);
2836
+ const res = await maintenanceActions$1.getAssignees(this.props.auth.site);
2747
2837
  this.setState({
2748
2838
  assignees: res.data.Users
2749
2839
  });
@@ -2756,7 +2846,7 @@ class Job extends React.Component {
2756
2846
  this.setState({
2757
2847
  loadingExternalSync: true
2758
2848
  });
2759
- const res = await maintenanceActions.getExternalSync(this.state.jobId);
2849
+ const res = await maintenanceActions$1.getExternalSync(this.state.jobId);
2760
2850
  this.setState({
2761
2851
  externalSync: res.data,
2762
2852
  loadingExternalSync: false
@@ -2781,7 +2871,7 @@ class Job extends React.Component {
2781
2871
  retrySyncError: null
2782
2872
  });
2783
2873
  try {
2784
- await maintenanceActions.retrySync(job.id);
2874
+ await maintenanceActions$1.retrySync(job.id);
2785
2875
  // Refresh job data to get updated history
2786
2876
  await this.getJob();
2787
2877
  this.setState({
@@ -2947,7 +3037,7 @@ class Job extends React.Component {
2947
3037
  // Method to handle user assignment
2948
3038
  _defineProperty__default["default"](this, "onAssignUser", async userId => {
2949
3039
  try {
2950
- const res = await maintenanceActions.assignJob(this.state.jobId, userId);
3040
+ const res = await maintenanceActions$1.assignJob(this.state.jobId, userId);
2951
3041
  this.getJob();
2952
3042
  } catch (err) {
2953
3043
  console.error("onAssignUser", err);
@@ -2959,12 +3049,12 @@ class Job extends React.Component {
2959
3049
  this.setState({
2960
3050
  submittingNote: true
2961
3051
  });
2962
- const res = await (this.state.editingNote ? maintenanceActions.editNote(this.state.jobId, this.state.editingNote, this.state.noteInput, this.state.noteAttachments.map(a => {
3052
+ const res = await (this.state.editingNote ? maintenanceActions$1.editNote(this.state.jobId, this.state.editingNote, this.state.noteInput, this.state.noteAttachments.map(a => {
2963
3053
  return {
2964
3054
  Title: a.Title,
2965
3055
  Source: a.Source
2966
3056
  };
2967
- }), this.state.noteImages) : maintenanceActions.addNote(this.state.jobId, this.state.noteInput, this.state.noteAttachments.map(a => {
3057
+ }), this.state.noteImages) : maintenanceActions$1.addNote(this.state.jobId, this.state.noteInput, this.state.noteAttachments.map(a => {
2968
3058
  return {
2969
3059
  Title: a.Title,
2970
3060
  Source: a.Source
@@ -2992,7 +3082,7 @@ class Job extends React.Component {
2992
3082
  });
2993
3083
  return;
2994
3084
  }
2995
- maintenanceActions.deleteNote(this.state.jobId, n.Id);
3085
+ maintenanceActions$1.deleteNote(this.state.jobId, n.Id);
2996
3086
  const newNotes = ___default["default"].filter(this.state.job.Notes, note => note.Id !== n.Id);
2997
3087
  const newJob = _objectSpread$4({}, this.state.job);
2998
3088
  newJob.Notes = newNotes;
@@ -3030,7 +3120,7 @@ class Job extends React.Component {
3030
3120
  seen: true,
3031
3121
  status: job.status || "Unassigned"
3032
3122
  };
3033
- await maintenanceActions.editJob(update, auth.site);
3123
+ await maintenanceActions$1.editJob(update, auth.site);
3034
3124
  } catch (error) {
3035
3125
  this.setState({
3036
3126
  updating: false
@@ -3084,7 +3174,7 @@ class Job extends React.Component {
3084
3174
  priorityChangerOpen: false
3085
3175
  });
3086
3176
  try {
3087
- const res = await maintenanceActions.editJobPriority(this.state.job.id, priority);
3177
+ const res = await maintenanceActions$1.editJobPriority(this.state.job.id, priority);
3088
3178
  const {
3089
3179
  job
3090
3180
  } = res.data;
@@ -3109,7 +3199,7 @@ class Job extends React.Component {
3109
3199
  statusChangerOpen: false
3110
3200
  });
3111
3201
  try {
3112
- const res = await maintenanceActions.editJobStatus(this.state.job.id, status);
3202
+ const res = await maintenanceActions$1.editJobStatus(this.state.job.id, status);
3113
3203
  const {
3114
3204
  job
3115
3205
  } = res.data;
@@ -3986,7 +4076,7 @@ class AddJob extends React.Component {
3986
4076
  _this = this;
3987
4077
  _defineProperty__default["default"](this, "getJob", async () => {
3988
4078
  try {
3989
- const res = await maintenanceActions.getJob(this.props.auth.site, this.state.jobId);
4079
+ const res = await maintenanceActions$1.getJob(this.props.auth.site, this.state.jobId);
3990
4080
  res.data.location = res.data.site;
3991
4081
  const {
3992
4082
  userID,
@@ -4020,7 +4110,7 @@ class AddJob extends React.Component {
4020
4110
  });
4021
4111
  _defineProperty__default["default"](this, "getJobTypes", async () => {
4022
4112
  try {
4023
- const res = await maintenanceActions.getJobTypes(this.props.auth.site);
4113
+ const res = await maintenanceActions$1.getJobTypes(this.props.auth.site);
4024
4114
  this.setState({
4025
4115
  types: res.data
4026
4116
  });
@@ -4280,7 +4370,7 @@ class AddJob extends React.Component {
4280
4370
  customFields: this.state.customFields
4281
4371
  };
4282
4372
  if (this.state.id != null) {
4283
- maintenanceActions.editJob(job, this.props.auth.site).then(res => {
4373
+ maintenanceActions$1.editJob(job, this.props.auth.site).then(res => {
4284
4374
  this.setState({
4285
4375
  success: true,
4286
4376
  updating: false
@@ -4294,12 +4384,12 @@ class AddJob extends React.Component {
4294
4384
  });
4295
4385
  } else {
4296
4386
  // Create New Job
4297
- maintenanceActions.createJob(job).then(res => {
4387
+ maintenanceActions$1.createJob(job).then(res => {
4298
4388
  this.setState({
4299
4389
  success: true,
4300
4390
  updating: false
4301
4391
  });
4302
- this.props.jobsUpdate(this.props.auth.site);
4392
+ // JobList fetches fresh data on mount — no action needed here
4303
4393
  }).catch(res => {
4304
4394
  this.setState({
4305
4395
  updating: false
@@ -4964,7 +5054,6 @@ const mapStateToProps$2 = state => {
4964
5054
  };
4965
5055
  };
4966
5056
  var AddJob$1 = reactRedux.connect(mapStateToProps$2, {
4967
- jobsUpdate,
4968
5057
  jobsLoaded,
4969
5058
  addRecentlyCreated: Actions.addRecentlyCreated
4970
5059
  })(reactRouter.withRouter(AddJob));
@@ -4986,7 +5075,7 @@ class AddJobType extends React.Component {
4986
5075
  super(props);
4987
5076
  _defineProperty__default["default"](this, "getJobType", async () => {
4988
5077
  try {
4989
- const res = await maintenanceActions.getJobType(this.props.auth.site, this.state.jobTypeId);
5078
+ const res = await maintenanceActions$1.getJobType(this.props.auth.site, this.state.jobTypeId);
4990
5079
  const {
4991
5080
  typeName,
4992
5081
  email,
@@ -5158,9 +5247,9 @@ class AddJobType extends React.Component {
5158
5247
  }, async () => {
5159
5248
  try {
5160
5249
  if (jobTypeId) {
5161
- await maintenanceActions.editJobType(site, jobTypeId, jobTypeName, jobTypeEmail, jobTypeDescription, jobTypeLevel, hasCustomFields, customFields);
5250
+ await maintenanceActions$1.editJobType(site, jobTypeId, jobTypeName, jobTypeEmail, jobTypeDescription, jobTypeLevel, hasCustomFields, customFields);
5162
5251
  } else {
5163
- await maintenanceActions.addJobType(site, jobTypeName, jobTypeEmail, jobTypeDescription, jobTypeLevel, hasCustomFields, customFields);
5252
+ await maintenanceActions$1.addJobType(site, jobTypeName, jobTypeEmail, jobTypeDescription, jobTypeLevel, hasCustomFields, customFields);
5164
5253
  }
5165
5254
  this.props.jobTypesUpdate(site);
5166
5255
  this.setState({