Browse Source

Doctor portal complete, still more work to go

production
Yiğit Çolakoğlu 4 years ago
parent
commit
c5686b0f34
13 changed files with 130 additions and 52 deletions
  1. +5
    -0
      package-lock.json
  2. +2
    -1
      package.json
  3. +3
    -2
      src/App.vue
  4. +3
    -2
      src/components/AppointmentModal.vue
  5. +2
    -1
      src/components/LoginForm.vue
  6. +1
    -1
      src/components/PatientCard.vue
  7. +22
    -9
      src/components/PatientModal.vue
  8. +9
    -5
      src/main.js
  9. +1
    -0
      src/router/index.js
  10. +11
    -6
      src/views/Calendar.vue
  11. +18
    -5
      src/views/Disabled.vue
  12. +1
    -0
      src/views/Login.vue
  13. +52
    -20
      src/views/Patients.vue

+ 5
- 0
package-lock.json View File

@ -14826,6 +14826,11 @@
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
"dev": true
},
"vue-toastification": {
"version": "1.7.11",
"resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-1.7.11.tgz",
"integrity": "sha512-CT/DYttb/VtWDNdhJG0BskLVfveZq5rGOgO/u3qTX+RPQQzX0WSai8VVxxUuvR8UpxfSGPS+JQleR33bo3Vadg=="
},
"w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/w3c-hr-time/download/w3c-hr-time-1.0.2.tgz",


+ 2
- 1
package.json View File

@ -33,7 +33,8 @@
"vue-popperjs": "^2.3.0",
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.2.0",
"vue-tailwindcss-typeahead": "^1.0.1"
"vue-tailwindcss-typeahead": "^1.0.1",
"vue-toastification": "^1.7.11"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",


+ 3
- 2
src/App.vue View File

