Guest User

Untitled

a guest
Sep 23rd, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.57 KB | None | 0 0
  1. <div class="page-section-header">
  2. <h1 class="list-title">Store Tender Totals</h1>
  3. </div>
  4.  
  5. <act-search-box
  6. default-type="attendant"
  7. search="vm.search"
  8. type="vm.type"
  9. placeholder="Enter a Store ID"
  10. type-options="[
  11. { label: 'Terminal', value : 'terminal' },
  12. { label: 'Total', value: 'total' },
  13. { label: 'Attendant', value: 'attendant' }
  14. ]"
  15. on-search="vm.getAttendants()">
  16. </act-search-box>
  17.  
  18. <div class="page-section-below-search-box single-width" style="width:27%;">
  19. <span class="calendarText">Showing totals for</span>
  20. <act-date-picker model="vm.date" placeholder="Select a date" on-change="vm.getAttendants()">
  21. </act-date-picker>
  22. </div>
  23.  
  24. <act-expanding-table
  25. list="vm.attendantNames"
  26. ng-hide="vm.emptyResult"
  27. properties="[
  28. { type: 'attendantName', size: 2, label: 'Attendant Name'},
  29. { type: 'total', size: 2, label: 'Total', format:'currency'},
  30. { type: 'runningTotal', size:2, label: 'Running Total', format:'currency'}
  31. ]"
  32. allow-selecting="true">
  33. <div>
  34. <div class="col-xs-12 form-section-header">
  35. <h4>Tender Totals</h4>
  36. </div>
  37. <act-field
  38. format="currency"
  39. class="col-xs-4"
  40. label="Cash"
  41. value="$item.tenderTotal.Cash">
  42. </act-field>
  43. <act-field
  44. format="currency"
  45. class="col-xs-4"
  46. label="Travelers Cash"
  47. value="$item.tenderTotal.TC">
  48. </act-field>
  49. <act-field
  50. format="currency"
  51. class="col-xs-4"
  52. label="UO Dollars"
  53. value="$item.tenderTotal.UOD">
  54. </act-field>
  55. <act-field
  56. format="currency"
  57. class="col-xs-4"
  58. label="Master Card"
  59. value="$item.tenderTotal.MC">
  60. </act-field>
  61. <act-field
  62. format="currency"
  63. class="col-xs-4"
  64. label="Visa"
  65. value="$item.tenderTotal.VI">
  66. </act-field>
  67. <act-field
  68. format="currency"
  69. class="col-xs-4"
  70. label="AMEX"
  71. value="$item.tenderTotal.AX">
  72. </act-field>
  73. <act-field
  74. format="currency"
  75. class="col-xs-4"
  76. label="Discover"
  77. value="$item.tenderTotal.DI">
  78. </act-field>
  79. <act-field
  80. format="currency"
  81. class="col-xs-4"
  82. label="JCB Card"
  83. value="$item.tenderTotal.JC">
  84. </act-field>
  85. <act-field
  86. format="currency"
  87. class="col-xs-4"
  88. label="Diners Club"
  89. value="$item.tenderTotal.DC">
  90. </act-field>
  91. <act-field
  92. format="currency"
  93. class="col-xs-4"
  94. label="Universal Pay"
  95. value="$item.tenderTotal.UOP">
  96. </act-field>
  97. <act-field
  98. format="currency"
  99. class="col-xs-4"
  100. label="Gringott Bucks"
  101. value="$item.tenderTotal.GN">
  102. </act-field>
  103. <act-field
  104. format="currency"
  105. class="col-xs-4"
  106. label="Gift Card"
  107. value="$item.tenderTotal.UOGC">
  108. </act-field>
  109. <act-field
  110. format="currency"
  111. class="col-xs-4"
  112. label="Loews Hotel Charge"
  113. value="$item.tenderTotal.HOTEL">
  114. </act-field>
  115. <act-field
  116. format="currency"
  117. class="col-xs-4"
  118. label="Guest Vouch"
  119. value="$item.tenderTotal.NCTNCG">
  120. </act-field>
  121. </div>
  122. </act-expanding-table>
  123. <act-total-panel ng-if="vm.totals" class="col-md-4 store-total-row">
  124. <line-item>
  125. <label>Total</label>
  126. <value>{{vm.totals | currency : "$"}}</value>
  127. </line-item>
  128. </act-total-panel>
  129. <act-error-message ng-show="vm.errorMessage">{{ vm.errorMessage }}</act-error-message>
  130.  
  131. import { digest, showLoader } from 'act/services/events';
  132. import 'act/components';
  133. import Searcher from 'act/services/lists/searcher';
  134. import * as moment from 'moment';
  135. import * as api from '../services/totals';
  136. import {header, dev} from 'act/services/logger';
  137. import {goToError} from 'act/services/controller-helpers';
  138. import '../components/store-total';
  139. const defaultStartDate = moment().startOf('day');
  140.  
  141. export default class StoreTotalsController {
  142. constructor() {
  143. this.attendantNames = [];
  144. this.emptyResult = true;
  145. this.totals = 0;//totals variable for the summed values in the Total column
  146. this.runningTotal = 0;
  147. }
  148.  
  149. getAttendants() {
  150. showLoader('Searching');
  151. const baseUrl = '/src/areas/store-totals/services/tender-total-data.json';
  152. const getStores = new Request(baseUrl, {
  153. method: 'GET'
  154. });
  155. fetch(getStores).then(function(response){
  156. return response.json();
  157. }).then(resp => {
  158.  
  159. if (!(resp[0] && resp[0].error)) {
  160. this.attendantNames = resp.stores[0].attendants;
  161. this.attendantNames.forEach((attendant, index) => {
  162. this.totals += attendant.total;
  163. })
  164.  
  165. this.emptyResult = false;
  166. this.errorMessage = null;
  167.  
  168. } else {
  169. this.errorMessage = resp[0].error.name;
  170. }
  171. digest();
  172. //this.calculateRunningTotals();
  173. showLoader(false);
  174. });
  175.  
  176. }
  177. /*calculateRunningTotals(){
  178. console.log("Sorter clicked");
  179. var attendantTotalCell = 0;
  180. var total = 0;
  181. var totalCell="";
  182. var totalsCells = document.querySelectorAll("td:nth-child(3)");
  183.  
  184. totalsCells.forEach(function(cell, index){
  185. cell.classList.remove('empty');
  186. totalCell = cell.innerText;
  187. attendantTotalCell = totalCell.replace(/[^0-9-.]/g, '');
  188. total = parseInt(attendantTotalCell) + parseInt(total);
  189. if(cell.nextElementSibling){
  190. cell.nextElementSibling.innerHTML = '$' + total.toFixed(2).replace(/d(?=(d{3})+.)/g, '$&,');
  191. }
  192. })
  193. }*/
  194.  
  195. searchIfReady() {
  196. if (this.search && this.date && this.date.isValid()) {
  197. this.getSearch();
  198. }
  199. }
  200.  
  201. updateDate(date) {
  202. this.date = moment(date).startOf('day');
  203. this.searchIfReady();
  204. }
  205. }
  206. StoreTotalsController.$inject = ['$stateParams'];
  207.  
  208. import app from 'act/app';
  209. import * as table from 'act/components/table';
  210. import './expanding-table.styles.less';
  211. import * as $ from 'jquery';
  212.  
  213. const expander = `
  214. <td class="col-xs-1 text-center link" ng-click="$event.stopPropagation()">
  215. <i class="fa fa-chevron-{{$item.expanded ? 'up' : 'down'}}" ng-click="$item.expanded = !$item.expanded"></i>
  216. </td>
  217. `;
  218.  
  219. const fakeRows = `
  220. <tbody ng-if="!$table.list.length">
  221. <tr class="dummy-data" ng-repeat="dummy in $table.fakeRows">
  222. ${expander}
  223.  
  224. <td ng-repeat="property in $table.properties track by property.type">
  225. dummy
  226. </td>
  227. </tr>
  228. </tbody>
  229. `;
  230.  
  231. const header = `
  232. <thead>
  233. <th>
  234.  
  235. </th>
  236.  
  237. <th ng-repeat="property in $table.properties track by property.type"
  238. class="col-xs-{{property.size}} clickable" ng-click="$table.sorter.changeType(property.type)">
  239. {{property.label}} &nbsp;
  240. <i class="fa fa-caret-{{$table.sorter.directionFor(property.type)}} fa-lg"></i>
  241. </th>
  242. </thead>
  243. `;
  244.  
  245. const rows = ({ row, ngRepeat, cell }) => `
  246. <tbody ng-if="$table.list.length">
  247. <tr class="clickable"
  248. ng-repeat-start="${ngRepeat}"
  249. ng-click="$item.expanded = !$item.expanded"
  250. ng-init="$item.expanded = false">
  251. ${row({ cell })}
  252. </tr>
  253.  
  254. <tr class="expanded-row" ng-show="$item.expanded"
  255. ng-repeat-end>
  256. <td colspan="12">
  257. <div expanded-placeholder></div>
  258. </td>
  259. </tr>
  260. </tbody>
  261. `;
  262.  
  263. const row = ({ cell }) => `
  264. ${expander}
  265.  
  266. ${cell}
  267. `;
  268.  
  269. app.directive('actExpandingTable', ['$compile', $compile =>
  270. table.defaultDirective({
  271. link: function($scope, $element, $attrs, $tables, $transclude) {
  272.  
  273. const $el = $(table.generateTemplate({ header, rows, row, fakeRows }));
  274. $scope.vm = $scope.$parent.vm;
  275. $transclude($scope, content => {
  276. if (content.length > 1) {
  277. $el.find('[expanded-placeholder]').replaceWith(content);
  278. } else {
  279. throw new Error('Expanding table requires transcluded content to show when expanded!');
  280. }
  281.  
  282. $compile($el)($scope, v => $element.append(v));
  283. });
  284. },
  285. })
  286. ]);
  287.  
  288. import './table.styles.less';
  289.  
  290. import * as lists from 'act/services/lists';
  291.  
  292. import {filter} from 'lodash';
  293.  
  294. import './formatters';
  295.  
  296. export const defaultTemplates = {
  297. ngRepeat: `$item in $table.list
  298. | orderBy:$table.sorter.type:$table.sorter.reverse
  299. | limitTo:$table.paginator.pageSize:$table.paginator.offset
  300. | filter:$table.filter track by $index`,
  301.  
  302. wrapper: ({ header, content, footer }) => `
  303. <div>
  304. <table class="table table-hover">
  305. ${header}
  306. ${content}
  307. </table>
  308.  
  309. ${footer}
  310. </div>
  311. `,
  312. header: `
  313. <thead>
  314. <th class="col-xs-1" ng-if="$table.allowSelecting">
  315. <span>
  316. <input id="locationCheckAll" ng-checked="$table.selector.all" type="checkbox" ng-click="$table.selector.toggleAll($table.list)">
  317. <label for="locationCheckAll" style="display:inline-block"></label>
  318. </span>
  319. </th>
  320.  
  321. <th ng-repeat="property in $table.properties track by property.type"
  322. ng-if="property.type"
  323. class="col-xs-{{property.size}}"
  324. ng-class="{ 'clickable': !property.disableSort, 'normal': property.disableSort }"
  325. ng-click="!property.disableSort && $table.sorter.changeType(property.type)">
  326. {{property.label}} &nbsp;
  327. <i class="fa fa-caret-{{$table.sorter.directionFor(property.type)}} fa-lg" ng-hide="property.disableSort"></i>
  328. </th>
  329. </thead>
  330. `,
  331. fakeRows: `
  332. <tbody ng-if="!$table.list.length">
  333. <tr class="dummy-data" ng-repeat="dummy in $table.fakeRows">
  334. <td class="col-xs-1" ng-click="$event.stopPropagation()" ng-if="$table.allowSelecting">
  335. <span>
  336. <input ng-checked="$item.selected" id="$item-{{$item._id}}" type="checkbox">
  337. <label for="$item-{{$item._id}}" style="display:inline-block"></label>
  338. </span>
  339. </td>
  340. <td ng-repeat="property in $table.properties track by property.type"
  341. ng-if="property.type">
  342. dummy
  343. </td>
  344. </tr>
  345. </tbody>
  346. `,
  347. rows: ({ ngRepeat, row, cell }) => `
  348. <tbody ng-if="$table.list.length">
  349. <tr class="clickable"
  350. ng-repeat="${ngRepeat}"
  351. ng-click="$table.onClick({ $item: $item })">
  352. ${row({ cell })}
  353. </tr>
  354. </tbody>
  355. `,
  356. row: ({ cell }) => `
  357. <td class="col-xs-1" ng-click="$event.stopPropagation()" ng-if="$table.allowSelecting">
  358. <span>
  359. <input ng-checked="$item.selected" id="$item-{{$item._id}}" type="checkbox" ng-click="$table.selector.toggle($item)">
  360. <label for="$item-{{$item._id}}" style="display:inline-block"></label>
  361. </span>
  362. </td>
  363.  
  364. ${cell}
  365. `,
  366. cell: `
  367. <td ng-if="property.type" ng-repeat="property in $table.properties track by property.type"
  368. act-placeholder
  369. ng-class="{ 'empty': $item[property.type] == null || $item[property.type].length === 0 }">
  370. <span ng-if="$item[property.type] != null">
  371. {{$item[property.type] | picker:property.format}}
  372. </span>
  373. <span ng-if="$item[property.type] == null">
  374. N/A
  375. </span>
  376. <span ng-if="$item[property.type].length === 0">
  377. N/A
  378. </span>
  379. </td>
  380. `,
  381. footer: `
  382. <act-paginator ng-if="$table.length() > $table.paginator.pageSize"
  383. total-count="$table.length()"
  384. paginator="$table.paginator"
  385. ></act-paginator>
  386. `,
  387. };
  388.  
  389. export const generateTemplate = ({
  390. wrapper = defaultTemplates.wrapper,
  391. header = defaultTemplates.header,
  392. fakeRows = defaultTemplates.fakeRows,
  393. rows = defaultTemplates.rows,
  394. row = defaultTemplates.row,
  395. footer = defaultTemplates.footer,
  396. ngRepeat = defaultTemplates.ngRepeat,
  397. cell = defaultTemplates.cell
  398. } = {}) => wrapper({
  399. header,
  400. footer,
  401. content: `
  402. ${rows({ row, ngRepeat, cell })}
  403.  
  404. ${fakeRows}
  405. `
  406. });
  407.  
  408. export const defaultScope = {
  409. list: '=',
  410. sorter: '=?',
  411. paginator: '=?',
  412. selector: '=?',
  413. searcher: '=?',
  414. properties: '=',
  415. onClick: '&',
  416. allowSelecting: '=?',
  417. filter: '=?',
  418. defaultSortType: '@',
  419. defaultSortReverse: '=?',
  420. fakeRowCount: '@'
  421. };
  422.  
  423. export const defaultController = class DefaultTableController {
  424. constructor($scope) {
  425. this.filter = this.filter || (_ => true);
  426. this.$scope = $scope;
  427. this.$filtered = [];
  428. }
  429.  
  430. $onInit() {
  431. this.searcher = this.searcher || {};
  432.  
  433. this.paginator = this.searcher.paginator || this.paginator || new lists.Paginator();
  434.  
  435. this.sorter = this.searcher.sorter || this.sorter || new lists.Sorter();
  436.  
  437. this.sorter.type = this.defaultSortType || this.properties[0].type;
  438. this.sorter.reverse = this.defaultSortReverse || false;
  439.  
  440. this.selector = this.searcher.selector || this.selector || new lists.Selector(() => this.filtered.length);
  441.  
  442. this.fakeRowCount = this.fakeRowCount || 25;
  443. this.fakeRows = [];
  444. for (let i = 0; i < this.fakeRowCount; i++) { this.fakeRows.push(i); }
  445.  
  446. this.$scope.$watch('$table.list', () => this.updateFilter());
  447. this.$scope.$watch('$table.filter', () => this.updateFilter());
  448. }
  449.  
  450. updateFilter() {
  451. this.filtered = filter(this.list, this.filter);
  452. this.calculateRunningTotals();
  453. }
  454.  
  455. calculateRunningTotals(){
  456. console.log("Calculate running totals was called by the watch function");
  457. var attendantTotalCell = 0;
  458. var total = 0;
  459. var totalCell="";
  460. var totalsCells = document.querySelectorAll("td:nth-child(3)");
  461.  
  462. totalsCells.forEach(function(cell, index){
  463. totalCell = cell.innerText;
  464. attendantTotalCell = totalCell.replace(/[^0-9-.]/g, '');
  465. total = parseInt(attendantTotalCell) + parseInt(total);
  466. if(cell.nextElementSibling){
  467. cell.nextElementSibling.innerHTML = '$' + total.toFixed(2).replace(/d(?=(d{3})+.)/g, '$&,');
  468. }
  469. })
  470. }
  471.  
  472. length() {
  473. return this.paginator.virtualized ? this.paginator.totalCount : this.filtered.length;
  474. }
  475. };
  476.  
  477. defaultController.$inject = ['$scope'];
  478.  
  479. export const defaultLink = ({ $compile, template }) => function($scope, $element, $attrs, $ctrls, $transclude) {
  480. /**
  481. * hello fellow traveler
  482. * you might be wondering wtf is going on here
  483. *
  484. * let me explain
  485. *
  486. * tables are kind of noisey when it comes to boilerplate.
  487. * pretty much all of the tables in this app need to support sorting and pagination.
  488. * but they're not all super identical.
  489. *
  490. * sometimes we show images in the table cells instead of data, or otherwise custom content.
  491. * we can capture this in some way through the 'properties' argument passed into the table,
  492. * but if we only do something on one page (such as the aforementioned images instead of data),
  493. * it seems like a waste to put it into the component itself.
  494. *
  495. * so instead, we can transclude the custom content into the table template.
  496. * however! necessarily, the custom table row must be able to access row data.
  497. * by default, transcluded content can not do this.
  498. *
  499. * but, we can specify whatever scope we want for the transcluded content.
  500. * you probably usually shouldn't do this.
  501. * but it lets us do cool things like this, where we can pass in a template and it 'magically'
  502. * can access $item, $table, etc. despite being transcluded content.
  503. */
  504.  
  505. // we need to start by reading our template as DOM nodes
  506. const templateEl = $(template);
  507.  
  508. // in order for 'normal' bindings (e.g not referencing $item, $table, etc.)
  509. // we do a small hack and put the parent scope's vm on this scope. since we ALWAYS
  510. // controllerAs vm, this will always work.
  511. $scope.vm = $scope.$parent.vm;
  512.  
  513. // kick off transclusion with the TABLE's scope (so we can access row data)
  514. $transclude($scope, content => {
  515. // only transclude if we passed in custom row data
  516. if (content.length > 1) {
  517. templateEl.find('[act-placeholder]').replaceWith(content);
  518. }
  519.  
  520. // Compile our template nodes, and then append it to our linked element.
  521. // Note that we are doing custom compilation, and we must put the transcluded template
  522. // in before we compile, or angular's ng-repeat will be confused
  523. $compile(templateEl)($scope, v => $element.empty().append(v));
  524. });
  525. };
  526.  
  527. export const defaultDirective = ({
  528. $compile,
  529. template,
  530. scope = defaultScope,
  531. controller = defaultController,
  532. link = defaultLink({ $compile, template }),
  533. }) => ({
  534. scope,
  535. controller,
  536. link,
  537. restrict: 'E',
  538. bindToController: true,
  539. controllerAs: '$table',
  540. transclude: true,
  541. });
  542.  
  543. export default class Sorter {
  544. constructor({ type = 'name',reverse = false, onChanged = () => {} } = {}) {
  545. this.type = type;
  546. this.reverse = reverse;
  547. this.onChanged = onChanged;
  548. }
  549.  
  550. changeType(type) {
  551. if (this.type !== type) {
  552. this.type = type;
  553. this.reverse = false;
  554.  
  555. } else {
  556. this.reverse = !this.reverse;
  557.  
  558. }
  559.  
  560. this.onChanged('sort');
  561. this.calculateRunningTotals();
  562.  
  563. }
  564.  
  565.  
  566.  
  567. changeReverse(reverse) {
  568. if (reverse !== this.reverse) {
  569. this.reverse = reverse;
  570. this.onChanged('reverse');
  571.  
  572. }
  573. }
  574.  
  575. directionFor(type) {
  576. if (this.type !== type) return '';
  577. return this.reverse ? 'up' : 'down';
  578. }
  579.  
  580.  
  581. }
Add Comment
Please, Sign In to add comment