planning-calendar.php 18 KB

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