@ -32,6 +32,7 @@ import Vue from 'vue'
import Login from "@/views/Login"
import router from './router'
import LoadingSpinner from "@/components/LoadingSpinner";
import axios from 'axios'
export default Vue.extend({
components : {
@ -61,7 +62,7 @@ export default Vue.extend({
this.loggedin = state;
if(state) {
router.push("/calendar")
this.$axios.get('/profile', {
axios.get('/profile', {
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
@ -85,7 +86,7 @@ export default Vue.extend({
return;
}
try{
const response = await this.$axios.get('/profile',{
const response = await axios.get('/profile',{
headers : {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}


+ 3
- 2
src/components/AppointmentModal.vue View File

@ -70,6 +70,7 @@
import DatetimePicker from '@/components/DatetimePicker'
import Typeahead from '@/components/Typeahead';
import dayjs from 'dayjs'
import axios from 'axios'
export default{
components: {
@ -98,7 +99,7 @@ export default{
this.showModal = true;
},
saveClicked: function(){
this.$axios.post('/appointments', {
axios.post('/appointments', {
start: dayjs(this.start, 'YYYY-MM-DDTHH:mm').toISOString(),
end: dayjs(this.end, 'YYYY-MM-DDTHH:mm').toISOString(),
online: this.online,
@ -132,7 +133,7 @@ export default{
this.patient = entry.patient;
},
updatePatientSuggestions: function(searchTerm){
this.$axios.get('/patients', {
axios.get('/patients', {
params: {
name: searchTerm
},


+ 2
- 1
src/components/LoginForm.vue View File

@ -66,6 +66,7 @@
<script>
import { StorageManagement, isEmail } from "@sebgroup/frontend-tools";
import axios from 'axios'
export default {
// Data
@ -90,7 +91,7 @@ export default {
}
this.emailValid = true
this.loginError = false
this.$axios.post('/login', {
axios.post('/login', {
email: this.email,
password: this.password
})


+ 1
- 1
src/components/PatientCard.vue View File

@ -1,5 +1,5 @@
<template>
<div @click="$emit('showModal', patient)" class="font-sans items-center flex flex-col md:flex-row hover:bg-gray-100">
<div @click="$emit('showModal', index)" class="font-sans items-center flex flex-col md:flex-row hover:bg-gray-100">
<div class="">
<h5>{{ patient.name }}</h5>
<p> {{ patient.phone }}</p>


+ 22
- 9
src/components/PatientModal.vue View File

@ -12,25 +12,33 @@
</div>
<div class="divide-y divide-gray-200">
<div class="py-8 text-base leading-6 space-y-4 text-gray-700 sm:text-lg sm:leading-7">
<div class="flex items-center space-x-4">
<div class="flex flex-col items-center space-x-4">
<div class="ml-auto w-full flex flex-col">
<label class="leading-loose">Name:</label>
<input v-model="patient.name" type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col">
<label class="leading-loose">Phone:</label>
<input v-model="patient.phone" type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col">
<label class="leading-loose">Name</label>
<input type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
<label class="leading-loose">E-Mail:</label>
<input v-model="patient.email" type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col">
<label class="leading-loose">Phone</label>
<input type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
<label class="leading-loose">TC No:</label>
<input v-model="patient.tcno" type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col">
<label class="leading-loose">Phone</label>
<input type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
<label class="leading-loose">Hes Code:</label>
<input v-model="patient.hescode" type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
</div>
<div class="pt-4 flex items-center space-x-4">
<button @click="showModal = false" class="flex justify-center items-center w-full text-gray-900 px-4 py-3 rounded-md focus:outline-none">
<svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg> Cancel
</button>
<button @click="saveClicked" class="bg-blue-500 flex justify-center items-center w-full text-white px-4 py-3 rounded-md focus:outline-none">Create</button>
<button @click="saveClicked" class="bg-blue-500 flex justify-center items-center w-full text-white px-4 py-3 rounded-md focus:outline-none">{{ button }}</button>
</div>
</div>
</div>
@ -41,18 +49,21 @@
</template>
<script>
// TODO protocol number input
export default {
name: "PatientModal",
data: function(){
return {
showModal: false,
patient: {}
patient: {},
button: "Create"
}
},
methods: {
showPatient: function(patient){
this.patient = patient;
this.showModal = true;
this.button = "Save"
},
emptyModal: function() {
this.patient = {
@ -60,8 +71,10 @@ export default {
phone: "",
}
this.showModal = true
this.button = "Create"
},
saveClicked: function(){
this.showModal = false
this.$emit("savePatient", this.patient);
},
},


+ 9
- 5
src/main.js View File

@ -2,14 +2,18 @@ import Vue from 'vue'
import App from './App.vue'
import router from './router'
import '@/assets/styles/index.css'
import Toast from "vue-toastification";
import "vue-toastification/dist/index.css";
import axios from "axios";
const axiosConfig = {
baseUrl: process.env.VUE_APP_API_BASE_URL,
timeout: 30000
}
axios.defaults.baseURL = process.env.VUE_APP_API_BASE_URL
Vue.prototype.$axios = axios.create(axiosConfig)
const options = {
};
Vue.use(Toast, options);
//Production variables
Vue.config.productionTip = false
Vue.config.devtools = true
Vue.config.performance = true


+ 1
- 0
src/router/index.js View File

@ -20,6 +20,7 @@ const routes = [
name: 'Disabled',
component: () => import('../views/Disabled.vue')
},
{path: '/', redirect: '/calendar'}
]
const router = new VueRouter({


+ 11
- 6
src/views/Calendar.vue View File

@ -33,6 +33,7 @@ import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from "@fullcalendar/timegrid"
import interactionPlugin from '@fullcalendar/interaction'
import { mixin as clickaway } from 'vue-clickaway';
import axios from 'axios'
import Popper from "popper.js";
export default {
@ -85,14 +86,18 @@ export default {
this.calendarElementClickedLast = false
},
deleteAppointment: function(){
this.$axios.post('/delete',this.selectedEvent.extendedProps.appObj,{
axios.post('/delete',this.selectedEvent.extendedProps.appObj,{
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
},
}).then((_) => { // eslint-disable-line no-unused-vars
this.selectedEvent.remove();
this.popoverShow = false;
})
this.$toast.success("Appointment deleted successfully.")
}).catch((err) => {
console.log(err);
this.$toast.error("Couldn't delete appointment");
})
},
eventClicked: function(info){
console.log()
@ -113,7 +118,7 @@ export default {
console.log(info)
},
getEvents: function(info, successCallback, failureCallback){
this.$axios.get('/appointments', {
axios.get('/appointments', {
params: {
start: info.startStr,
end: info.endStr
@ -146,12 +151,12 @@ export default {
})
.catch((err) => {
console.log(err);
console.log("ERROR PLACEHOLDER");
this.$toast.error("Error fetching appointments.");
failureCallback(err)
});
},
getDisabled: function(info, successCallback, failureCallback){
this.$axios.get('/disabled', {
axios.get('/disabled', {
params: {
start: info.startStr,
end: info.endStr
@ -178,7 +183,7 @@ export default {
})
.catch((err) => {
console.log(err);
console.log("ERROR PLACEHOLDER");
this.$toast.error("Error fetching disabled rules.");
failureCallback(err)
});
},


+ 18
- 5
src/views/Disabled.vue View File

@ -9,6 +9,7 @@
<script>
import DisabledCard from "@/components/DisabledCard";
import axios from 'axios'
export default {
name: "Disabled",
@ -20,17 +21,20 @@ export default {
},
methods: {
updateRule: function(rule){
this.$axios.post('/disabled/update', rule.obj,{
axios.post('/disabled/update', rule.obj,{
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then((result) =>{
this.rules[rule.index] = rule.obj;
console.log(result)
}).catch((err) => {
console.log(err);
this.$toast.error("Couldn't update rule")
})
},
createRule: function(rule){
this.$axios.post('/disabled', rule.obj,{
axios.post('/disabled', rule.obj,{
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
@ -38,10 +42,13 @@ export default {
this.rules.push(rule.obj);
this.$refs.newRule.disabled = {start: '', duration: '', repetition: ''}
console.log(result)
}).catch((err) => {
console.log(err)
this.$toast.error("Couldn't create rule")
})
},
deleteRule: function(rule){
this.$axios.get('/disabled/delete', {
axios.get('/disabled/delete', {
params: {
id: rule.obj.id
},
@ -51,18 +58,24 @@ export default {
}).then((result) =>{
this.rules.splice(rule.index)
console.log(result)
}).catch((err) => {
console.log(err)
this.$toast.error("Couldn't delete rule")
})
},
},
mounted(){
this.$axios.get('/disabled/rules', {
axios.get('/disabled/rules', {
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then((result) =>{
console.log(result.data)
this.rules = result.data
}) // TODO err handling here as well
}).catch((err) => {
console.log(err);
this.$toast.error("Couldn't fetch rules")
})
}
}


+ 1
- 0
src/views/Login.vue View File

@ -5,6 +5,7 @@
</template>
<script>
import LoginForm from '@/components/LoginForm.vue';
export default {


+ 52
- 20
src/views/Patients.vue View File

@ -3,10 +3,10 @@
<PatientSearchField @new="showEmptyPatientModal" class=" md:w-4/6 md:mx-auto" @fieldsUpdated="search" title="Patient"/>
<Pagination class="h-10 my-8 mx-auto" :pages="pages" :currentPage="searchFields.page + 1" @page-changed="pageChanged"/>
<div class="md:w-4/6 md:mx-auto md:h-1/4 border-gray-200 md:border-t md:border-b rounded-md md:overflow-auto">
<PatientCard @showModal="showModal" @change-password="showPasswordModal" @check-covid="checkCovid" @delete-patient="deletePatient" :class="{'rounded-t-md': index == 0, 'rounded-b-md': index == searchFields.pageSize - 1}" class="border border-gray-200 p-2" :key="patient.id" v-for="(patient, index) in patients" :patient="patient"/>
<PatientCard @showModal="showModal" @change-password="showPasswordModal" @check-covid="checkCovid" @delete-patient="deletePatient" :class="{'rounded-t-md': index == 0, 'rounded-b-md': index == searchFields.pageSize - 1}" class="border border-gray-200 p-2" :key="patient.id" v-for="(patient, index) in patients" :patient="patient" :index="index"/>
</div>
<Pagination class="h-10 my-8 mx-auto" :pages="pages" :currentPage="searchFields.page + 1" @page-changed="pageChanged"/>
<PatientModal class="z-5" ref="patientModal"/>
<PatientModal @savePatient="savePatient" class="z-5" ref="patientModal"/>
</div>
</template>
@ -15,6 +15,7 @@ import PatientSearchField from '@/components/PatientSearchField'
import PatientCard from '@/components/PatientCard'
import Pagination from '@/components/Pagination'
import PatientModal from "@/components/PatientModal";
import axios from 'axios'
export default {
name: "Patients",
@ -35,13 +36,14 @@ export default {
page: 0
},
pages: 0,
patients: []
}
patients: [],
patient_index: 0
}
},
methods: {
pageChanged: function(page){
this.searchFields.page = page - 1;
this.$axios.get('/patients', {
axios.get('/patients', {
params: this.searchFields,
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
@ -49,12 +51,12 @@ export default {
}).then((result) =>{
console.log(result.data);
this.patients = result.data.patients
})
})
},
search: function(fields){
this.searchFields = fields;
this.searchFields.page = 0;
this.$axios.get('/patients', {
axios.get('/patients', {
params: this.searchFields,
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
@ -67,27 +69,54 @@ export default {
else
this.pages = (result.data.patient_num / this.searchFields.pageSize)
}) // TODO error handling here
}).catch((err) => {
console.log(err);
this.$toast.error("Couldn't search")
})
},
deletePatient: function(patient){
console.log(patient);
},
showPasswordModal: function(patient){
console.log(patient);
},
checkCovid: function(patient){
console.log(patient);
},
showModal: function(patient){
this.$refs.patientModal.showPatient(patient);
console.log(patient);
showModal: function(index){
this.patient_index = index
console.log(this.patients[index])
this.$refs.patientModal.showPatient(this.patients[index]);
console.log(this.patients[index]);
},
showEmptyPatientModal: function(){
this.$refs.patientModal.emptyModal();
},
savePatient: function(patient){
if(patient.id){
axios.post('/patients/update', patient,{
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
} ).then((result) => {
this.patients[this.patient_index] = patient
console.log(result)
this.$toast.success("Patient updated successfully")
})
}else{
axios.post('/patients/create', patient,{
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
} ).then((result) => {
console.log(result)
this.$toast.success("Patient created successfully")
})
}
},
checkCovid: function(patient){
console.log(patient)
},
showPasswordModal: function(patient){
console.log(patient)
}
},
mounted(){
this.$axios.get('/patients', {
axios.get('/patients', {
params: this.searchFields,
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
@ -95,12 +124,15 @@ export default {
}).then((result) =>{
console.log(result.data);
this.patients = result.data.patients
if(Math.floor(result.data.patient_num / this.searchFields.pageSize) != result.data.patient_num / this.searchFields.pageSize)
if(Math.floor(result.data.patient_num / this.searchFields.pageSize) !== result.data.patient_num / this.searchFields.pageSize)
this.pages = Math.floor(result.data.patient_num / this.searchFields.pageSize) + 1
else
this.pages = (result.data.patient_num / this.searchFields.pageSize)
}) // TODO err handling here as well
}).catch((err) => {
console.log(err)
this.$toast.error("Could not fetch patients")
})
}
}


Loading…
Cancel
Save