planning-calendar.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. <?php
  2. require_once __DIR__ . '/../config/database.php';
  3. require_once __DIR__ . '/../lib/auth.php';
  4. if (session_status() === PHP_SESSION_NONE) {
  5. session_start();
  6. }
  7. requireLogin();
  8. $pageTitle = 'Planning Calendar';
  9. $siteName = 'Crop Monitor';
  10. $userId = getCurrentUserId();
  11. include __DIR__ . '/../layouts/header.php';
  12. include __DIR__ . '/../layouts/navbar.php';
  13. ?>
  14. <div id="layoutSidenav">
  15. <div id="layoutSidenav_nav"><?php include __DIR__ . '/../layouts/sidebar.php'; ?></div>
  16. <div id="layoutSidenav_content"><main><div class="container-fluid px-4">
  17. <h1 class="mt-4"><?= htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8') ?></h1>
  18. <ol class="breadcrumb mb-4">
  19. <li class="breadcrumb-item"><a href="/dashboard/dashboard.php">Dashboard</a></li>
  20. <li class="breadcrumb-item active">Planning Calendar</li>
  21. </ol>
  22. <!-- custom scripts -->
  23. <script type="text/javascript" src='client-assets/fullcalendar/js/moment.min.js'></script>
  24. <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/locale/en-au.js"></script>
  25. <!-- fullcalendar -->
  26. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.0/fullcalendar.css" />
  27. <!-- <link rel="stylesheet" href="client-assets/fullcalendar/css/fullcalendar.print.css" media='print' /> -->
  28. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.print.css" integrity="sha256-eODYvezY8MWH5O2DbXi3BwOJESNqpDfU1rmBLT72PyQ=" crossorigin="anonymous" media='print' />
  29. <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.0/fullcalendar.js"></script>
  30. <!-- scheduler -->
  31. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar-scheduler/1.9.4/scheduler.css" />
  32. <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar-scheduler/1.9.4/scheduler.js"></script>
  33. <script type="text/javascript" src="https://use.fontawesome.com/1e2844bb90.js"></script>
  34. <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous" />
  35. <!-- Include Bootstrap Datepicker -->
  36. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.css" integrity="sha256-b5ZKCi55IX+24Jqn638cP/q3Nb2nlx+MH/vMMqrId6k=" crossorigin="anonymous" />
  37. <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js" integrity="sha256-5YmaxAwMjIpMrVlK84Y/+NjCpKnFYa8bWWBbUHSBGfU=" crossorigin="anonymous"></script>
  38. <!-- Bootstrap Date-Picker Plugin -->
  39. <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.4.1/js/bootstrap-datepicker.min.js"></script>
  40. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.4.1/css/bootstrap-datepicker3.css"/>
  41. <style>
  42. .fc-view table {
  43. margin-bottom: 0px;
  44. }
  45. .fc-content {
  46. /* color: white !important; */
  47. }
  48. .fc-head-container {
  49. background-color: #D82508;
  50. color: white;
  51. border: 1px solid #D82508 !important;
  52. }
  53. </style>
  54. <div class="container-fluid">
  55. <div class="row">
  56. <div class="col">
  57. <div id="calendar"></div>
  58. </div>
  59. </div>
  60. </div>
  61. <!-- Modal to Add Event -->
  62. <div class="modal" id="createEventModal" tabindex="-1" role="dialog" aria-hidden="true" >
  63. <div class="modal-dialog" role="document">
  64. <!-- Modal content-->
  65. <div class="modal-content">
  66. <div id="modalHeader" class="modal-header">
  67. <h4 class="modal-title">Add Event to Schedule</h4>
  68. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
  69. </div>
  70. <div class="modal-body">
  71. <div class="control-group">
  72. <label class="control-label" for="inputPatient">Event:</label>
  73. <div class="field desc">
  74. <input class="form-control" id="title" name="title" placeholder="Event" type="text" value="">
  75. <input type="hidden" id="modx_user_id" value="<?= (int) $userId ?>">
  76. </div>
  77. </div>
  78. <hr>
  79. <div class="row">
  80. <div class="col">
  81. <label class="control-label" for="startTime">Start Time:</label>
  82. <input class="form-control startTime" type="text" id="startTime" >
  83. </div>
  84. <div class="col">
  85. <label class="control-label" for="endTime">End Time:</label>
  86. <input class="form-control endTime" type="text" id="endTime" >
  87. </div>
  88. </div>
  89. <script type="text/javascript">
  90. $(function () {
  91. $('.startTime').datetimepicker();
  92. $('.endTime').datetimepicker({
  93. //format: 'L',
  94. format: 'yyyy-mm-dd hh:ii',
  95. daysOfWeekDisabled: [0, 6],
  96. collapse: true,
  97. useCurrent: false //Important! See issue #1075
  98. });
  99. $(".startTime").on("dp.change", function (e) {
  100. $('.endTime').data("DateTimePicker").minDate(e.date);
  101. });
  102. $(".endTime").on("dp.change", function (e) {
  103. $('.startTime').data("DateTimePicker").maxDate(e.date);
  104. });
  105. });
  106. </script>
  107. </div>
  108. <div id="modalFooter" class="modal-footer">
  109. <button type="button" class="btn btn-secondary" data–dismiss="createEventModal" aria–hidden="true">Close</button>
  110. <button type="submit" class="btn btn-success" id="submitButton" aria–hidden="true">Save</button>
  111. </div>
  112. <!--
  113. <div class="control-group">
  114. <label class="control-label" for="when">When:</label>
  115. <div class="controls controls-row" id="when" style="margin-top:5px;"> </div>
  116. </div>
  117. -->
  118. </div>
  119. </div>
  120. </div>
  121. </div>
  122. <!-- Modal to Event Details -->
  123. <div class="modal" id="calendarModal" tabindex="-1" role="dialog" aria-hidden="true" >
  124. <div class="modal-dialog" role="document">
  125. <div class="modal-content">
  126. <div id="modalHeader" class="modal-header">
  127. <h4 class="modal-title">Event Details</h4>
  128. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
  129. </div>
  130. <div id="modalBody" class="modal-body">
  131. <!-- <div id="modalWhen" style="margin-top:5px;"></div> -->
  132. <div class="row">
  133. <div class="col" >
  134. <h4 id="modalTitle" class="modal-title"></h4>
  135. </div>
  136. </div>
  137. <hr>
  138. <div class="row">
  139. <div class="col" >
  140. <label for="eventID">From:</label>
  141. <input type="text" class="form-control form-control-sm datetimepicker" id="startTime" readonly>
  142. </div>
  143. </div>
  144. <div class="row">
  145. <div class="col" >
  146. <label for="eventID">To:</label>
  147. <input type="text" class="form-control form-control-sm datetimepicker" id="endTime" readonly>
  148. </div>
  149. </div>
  150. <!--
  151. <hr>
  152. <div class="row">
  153. <div class="col" >
  154. <div id="modalWhen" style="margin-top:5px;"></div>
  155. </div>
  156. </div>
  157. -->
  158. <script type="text/javascript">
  159. $(document).ready(function(){
  160. $('.datetimepicker').datetimepicker({
  161. format: 'dddd, MMMM Do YYYY, h:mm',
  162. showTodayButton: true,
  163. useCurrent: true,
  164. stepping: 60,
  165. daysOfWeekDisabled: [0, 6],
  166. collapse: true,
  167. useCurrent: false //Important! See issue #1075
  168. });
  169. });
  170. </script>
  171. </div>
  172. <input type="hidden" id="eventID"/>
  173. <div class="modal-footer">
  174. <button type="button" class="btn btn-secondary" data–dismiss="modal" aria–hidden="true">Cancel</button>
  175. <button type="submit" class="btn btn-success" id="updateButton" aria–hidden="true">Update</button>
  176. <button type="submit" class="btn btn-danger" id="deleteButton">Delete</button>
  177. </div>
  178. </div>
  179. </div>
  180. </div>
  181. <!-- Modal-->
  182. <script type="text/javascript">
  183. $(document).ready(function(){
  184. var calendar = $('#calendar').fullCalendar({ // assign calendar
  185. plugins: [ 'bootstrap4', 'interaction', 'list' ],
  186. themeSystem: 'bootstrap4',
  187. timeZone: 'UTC',
  188. defaultView: 'month',
  189. aspectRatio: 2,
  190. allDayDefault: true,
  191. stick: true,
  192. header: {
  193. left: 'today prev,next',
  194. center: 'title ',
  195. right: 'timeGridThreeMonths, month, listWeek, listMonth' //agendaWeek, agendaDay,
  196. },
  197. droppable: true, // this allows things to be dropped onto the calendar
  198. eventLimit: true, // when too many events in a day, show the popover
  199. displayEventTime: false, //https://fullcalendar.io/docs/displayEventTime
  200. editable: true, // enable draggable events
  201. eventStartEditable: true,
  202. eventResizableFromStart: true,
  203. eventDurationEditable: true,
  204. resizable: true,
  205. selectable: true,
  206. allDaySlot: false,
  207. contentHeight: 'auto',
  208. weekNumbers: true,
  209. weekNumbersWithinDays: true,
  210. views: {
  211. timeGridFourDays: {
  212. type: 'timeline',
  213. duration: { days: 5 },
  214. buttonText: '4 days'
  215. },
  216. timeGridFourWeeks: {
  217. type: 'timeline',
  218. duration: { days: 28 },
  219. buttonText: '4 Weeks'
  220. },
  221. timeGridThreeMonths: {
  222. buttonText: '3 Months',
  223. type: 'timeline',
  224. duration: { days: 95 },
  225. buttonText: '3 Months'
  226. },
  227. month: {
  228. buttonText: 'Month',
  229. titleFormat: '#M. MMMM YYYY'
  230. //allDay: true
  231. },
  232. agendaWeek: {
  233. allDaySlot: true,
  234. nowIndicator: true
  235. },
  236. agendaDay: {
  237. minTime: '05:00:00',
  238. maxTime: '19:00:00',
  239. nowIndicator: true
  240. },
  241. listDay: {
  242. buttonText: 'List Day'
  243. },
  244. listWeek: { buttonText: 'List Week' },
  245. listMonth: { buttonText: 'List Month' }
  246. },
  247. resourceLabelText: 'Current Jobs',
  248. schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
  249. //resources: 'https://fullcalendar.io/demo-resources.json?with-nesting&with-colors',
  250. //events: 'https://fullcalendar.io/demo-events.json?single-day&for-resource-timeline'
  251. //events: "index.php?view=1", // request to load current events
  252. //events: '[[!calendar_index? &view=1]]',
  253. eventSources: [
  254. 'ci.html?view=1',
  255. 'http://api.openweathermap.org/data/2.5/forecast?lat=-41.179&lon=147.545&cnt=10&mode=json&units=metric&appid=a164361b43628b08cfa06c0a9fd03a02', //needs formatting to show min-max temps for each day
  256. ],
  257. eventTextColor: '#fff !important',
  258. eventRender: function(event, element) {
  259. // PLANT IS GREEN
  260. if(event.type == 'plant' || event.type == 'Dry Ash Test') {
  261. element.css({
  262. 'background-color': '#008000',
  263. 'border-color': '#008000'
  264. });
  265. }
  266. // SOIL IS BROWN
  267. else if(event.type == 'soil' || event.type == 'Soil Test') {
  268. element.css({
  269. 'background-color': '#a52a2a',
  270. 'border-color': '#a52a2a'
  271. });
  272. }
  273. // WATER IS BLUE
  274. else if(event.type == 'water') {
  275. element.css({
  276. 'background-color': '#0000FF',
  277. 'border-color': '#0000FF',
  278. });
  279. }
  280. // ANIMAL IS ORANGE
  281. else if(event.type == 'animal') {
  282. element.css({
  283. 'background-color': '#FFA500',
  284. 'border-color': '#FFA500'
  285. });
  286. }
  287. // WEATHER IS BLACK
  288. else if(event.type == 'weather') {
  289. element.css({
  290. 'background-color': '#ffffff',
  291. 'border-color': '#ffffff',
  292. 'color': '#212529 !important',
  293. 'font-weight': 'bold',
  294. 'text-align': 'center'
  295. });
  296. }
  297. // REST IS SILVER
  298. else {
  299. element.css({
  300. 'background-color': '#C0C0C0',
  301. 'border-color': '#C0C0C0'
  302. });
  303. }
  304. },
  305. eventClick: function(event, jsEvent, view) { // when some one click on any event
  306. endtime = $.fullCalendar.moment(event.end).format('dddd, MMMM Do YYYY, h:mm');
  307. starttime = $.fullCalendar.moment(event.start).format('dddd, MMMM Do YYYY, h:mm');
  308. var mywhen = starttime + ' – ' + endtime;
  309. $('#calendarModal #modx_user_id').html(modx_user_id);
  310. $('#calendarModal #modalTitle').html(event.title);
  311. $('#calendarModal #modalWhen').text(mywhen);
  312. $('#calendarModal #eventID').val(event.id);
  313. $('#calendarModal #startTime').val(starttime);
  314. $('#calendarModal #endTime').val(endtime);
  315. $('#calendarModal').modal();
  316. },
  317. select: function(start, end, jsEvent) { // click on empty time slot
  318. endtime = $.fullCalendar.moment(end).format('dddd, MMMM Do YYYY, h:mm');
  319. starttime = $.fullCalendar.moment(start).format('dddd, MMMM Do YYYY, h:mm');
  320. var mywhen = starttime + ' – ' + endtime;
  321. start = moment(start).format('YYYY-MM-DD hh:mm');
  322. end = moment(end).format('YYYY-MM-DD hh:mm');
  323. $('#createEventModal #startTime').val(start);
  324. $('#createEventModal #endTime').val(end);
  325. $('#createEventModal #when').text(mywhen);
  326. $('#createEventModal').modal('toggle');
  327. },
  328. eventDrop: function(event, delta){ // event drag and drop
  329. $.ajax({
  330. //url: 'index.php',
  331. url: '/api/calendar.php',
  332. data: 'action=update&title='+event.title+'&start='+moment(event.start).format()+'&end='+moment(event.end).format()+'&id='+event.id+'&modx_user_id='+modx_user_id ,
  333. type: "POST",
  334. success: function(json) {
  335. //alert(json);
  336. }
  337. });
  338. },
  339. eventResize: function(event) { // resize to increase or decrease time of event
  340. $.ajax({
  341. //url: 'index.php',
  342. url: '/api/calendar.php',
  343. data: 'action=update&title='+event.title+'&start='+moment(event.start).format()+'&end='+moment(event.end).format()+'&id='+event.id+'&modx_user_id='+modx_user_id,
  344. type: "POST",
  345. success: function(json) {
  346. //alert(json);
  347. }
  348. });
  349. }
  350. });
  351. $('#deleteButton').on('click', function(e){ // delete event clicked
  352. // We don't want this to act as a link so cancel the link action
  353. e.preventDefault();
  354. doDelete(); // send data to delete function
  355. });
  356. function doDelete(){ // delete event
  357. $("#calendarModal").modal('hide');
  358. var eventID = $('#eventID').val();
  359. var modx_user_id = $('#modx_user_id').val();
  360. $.ajax({
  361. //url: 'index.php',
  362. url: '/api/calendar.php',
  363. data: 'action=delete&id='+eventID+'&modx_user_id='+modx_user_id,
  364. type: "POST",
  365. success: function(json) {
  366. if(json == 1)
  367. $("#calendar").fullCalendar('removeEvents',eventID);
  368. else
  369. return false;
  370. }
  371. });
  372. }
  373. $('#submitButton').on('click', function(e){ // add event submit
  374. // We don't want this to act as a link so cancel the link action
  375. e.preventDefault();
  376. doSubmit(); // send to form submit function
  377. });
  378. function doSubmit(){ // add event
  379. $("#createEventModal").modal('hide');
  380. var title = $('#title').val();
  381. var modx_user_id = $('#modx_user_id').val();
  382. var startTime = $('#startTime').val();
  383. var endTime = $('#endTime').val();
  384. $.ajax({
  385. //url: 'index.php',
  386. url: '/api/calendar.php',
  387. data: 'action=add&title='+title+'&start='+startTime+'&end='+endTime+'&modx_user_id='+modx_user_id,
  388. type: "POST",
  389. success: function(json) {
  390. $("#calendar").fullCalendar('renderEvent',
  391. {
  392. id: json.id,
  393. title: title,
  394. start: startTime,
  395. end: endTime,
  396. },
  397. true);
  398. }
  399. });
  400. }
  401. $('#updateButton').on('click', function(e){ // delete event clicked
  402. // We don't want this to act as a link so cancel the link action
  403. e.preventDefault();
  404. doUpdate(); //send data to delete function
  405. });
  406. function doUpdate(){ // delete event
  407. $("#calendarModal").modal('hide');
  408. var startTime = $('#calendarModal #startTime').val();
  409. var endTime = $('#calendarModal #endTime').val();
  410. var quote = $('#calendarModal #quote').val();
  411. var eventType = $('#calendarModal #eventType').val();
  412. var eventID = $('#calendarModal #eventID').val();
  413. var quid = $('#calendarModal #quid').val();
  414. $.ajax({
  415. //url: 'index.php',
  416. url: '/api/calendar.php',
  417. data: 'action=project_update&id='+eventID+'&quote='+quote+'&title='+title+'&start='+startTime+'&end='+endTime+'&eventType='+eventType+'&quid='+quid,
  418. type: "POST",
  419. success: function(json) {
  420. $("#calendar").fullCalendar('renderEvent',
  421. {
  422. id: eventID,
  423. quote: quote,
  424. title: quote,
  425. start: startTime,
  426. end: endTime,
  427. type: eventType,
  428. quid: quid,
  429. },
  430. true);
  431. }
  432. });
  433. }
  434. function fetchWeatherForecast(location, $http, $filter){
  435. $http.get("http://api.openweathermap.org/data/2.5/forecast?lat=-41.179&lon=147.545&cnt=10&mode=json&units=metric&appid=a164361b43628b08cfa06c0a9fd03a02").success(function(data) {
  436. addWeatherToCalendar(data, $filter);
  437. });
  438. }
  439. function addWeatherToButton(weatherData, $filter){
  440. var date = new Date();
  441. for (var i = 0; i < weatherData.list.length; i++) {
  442. var element = angular.element('td.fc-day[data-date="' + $filter('date')(date, 'yyyy-MM-dd').toString() + '"]')
  443. var html = element[0].innerHTML
  444. var icon = weatherData.list[i].weather[0].icon
  445. var temp = weatherData.list[i].temp.max + "-" +weatherData.list[i].temp.min
  446. element.append("<span><img src='http://openweathermap.org/img/w/"+icon+".png'/>"+temp+"</span>")
  447. date.setDate(date.getDate() + 1);
  448. }
  449. }
  450. });
  451. </script>
  452. </div></main>
  453. <?php include __DIR__ . '/../layouts/footer.php'; ?>
  454. </div></div>