Browse Source

Zoom Oauth Support

main
Unknown 4 years ago
parent
commit
b6cfbc2f4c
8 changed files with 3169 additions and 2700 deletions
  1. +2963
    -2684
      package-lock.json
  2. +3
    -0
      src/components/AppointmentModal.vue
  3. +14
    -14
      src/components/PatientModal.vue
  4. +1
    -1
      src/main.js
  5. +10
    -0
      src/router/index.js
  6. +1
    -1
      src/views/Patients.vue
  7. +151
    -0
      src/views/Profile.vue
  8. +26
    -0
      src/views/ZoomOauth.vue

+ 2963
- 2684
package-lock.json
File diff suppressed because it is too large
View File


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

@ -141,6 +141,9 @@ export default{
this.patient = entry.patient; this.patient = entry.patient;
}, },
updatePatientSuggestions: function(searchTerm){ updatePatientSuggestions: function(searchTerm){
if(searchTerm.length <= 3){
return
}
axios.get('/patients', { axios.get('/patients', {
params: { params: {
name: searchTerm name: searchTerm


+ 14
- 14
src/components/PatientModal.vue View File

@ -11,32 +11,32 @@
</div> </div>
</div> </div>
<div class="divide-y divide-gray-200"> <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 flex-col items-center space-x-4">
<div class="py-8 text-base leading-6 space-y-4 text-gray-700 sm:text-lg sm:leading-7">
<div class="flex flex-col items-center space-x-4">
<div class="ml-4 w-full flex flex-col md:flex-row md:mb-3"> <div class="ml-4 w-full flex flex-col md:flex-row md:mb-3">
<label class="leading-loose mr-1">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">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div> </div>
<div class="w-full flex flex-col md:flex-row md:mb-3"> <div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="leading-loose mr-1">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">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div> </div>
<div class="w-full flex flex-col md:flex-row md:mb-3"> <div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="leading-loose mr-1">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">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div> </div>
<div class="w-full flex flex-col md:flex-row md:mb-3"> <div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="leading-loose mr-1">TC:</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">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">TC:</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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div> </div>
<div class="w-full flex flex-col md:flex-row md:mb-3"> <div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="leading-loose mr-1">Hes:</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">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">Hes:</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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div> </div>
<div class="w-full flex flex-col md:flex-row md:mb-3"> <div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="leading-loose mr-1">Protocol:</label>
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">Protocol:</label>
<vue-tags-input <vue-tags-input
class="focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600"
class="focus:ring-gray-500 h-full focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-r-md focus:outline-none text-gray-600"
v-model="tag" v-model="tag"
:tags="tags" :tags="tags"
@tags-changed="newTags => patient.protocolNumbers = convertTags(newTags)" @tags-changed="newTags => patient.protocolNumbers = convertTags(newTags)"


+ 1
- 1
src/main.js View File

@ -6,7 +6,7 @@ import Toast from "vue-toastification";
import "vue-toastification/dist/index.css"; import "vue-toastification/dist/index.css";
import axios from "axios"; import axios from "axios";
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:9090' : 'https://api.metisapp.net'
axios.defaults.baseURL = process.env.VUE_APP_API_BASE_URL
Vue.use(Toast, {}); Vue.use(Toast, {});


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

@ -20,6 +20,16 @@ const routes = [
name: 'Disabled', name: 'Disabled',
component: () => import('../views/Disabled.vue') component: () => import('../views/Disabled.vue')
}, },
{
path: '/profile',
name: 'Profile',
component: () => import('../views/Profile.vue')
},
{
path: '/oauth/zoom',
name: 'ZoomOauth',
component: () => import('../views/ZoomOauth.vue')
},
{path: '/', redirect: '/calendar'} {path: '/', redirect: '/calendar'}
] ]


+ 1
- 1
src/views/Patients.vue View File

@ -1,6 +1,6 @@
<template> <template>
<div class="flex-col flex content-center py-3 mx-auto"> <div class="flex-col flex content-center py-3 mx-auto">
<PatientSearchField @new="showEmptyPatientModal" class=" md:w-4/6 md:mx-auto" @fieldsUpdated="search" title="Patient"/>
<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"/> <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"> <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" :index="index"/> <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"/>


+ 151
- 0
src/views/Profile.vue View File

@ -0,0 +1,151 @@
<template>
<div v-if="profile !== {}" >
<div class="w-10/12 md:mt-8 md:w-7/12 mx-auto p-5 rounded-lg border-gray-100 border-2">
<div class="flex flex-col items-center space-x-4">
<div class="ml-4 w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">Name:</label>
<input v-model="profile.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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">Phone:</label>
<input v-model="profile.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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">E-Mail:</label>
<input v-model="profile.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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">TC:</label>
<input v-model="profile.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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">Hes:</label>
<input v-model="profile.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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center">Locale:</label>
<select v-model="profile.locale" 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-r-md focus:outline-none text-gray-600" placeholder="Patient Name">
<option value="tr">Turkish</option>
<option value="en">English</option>
</select>
</div>
</div>
<div class="pt-1 flex items-center space-x-4">
<button @click="saveClicked" class="ml-auto bg-blue-500 flex justify-center items-center w-2/12 text-white px-2 py-2 rounded-md focus:outline-none">Save</button>
</div>
</div>
<div class="w-10/12 md:mt-8 md:w-7/12 mx-auto p-5 rounded-lg border-gray-100 border-2">
<div class="flex flex-col items-center space-x-4">
<div class="ml-4 w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center w-1/5">Old Password:</label>
<input v-model="oldpass" type="password" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-r-md focus:outline-none text-gray-600" placeholder="">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center w-1/5">New Password:</label>
<input v-model="newpass" type="password" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-r-md focus:outline-none text-gray-600" placeholder="">
</div>
<div class="w-full flex flex-col md:flex-row md:mb-3">
<label class="bg-gray-200 border-gray-300 border rounded-l-md p-1 px-2 text-gray-600 flex items-center w-1/4">Confirm Password:</label>
<input v-model="confirmpass" type="password" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-r-md focus:outline-none text-gray-600" placeholder="">
</div>
</div>
<div class="pt-1 flex items-center space-x-4">
<button @click="updatePassword" class="ml-auto bg-blue-500 flex justify-center items-center w-2/12 text-white px-2 py-2 rounded-md focus:outline-none">Save</button>
</div>
</div>
<div v-if="profile.role !== 'PATIENT'" class="w-10/12 md:mt-8 md:w-7/12 mx-auto p-5 rounded-lg border-gray-100 border-2">
<div class="ml-4 w-full flex flex-col md:flex-row md:mb-3">
<button @click="sendSms" :disabled="!hesvalidate" :class="{'bg-gray-200 border-gray-300 text-gray-600 border': !hesvalidate, 'bg-blue-500 border-0 text-white': hesvalidate}" class="rounded-l-md p-1 px-2 flex items-center w-1/6">Send SMS</button>
<input :disabled="hesvalidate" v-model="smscode" type="text" class="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 focus:outline-none text-gray-600" placeholder="SMS Code">
<button @click="saveHesApi" :disabled="hesvalidate" :class="{'bg-gray-200 border-gray-300 text-gray-600 border': hesvalidate, 'bg-blue-500 border-0 text-white': !hesvalidate}" class="rounded-r-md p-1 px-2 flex items-center w-1/6">Save</button>
</div>
<div class="ml-4 w-full flex flex-col md:flex-row md:mb-3">
<a class="bg-blue-500 border-0 text-white rounded-md p-1 px-2 flex items-center w-2/6 mt-2 py-2" :href="zoom_oauth_url">Connect to ZOOM</a>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "Profile",
data: function() {
return {
profile: {},
oldpass: "",
newpass: "",
confirmpass: "",
hesvalidate: true,
smscode: "",
zoom_oauth_url:`https://zoom.us/oauth/authorize?response_type=code&client_id=${process.env.VUE_APP_ZOOM_CLIENT_ID}&redirect_uri=${window.location.origin}/oauth/zoom`
}
},
methods: {
saveClicked: function () {
axios.post('/profile', this.profile, {
headers:{
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then(() => {
this.$toast.success("Profile information saved successfully.");
})
.catch(() => { this.$toast.error("An error occured.")});
},
updatePassword: function(){
if(this.newpass !== this.confirmpass){
this.$toast.error("New passwords do not match.")
return;
}
axios.post("/profile/password", `oldPassword=${encodeURI(this.oldpass)}&newPassword=${encodeURI(this.newpass)}`,{
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then((result) => {
if(result.data.code !== 200){
this.$toast.error(result.data.message);
return;
}
this.$toast.success("Password changed successfully!")
})
.catch(() => {this.$toast.error("An unknown error occured!")})
},
sendSms: function(){
this.hesvalidate = false
axios.get("/profile/hes/sendsms", {
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then(() => {
this.$toast.info("An SMS was sent to your mobile phone")
}).catch(() => {
this.$toast.error("An error occured!");
this.hesvalidate = true;
})
},
saveHesApi: function(){
axios.get("/profile/smscode", {
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
},
params: {
code: this.smscode
}
}).then(() => {
this.$toast.info("Connection to HES successful")
})
}
},
mounted(){
axios.get('/profile', {
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then((result) => {
this.profile = result.data.user
console.log(this.profile)
})
}
}
</script>

+ 26
- 0
src/views/ZoomOauth.vue View File

@ -0,0 +1,26 @@
<template>
<div><p>Redirecting...</p></div>
</template>
<script>
import axios from "axios";
import router from '../router'
export default {
name: "ZoomOauth",
mounted(){
const code = new URLSearchParams(window.location.search).get('code');
console.log(code)
axios.get('/profile/zoom/authorization', {
params: {
code: code
},
headers:{
'Authorization': `Bearer ${window.localStorage.getItem('JWT')}`
}
}).then(() => {
router.push("/profile")
}).catch(() => { this.$toast.error("An error occured.")});
}
}
</script>

Loading…
Cancel
Save