|
@@ -87,27 +87,156 @@
|
|
|
</form>
|
|
|
<hr class="my-2">
|
|
|
<div class="appt-calendar-col">
|
|
|
- <div class="stag-fc-container">
|
|
|
-
|
|
|
- </div>
|
|
|
+ <div class="stag-fc-container"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div class="stag-popup stag-popup-sm mcp-theme-1" stag-popup-key="client-add-appointment">
|
|
|
+ <form method="POST" action="/api/appointment/create" id="newApptForm">
|
|
|
+ <h3 class="stag-popup-title">
|
|
|
+ <span>Book New Appointment</span>
|
|
|
+ <a href="#" class="ml-auto text-secondary"
|
|
|
+ onclick="return closeStagPopup()"><i class="fa fa-times-circle"></i></a>
|
|
|
+ </h3>
|
|
|
+ <input type="hidden" name="clientUid" :value="newAppointment.clientUid">
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Patient
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <input type="text"
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ :value="client.nameStr" readonly>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Pro
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <select id="addApptPro" name="proUid" required
|
|
|
+ v-model="newAppointment.proUid"
|
|
|
+ class="form-control form-control-sm">
|
|
|
+ @foreach($pros as $iPro)
|
|
|
+ <option value="{{$iPro->uid}}">
|
|
|
+ {{$iPro->displayName()}}
|
|
|
+ </option>
|
|
|
+ @endforeach
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <input type="hidden" name="referringProUid" value="{{ $pro->uid }}">
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Date
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <input type="date" name="date" required
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ v-model="newAppointment.date">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Start Time
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <input type="time" name="startTime" required
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ v-model="newAppointment.startTime">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ End Time
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <input type="time" name="endTime"
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ v-model="newAppointment.endTime">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <input type="hidden" name="timeZone" :value="timezone">
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Timezone
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <input type="text"
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ :value="timezone" readonly>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Title
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <input type="text" name="title"
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ v-model="newAppointment.title">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row mb-2">
|
|
|
+ <div class="col-3 text-secondary">
|
|
|
+ Description
|
|
|
+ </div>
|
|
|
+ <div class="col-9 font-weight-bold">
|
|
|
+ <textarea name="description"
|
|
|
+ class="form-control form-control-sm"
|
|
|
+ v-model="newAppointment.description"></textarea>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="d-flex align-items-center justify-content-center">
|
|
|
+ <button class="btn btn-sm btn-primary mr-2"
|
|
|
+ :disabled="inProgress"
|
|
|
+ v-on:click.prevent="addAppointment()">Submit</button>
|
|
|
+ <button class="btn btn-sm btn-default border"
|
|
|
+ onclick="return closeStagPopup()">Cancel</button>
|
|
|
+ </div>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
+ <div class="stag-popup mcp-theme-1" stag-popup-key="client-edit-appointment">
|
|
|
+ <form method="POST" action="/api/appointment/update">
|
|
|
+ Edit
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<script>
|
|
|
(function() {
|
|
|
|
|
|
+ <?php
|
|
|
+ $patient->nameStr = $patient->displayName();
|
|
|
+ $clientObject = json_encode($patient);
|
|
|
+ ?>
|
|
|
+
|
|
|
function init() {
|
|
|
window.calendarApp = new Vue({
|
|
|
el: '#calendarApp',
|
|
|
data: {
|
|
|
+ client: {!! json_encode($patient) !!},
|
|
|
+
|
|
|
calendar: null,
|
|
|
proMeta: {!! json_encode($proMeta) !!},
|
|
|
proIds: ['{{ $pro->id }}'],
|
|
|
timezone: 'EASTERN',
|
|
|
+ today: new Date('{{ date('Y-m-d 00:00:00') }}'),
|
|
|
|
|
|
// user clicks/selection
|
|
|
selectedSlot: null,
|
|
|
selectedEvent: null,
|
|
|
+
|
|
|
+ // new appt.
|
|
|
+ newAppointment: {
|
|
|
+ proUid: '',
|
|
|
+ referringProUid: '',
|
|
|
+ date: '',
|
|
|
+ startTime: '',
|
|
|
+ endTime: '',
|
|
|
+ timeZone: '',
|
|
|
+ title: '',
|
|
|
+ description: '',
|
|
|
+ },
|
|
|
+ inProgress: false
|
|
|
},
|
|
|
methods: {
|
|
|
// init
|
|
@@ -164,6 +293,16 @@
|
|
|
self.proIds = $(this).val();
|
|
|
self.refreshEvents();
|
|
|
});
|
|
|
+ $('#addApptPro')
|
|
|
+ .select2({
|
|
|
+ width: '100%',
|
|
|
+ templateResult: function(_state) {
|
|
|
+ return $('<span class="mcp-theme-1"><span>' + _state.text + '</span></span>');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .on('change', function() {
|
|
|
+ self.newAppointment.proUid = $(this).val();
|
|
|
+ });
|
|
|
},
|
|
|
initCalendar: function () {
|
|
|
let self = this;
|
|
@@ -217,6 +356,7 @@
|
|
|
},
|
|
|
eventClick: function(info) {
|
|
|
self.selectedEvent = info.event;
|
|
|
+ self.showEditAppointmentModal();
|
|
|
},
|
|
|
selectAllow: function(info) { // allow only single selections
|
|
|
let seconds = info.end.getTime() - info.start.getTime(),
|
|
@@ -229,22 +369,36 @@
|
|
|
},
|
|
|
select: function(info) {
|
|
|
self.selectedSlot = info;
|
|
|
+ if(self.today.getTime() <= self.selectedSlot.start.getTime()) {
|
|
|
+ $('<a href="#" class="add-overlay ' +
|
|
|
+ (info.allDay ? 'add-overlay-day-grid' : 'add-overlay-time-grid') + '">Add</a>')
|
|
|
+ .on('mousedown', function() {
|
|
|
+ self.showAddAppointmentModal();
|
|
|
+ return false;
|
|
|
+ })
|
|
|
+ .appendTo('.fc-highlight');
|
|
|
+ }
|
|
|
},
|
|
|
eventDrop: self.eventMovedOrResized,
|
|
|
eventResize: self.eventMovedOrResized
|
|
|
});
|
|
|
this.calendar.render();
|
|
|
},
|
|
|
+ dateStr: function(_dateTime) {
|
|
|
+ return _dateTime.getFullYear() + "-" +
|
|
|
+ ("0"+(_dateTime.getMonth()+1)).slice(-2) + "-" +
|
|
|
+ ("0" + _dateTime.getDate()).slice(-2);
|
|
|
+ },
|
|
|
+ timeStr: function(_dateTime) {
|
|
|
+ return ("0" + _dateTime.getHours()).slice(-2) + ":" +
|
|
|
+ ("0" + _dateTime.getMinutes()).slice(-2);
|
|
|
+ },
|
|
|
eventMovedOrResized: function (info) {
|
|
|
- let date = info.event.start.getFullYear() + "-" +
|
|
|
- ("0"+(info.event.start.getMonth()+1)).slice(-2) + "-" +
|
|
|
- ("0" + info.event.start.getDate()).slice(-2);
|
|
|
- let startTime = ("0" + info.event.start.getHours()).slice(-2) + ":" +
|
|
|
- ("0" + info.event.start.getMinutes()).slice(-2);
|
|
|
+ let date = this.dateStr(info.event.start);
|
|
|
+ let startTime = this.timeStr(info.event.start);
|
|
|
let endTime = null;
|
|
|
if(info.event.end) {
|
|
|
- endTime = ("0" + info.event.end.getHours()).slice(-2) + ":" +
|
|
|
- ("0" + info.event.end.getMinutes()).slice(-2);
|
|
|
+ endTime = this.timeStr(info.event.end);
|
|
|
}
|
|
|
$.post('/api/appointment/updateDateAndTime', {
|
|
|
uid: info.event.extendedProps.appointmentUid,
|
|
@@ -258,6 +412,53 @@
|
|
|
},
|
|
|
refreshEvents: function() {
|
|
|
this.calendar.refetchEvents();
|
|
|
+ },
|
|
|
+ showAddAppointmentModal: function() {
|
|
|
+ // setup model data
|
|
|
+ let startTime = this.timeStr(this.selectedSlot.start);
|
|
|
+ this.newAppointment.clientUid = this.client.uid;
|
|
|
+ this.newAppointment.proUid = '';
|
|
|
+ this.newAppointment.referringProUid = '';
|
|
|
+ this.newAppointment.date = this.dateStr(this.selectedSlot.start);
|
|
|
+ this.newAppointment.startTime = startTime === '00:00' ? '' : startTime;
|
|
|
+ this.newAppointment.endTime = '';
|
|
|
+ this.newAppointment.timeZone = this.timezone;
|
|
|
+ this.newAppointment.title = '';
|
|
|
+ this.newAppointment.description = '';
|
|
|
+ Vue.nextTick(function() {
|
|
|
+ $('#addApptPro').find('option').prop('selected', false);
|
|
|
+ $('#addApptPro').trigger('change');
|
|
|
+ showStagPopup('client-add-appointment');
|
|
|
+ });
|
|
|
+ },
|
|
|
+ addAppointment: function() {
|
|
|
+ let form = $('#newApptForm');
|
|
|
+ if(!form[0].checkValidity()) {
|
|
|
+ form[0].reportValidity();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ this.inProgress = true;
|
|
|
+ let self = this;
|
|
|
+ showMask();
|
|
|
+ $.post(form.attr('action'), form.serialize(), function(_data) {
|
|
|
+ if(_data) {
|
|
|
+ if(_data.success) {
|
|
|
+ self.refreshEvents();
|
|
|
+ closeStagPopup();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ toastr.error(_data.message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ toastr.error('Unable to book appointment!');
|
|
|
+ }
|
|
|
+ self.inProgress = false;
|
|
|
+ hideMask();
|
|
|
+ }, 'json');
|
|
|
+ },
|
|
|
+ showEditAppointmentModal: function() {
|
|
|
+ showStagPopup('client-edit-appointment');
|
|
|
}
|
|
|
},
|
|
|
mounted: function() {
|