routes.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. var editors = [];
  2. var rows = {};
  3. function initializeRoutes()
  4. {
  5. router('/login', routes['login']);
  6. router('/logout', routes['logout']);
  7. router('/sd', routes['sd']);
  8. router('/', routes['login']);
  9. router('*', routes['login']);
  10. }
  11. //add a 'firstLoad' setup function into the route's middleware chain
  12. var routes =
  13. {
  14. login: function()
  15. {
  16. showPage('login');
  17. },
  18. logout: function()
  19. {
  20. $.post('api/logout.php');
  21. router('/');
  22. },
  23. sd: function()
  24. {
  25. showPage('sd');
  26. loadAllData();
  27. }
  28. };
  29. function showPage(page)
  30. {
  31. console.log('show page', page);
  32. var $page_old = $('.screen.active');
  33. var $page_new = $('#screen-' + page);
  34. //do nothing if we are already on the page
  35. if($page_old.is($page_new))
  36. return;
  37. $('body').attr('class', 'screen-' + page);
  38. //put new page on top of old
  39. $page_new.insertAfter('.screen.active');
  40. //slide it to the right while crossfading
  41. $page_old
  42. .one('animationend', function(event) //jshint ignore:line, unused
  43. {
  44. $(this).hide();
  45. }) //TODO: add detect webkitanimationend or animationend
  46. .removeClass('active');
  47. //slide from left while crossfading
  48. $page_new
  49. .show()
  50. .off('animationend')
  51. .addClass('active')
  52. .focus(); //this needs to be used in conjunction with a "tabindex" field on the html object to maintain keyboard focus
  53. }
  54. function loadAllData()
  55. {
  56. console.log('requesting data');
  57. $.get('api/getRows.php', 'json')
  58. .done(function(companies)
  59. {
  60. console.log('received data');
  61. //go through each company and add a tab if one isn't present
  62. if(!companies.length)
  63. return;
  64. for(var c = 0; c < companies.length; c++)
  65. {
  66. var company = companies[c];
  67. var id_company = company['id_company'];
  68. if(company['file_rows'])
  69. for(var r = 0; r < company['file_rows'].length; r++)
  70. {
  71. var id_file_row = company['file_rows'][r]['id_file_row'];
  72. rows[id_file_row] = company['file_rows'][r];
  73. }
  74. drivers_by_company[id_company] = {}
  75. for(var i = 0; company['drivers'] && i < company['drivers'].length; i++)
  76. {
  77. var driver = company['drivers'][i];
  78. var id_driver = driver['id_driver'];
  79. drivers_by_company[id_company][id_driver] = driver;
  80. }
  81. //if the company's tab doesn't exist, create it
  82. if(!tables[id_company])
  83. {
  84. //add tab
  85. $('<li><a data-toggle="tab" href="#table-' + id_company + '-container">' + company['name'] + '</a></li>')
  86. .data('id_company', id_company)
  87. .insertBefore('#audit-tab-parent');
  88. //add table
  89. $('<div id="table-' + id_company + '-container" class="tab-pane fade in">'
  90. + '<table id="table-' + id_company + '" class="table table-striped editable" width="100%"></table>'
  91. + '<button class="download-csv" data-id_company="' + id_company + '">Download CSV</button>'
  92. + '</div>')
  93. .appendTo('#screen-sd .tab-content');
  94. $('<h1>' + company['name'] + '</h1>'
  95. + '<table id="table-updates-' + id_company + '" class="table table-striped editable" width="100%"></table>')
  96. .appendTo('#audit-content');
  97. //create the datatable
  98. tables[id_company] = createTable(id_company, '#screen-sd #table-' + id_company);
  99. table_updates[id_company] = createUpdatesTable(id_company, '#screen-sd #table-updates-' + id_company);
  100. }
  101. else
  102. {
  103. tables[id_company].clear();
  104. table_updates[id_company].clear();
  105. }
  106. //load the data into the data
  107. tables[id_company].rows.add(company['file_rows']).draw();
  108. table_updates[id_company].rows.add(company['row_updates']).draw();
  109. }
  110. if($('#screen-sd ul.nav-tabs > li.active').length === 0)
  111. $('#screen-sd ul.nav-tabs > li:eq(0) a').click();
  112. })
  113. .fail(function(err, xhr, text)
  114. {
  115. console.error(err['responseText']);
  116. });
  117. }
  118. function loadCompanies()
  119. {
  120. $.post('api/getCompanies.php')
  121. .done(function(response)
  122. {
  123. })
  124. .fail(function(err, xhr, text)
  125. {
  126. console.error(err.responseText);
  127. });
  128. }
  129. function createTable(id_company, table_dom)
  130. {
  131. var table = $(table_dom).DataTable(
  132. {
  133. 'data': [],
  134. 'order': [[0, 'row_number']],
  135. 'columns':
  136. [
  137. { 'title': 'Division', 'data': 'division', 'defaultContent': '', 'className': 'division' },
  138. { 'title': 'Consignee', 'data': 'consignee', 'defaultContent': '', 'className': 'consignee' },
  139. { 'title': 'Called&nbsp;In', 'data': 'date_called_in', 'defaultContent': '', 'className': 'date_called_in' },
  140. { 'title': 'Dispatch&nbsp;#', 'data': 'dispatch_number', 'defaultContent': '', 'className': 'dispatch_number' },
  141. { 'title': 'Shipper', 'data': 'shipper', 'defaultContent': '', 'className': 'shipper' },
  142. { 'title': 'Ready', 'data': 'date_ready', 'defaultContent': '', 'className': 'date_ready' },
  143. { 'title': 'Driver', 'data': 'id_driver', 'defaultContent': '', 'className': 'id_driver',
  144. 'render': function(data, type, row)
  145. {
  146. var id_driver = row['id_driver'];
  147. if(!id_driver)
  148. return '';
  149. return drivers_by_company[id_company][id_driver]['name'];
  150. }
  151. },
  152. { 'title': 'Trailer', 'data': 'trailer', 'defaultContent': '', 'className': 'trailer' },
  153. { 'title': 'Address&nbsp;1', 'data': 'address_1', 'address_1': '', 'className': 'address_1' },
  154. { 'title': 'Address&nbsp;2', 'data': 'address_2', 'address_2': '', 'className': 'address_2' },
  155. { 'title': 'City', 'data': 'city', 'defaultContent': '', 'className': 'city' },
  156. { 'title': 'State', 'data': 'state', 'defaultContent': '', 'className': 'state' },
  157. { 'title': 'Zip', 'data': 'zip', 'defaultContent': '', 'className': 'zip' },
  158. { 'title': 'Phone', 'data': 'phone', 'defaultContent': '', 'className': 'phone' },
  159. { 'title': 'Ready&nbsp;Time', 'data': 'time_ready', 'defaultContent': '', 'className': 'time_ready' },
  160. { 'title': 'Close&nbsp;Time', 'data': 'time_close', 'defaultContent': '', 'className': 'time_close' },
  161. { 'title': 'Authorization&nbsp;#', 'data': 'dispatch_reference', 'defaultContent': '', 'className': 'dispatch_reference' },
  162. { 'title': 'Ctns', 'data': 'ctns', 'defaultContent': '', 'className': 'ctns' },
  163. { 'title': 'Weight', 'data': 'weight', 'defaultContent': '', 'className': 'weight' },
  164. { 'title': 'Cube', 'data': 'cube', 'defaultContent': '', 'className': 'cube' },
  165. { 'title': 'Pickup&nbsp;Time', 'data': 'time_pickup', 'defaultContent': '&nbsp;', 'className': 'time_pickup' },
  166. { 'title': 'Depart&nbsp;Time', 'data': 'time_depart', 'defaultContent': '&nbsp;', 'className': 'time_depart' },
  167. { 'title': 'BOL&nbsp;Delivered', 'data': 'bol_delivered', 'defaultContent': '&nbsp;', 'className': 'bol_delivered' },
  168. { 'title': 'Acknowledged', 'data': 'date_processed', 'defaultContent': '&nbsp;', 'className': 'date_processed' },
  169. { 'title': '', 'data': 'date_canceled', 'defaultContent': '&nbsp;', 'className': 'date_canceled',
  170. 'render': function(data, type, row)
  171. {
  172. //if the row is already completed, then don't show any buttons
  173. if(row.time_pickup && row.time_depart && row.bol_delivered)
  174. return '';
  175. //if it's been canceled, show the restore button
  176. if(row.date_canceled)
  177. return '<button class="restore"><img src="media/undo-variant.png"/></button>';
  178. //show the cancel button
  179. return '<button class="cancel"><img src="media/close.png"/></button>';
  180. }
  181. }
  182. ],
  183. 'language':
  184. {
  185. 'search': '',
  186. 'searchPlaceholder': "Search Active"
  187. },
  188. 'deferRender': true,
  189. 'lengthChange': false,
  190. 'scrollX': true,
  191. 'fixedColumns':
  192. {
  193. 'leftColumns': 0,
  194. 'rightColumns': 5
  195. },
  196. 'pageLength': 200,
  197. /* 'buttons': [{
  198. text: 'Completed',
  199. action: function(e, dt, node, config)
  200. {
  201. $(e.currentTarget).toggleClass('checked');
  202. if($(e.currentTarget).hasClass('checked'))
  203. {
  204. }
  205. dt.draw();
  206. }
  207. }],
  208. 'dom': 'Bfrtip'
  209. */
  210. });
  211. var driver_options = [
  212. {
  213. "value": "",
  214. "label": "None"
  215. }];
  216. for(var id_driver in drivers_by_company[id_company])
  217. {
  218. var driver = drivers_by_company[id_company][id_driver];
  219. driver_options.push(
  220. {
  221. "value": id_driver,
  222. "label": driver.name
  223. });
  224. }
  225. var editor = new $.fn.dataTable.Editor(
  226. {
  227. idSrc: 'id_file_row',
  228. table: table_dom,
  229. fields:
  230. [{
  231. label: "Pickup Time:",
  232. name: "time_pickup",
  233. type: "datetime",
  234. format: 'MM/DD/YYYY hh:mm A'
  235. },
  236. {
  237. label: "Depart Time:",
  238. name: "time_depart",
  239. type: "datetime",
  240. format: 'MM/DD/YYYY hh:mm A'
  241. },
  242. {
  243. label: "BOL Delivered:",
  244. name: "bol_delivered",
  245. type: "datetime",
  246. format: 'MM/DD/YYYY hh:mm A'
  247. },
  248. {
  249. label: "Trailer:",
  250. name: "trailer",
  251. type: "text"
  252. },
  253. {
  254. label: "Driver:",
  255. name: "id_driver",
  256. type: "select",
  257. options: driver_options
  258. }],
  259. ajax: function(method, url, d, success, error)
  260. {
  261. if(d['action'] === 'edit')
  262. {
  263. //just get the first row
  264. var id_file_row;
  265. for(id_file_row in d['data']);
  266. var row_partial = d['data'][id_file_row];
  267. var properties_auditable = ['time_pickup', 'time_depart', 'bol_delivered'];
  268. var is_auditable = false;
  269. //go thru all the properties on the object
  270. for(var property in row_partial)
  271. {
  272. var value = row_partial[property];
  273. //update our master record
  274. rows[id_file_row][property] = value;
  275. //check if this is an auditable property
  276. if(properties_auditable.indexOf(property) !== -1)
  277. is_auditable = true;
  278. }
  279. if(is_auditable)
  280. {
  281. //send the update up to the server thru api
  282. $.post('api/createRowUpdate.php?id_file_row=' + id_file_row, row_partial)
  283. .done(function(response)
  284. {
  285. console.log(response);
  286. //report to the datatable a full updated row
  287. success({ "data": [ rows[id_file_row] ] });
  288. })
  289. .fail(function(err, xhr, text)
  290. {
  291. console.log(err['responseText']);
  292. //TODO: handle error
  293. });
  294. }
  295. else
  296. {
  297. $.post('api/updateRowImmediate.php?id_file_row=' + id_file_row, row_partial)
  298. .done(function(response)
  299. {
  300. console.log(response);
  301. //report to the datatable a full updated row
  302. success({ "data": [ rows[id_file_row] ] });
  303. })
  304. .fail(function(err, xhr, text)
  305. {
  306. console.log(err['responseText']);
  307. });
  308. }
  309. }
  310. }
  311. });
  312. //attach the editor
  313. $(table_dom).on('click', 'td.time_pickup', function(e) {
  314. editor.bubble(this, 'time_pickup');
  315. });
  316. $(table_dom).on('click', 'td.time_depart', function(e) {
  317. editor.bubble(this, 'time_depart');
  318. });
  319. $(table_dom).on('click', 'td.bol_delivered', function(e) {
  320. editor.bubble(this, 'bol_delivered');
  321. });
  322. $(table_dom).on('click', 'td.id_driver, td.trailer', function(e) {
  323. editor.bubble(this, ['trailer', 'id_driver']);
  324. });
  325. $(table_dom).on('click', 'td.date_canceled button.cancel', function(e)
  326. {
  327. var row = table.row($(this).closest('tr')).data();
  328. var id_file_row = row.id_file_row;
  329. if(confirm('Are you sure you want to cancel that row?'))
  330. {
  331. $.post('api/updateRowImmediate.php?id_file_row=' + id_file_row, { date_canceled: 1 })
  332. .done(function(response)
  333. {
  334. row.date_canceled = new Date();
  335. table.rows().invalidate('data').draw(false);
  336. })
  337. .fail(function(err, xhr, text)
  338. {
  339. console.log(err['responseText']);
  340. });
  341. }
  342. });
  343. $(table_dom).on('click', 'td.date_canceled button.restore', function(e)
  344. {
  345. var row = table.row($(this).closest('tr')).data();
  346. var id_file_row = row.id_file_row;
  347. if(confirm('Are you sure you want to restore that canceled row?'))
  348. {
  349. $.post('api/updateRowImmediate.php?id_file_row=' + id_file_row, { date_canceled: 0 })
  350. .done(function(response)
  351. {
  352. row.date_canceled = null;
  353. table.rows().invalidate('data').draw(false);
  354. })
  355. .fail(function(err, xhr, text)
  356. {
  357. console.log(err['responseText']);
  358. });
  359. }
  360. });
  361. /*
  362. $(table_dom).on('click', 'td.time_pickup, td.time_depart, td.bol_delivered', function(e) {
  363. editor.bubble(this, [ 'time_pickup', 'time_depart', 'bol_delivered' ]);
  364. });
  365. */
  366. return table;
  367. }
  368. function createUpdatesTable(id_company, table_dom)
  369. {
  370. var table = $(table_dom).DataTable(
  371. {
  372. 'data': [],
  373. 'order': [[0, 'date_modified']],
  374. 'columns':
  375. [
  376. { 'title': 'Date', 'data': 'date_modified', 'defaultContent': '&nbsp;', 'className': 'date_modified' },
  377. { 'title': 'User', 'data': 'user_name', 'defaultContent': '&nbsp;', 'className': 'user_name' },
  378. { 'title': 'Dispatch&nbsp;#', 'data': 'dispatch_number', 'defaultContent': '', 'className': 'dispatch_number' },
  379. { 'title': 'Authorization&nbsp;#', 'data': 'dispatch_reference', 'defaultContent': '', 'className': 'dispatch_reference' },
  380. { 'title': 'Pickup&nbsp;Time', 'data': 'time_pickup', 'defaultContent': '&nbsp;', 'className': 'time_pickup' },
  381. { 'title': 'Depart&nbsp;Time', 'data': 'time_depart', 'defaultContent': '&nbsp;', 'className': 'time_depart' },
  382. { 'title': 'BOL&nbsp;Delivered', 'data': 'bol_delivered', 'defaultContent': '&nbsp;', 'className': 'bol_delivered' }
  383. ],
  384. 'language':
  385. {
  386. 'search': '',
  387. 'searchPlaceholder': "Search Updates"
  388. },
  389. 'deferRender': true,
  390. 'lengthChange': false
  391. });
  392. return table;
  393. }