diff --git a/web/src/views/Profile.vue b/web/src/views/Profile.vue index 712f22b9caa5a9f56feb5e16d07383e04a1f88f4..ea4e01ec30e2cab22550d6f174e6065fa464f6b0 100644 --- a/web/src/views/Profile.vue +++ b/web/src/views/Profile.vue @@ -1,12 +1,14 @@ <template> <div id="page-content-wrapper" class="main"> - - <base-toaster @close="hideDialog" :open="toasterIsOpen" type="error"> + <base-toaster @close="hideDialog" :open="toasterIsOpen"> <div class="flex justify-between space-x-4 items-center"> - <font-awesome-icon size="lg" class="ml-3" icon="fa-solid fa-triangle-exclamation" /> - + <font-awesome-icon + class="ml-3" + icon="fa-solid fa-thumbs-up " + size="lg" + /> - <h4>Profile edit at the moment not possible!</h4> + <h4>Profile update successful!</h4> <button class="btn btn-outline" @click="hideDialog"> <font-awesome-icon icon="fa-regular fa-circle-xmark" size="2x" /> </button> @@ -21,39 +23,99 @@ <div v-else> <!-- {{response}}--> <h4 class="round">User Profile</h4> - <div class="panel panel-default" v-if="!editMode"> + <div class="panel panel-default"> <div class="panel-body"> <div class="container-fluid col-md-12"> <div class="row"> <div class="text col-sm-3">User ID</div> <div class="col-sm-9"> - <div class="flex justify-between"> - <b>{{ response.username }}</b> - <button - - type="button" - class=" - - - bg-blue-600 - text-2xl font-bold rounded-lg p-5 text-white hover:bg-blue-600 - - " - @click="toasterIsOpen= true" - - - > - Edit <font-awesome-icon class="ml-2" icon="fa-solid fa-user-pen" /> - </button> - + <b>{{ response.username }}</b> + <div class="relative"> + <button + type="button" + class=" + bg-blue-600 + text-2xl + font-bold + rounded-lg + p-5 + text-white + hover:bg-blue-600 + " + @click="isOpen = !isOpen" + > + Edit + <font-awesome-icon + class="ml-2" + icon="fa-solid fa-user-pen" + /> + </button> + <div + v-if="isOpen" + class=" + mt-2 + absolute + z-50 + right-0 + rounded-lg + py-4 + w-80 + shadow-lg + bg-white + " + > + <!-- Active: "bg-gray-100 text-gray-900", Not Active: "text-gray-700" --> + <a + href="#" + @click="openScientificDisciplineEdit" + class=" + text-gray-700 + rounded-lg + block + px-6 + py-4 + text-2xl + hover:bg-gray-400 + hover:text-white + hover:no-underline + " + >Scientific Discipline</a + > + <a + href="#" + @click="openProfileLinkEdit" + class=" + text-gray-700 + block + px-6 + rounded-lg + py-4 + text-2xl + hover:bg-gray-400 + hover:text-white + hover:no-underline + " + >Profile Link</a + > + <!-- <a href="#" @click="openChangePassword" class="text-gray-700 + block + px-6 + rounded-lg + py-4 + text-2xl + hover:bg-gray-400 + hover:text-white + hover:no-underline" >Password</a> --> + </div> + </div> </div> - </div> + </div> </div> <div class="row"> <div class="text col-sm-3">Full Name</div> <div class="col-sm-9"> - <b>{{response.full_name}}</b> + <b>{{ response.full_name }}</b> </div> </div> <div class="row"> @@ -72,44 +134,39 @@ <div class="text col-sm-3">Current role</div> <div class="col-sm-9"> <div> - {{response.current_role}} + {{ response.current_role }} </div> - </div> </div> <div class="row"> - <div class="text col-sm-3">Scientific Discipline</div> <div class="col-sm-9"> <div> - {{response.scientific_discipline}} - </div> - + {{ response.scientific_discipline }} + </div> </div> </div> <div class="row"> <div class="text col-sm-3">Motivation</div> <div class="col-sm-9"> <p> - {{response.motivation_text}} + {{ response.motivation_text }} </p> - </div> </div> <div class="row"> <div class="text col-sm-3">Affiliation</div> <div class="col-sm-9"> <div> - {{response.current_affiliation}} + {{ response.current_affiliation }} </div> - </div> </div> <div class="row"> <div class="text col-sm-3">Profile Link</div> <div class="col-sm-9"> <a :href="response.profile_link" target="_blank"> - {{response.profile_link}} + {{ response.profile_link }} </a> </div> </div> @@ -127,132 +184,141 @@ </div> </div> </div> - </div> </div> <div class="panel panel-default" v-if="editMode"> <div class="panel-body"> <div class="container-fluid col-md-12"> - <div class="row"> - <div class="text col-sm-3">User ID</div> - <div class="col-sm-9"> - <b>{{ response.username }}</b> - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Full Name</div> - <div class="col-sm-9"> - <b>{{response.full_name}}</b> - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Email</div> - <div class="col-sm-9"> - {{ response.email }} - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Role</div> - <div class="col-sm-9"> - {{ setRole(response.role.name) }} - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Current role</div> - <div class="col-sm-9"> - <select v-model="current_role" class="bg-white py-1 text-gray-700 outline-none bg-transparent border-b hover:border-blue-700 focus:bg-gray-200 focus:border-blue-700" id="inline-current-role" > - <option id="phd" value="PhD">PhD</option> - <option id="postdoc" value="PostDoc">PostDoc</option> - <option id="research_scientist" value="Research_Scientist">Research Scientist</option> - <option id="principal_investigator" value="Principal_Investigator">Principal Investigator</option> - </select> - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Scientific Discipline</div> - <div class="col-sm-9"> - <input type="checkbox" id="physics" value="Physics" v-model="scientific_discipline"> - <label class="mx-3" for="physics">Physics</label> - <input type="checkbox" id="chemistry" value="Chemistry" v-model="scientific_discipline"> - <label class="mx-3" for="chemistry">Chemistry</label> - <input type="checkbox" id="biology" value="Biology" v-model="scientific_discipline"> - <label class="mx-3" for="biology">Biology</label> - <input type="checkbox" id="computer_science" value="Computer_Science" v-model="scientific_discipline"> - <label class="mx-3" for="computer_science">Computer Science</label> - <input type="checkbox" id="mathematics" value="Mathematics" v-model="scientific_discipline"> - <label class="mx-3" for="mathematics">Mathematics</label> - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Motivation</div> - <div class="col-sm-9"> - <textarea rows="5" class=" - bg-white - w-full - py-2 - text-gray-700 - outline-none - bg-transparent - border-b - hover:border-gray-700 - focus:bg-gray-200 focus:border-gray-700 - " - v-model="motivation_text" - ></textarea> - - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Affiliation</div> - <div class="col-sm-9"> - <input v-model="current_affiliation" class="bg-white w-3/4 py-1 text-gray-700 outline-none bg-transparent border-b hover:border-blue-700 focus:bg-gray-200 focus:border-blue-700" id="inline-current-affiliation" type="text" :placeholder="current_affiliation === ''? current_affiliation = response.current_affiliation : current_affiliation"> - </div> - </div> - <div class="row"> - <div class="text col-sm-3">Profile Link</div> - <div class="col-sm-9"> - {{response.profile_link}} - <input v-model="profile_link" class="bg-white w-3/4 py-1 text-gray-700 outline-none bg-transparent border-b hover:border-blue-700 focus:bg-gray-200 focus:border-blue-700" id="inline-profile-link" type="text" :placeholder="profile_link === ''? profile_link = response.profile_link : profile_link"> + <div v-if="showEditScientificDis"> + <h3 class="mb-6 border-b">Update Scientific Discipline</h3> + <div class="row"> + <div class="text col-sm-3 p-4">Scientific Discipline</div> + <div class="col-sm-9 p-4"> + <div + v-for="options in scientificDisciplineOptions" + :key="options.id" + > + <input + type="checkbox" + class="h-6 w-6" + :id="options.id" + :name="options" + :value="options.discipline" + v-model="selected" + /> + <label class="mx-3" :for="options.id">{{ + options.discipline + }}</label> + </div> + + <p + class="text-red-500 font-bold mt-2" + v-if="error && scientificErrMsg" + > + {{ scientificErrMsg }} + </p> + </div> </div> </div> + <div v-if="showEditProfileLink"> + <h3 class="mb-6 border-b">Change Profile Link</h3> + <div class="row"> + <div class="text col-sm-3 p-4">Profile Link</div> - <div class="row"> - <div class="text col-sm-3">Joined</div> - <div class="col-sm-9"> - {{ response.createdAt }} + <div class="col-sm-9 p-4"> + <input + v-model.trim="profile_link" + class=" + bg-white + w-1/3 + py-4 + px-4 + rounded-lg + text-gray-700 + bg-transparent + border border-gray-500 + hover:border-gray-700 + " + id="inline-profile-link" + type="text" + placeholder="Enter profile link." + /> + <p + class="text-red-500 font-bold mt-2" + v-if="error && profileLinkErrMsg" + > + {{ profileLinkErrMsg }} + </p> + </div> </div> </div> - <div class="row"> - <div class="text col-sm-3">Updated</div> - <div class="col-sm-9"> - {{ response.updatedAt }} + <div v-if="showChangePassword"> + <h3 class="mb-6 border-b">Change Password</h3> + <div class="row"> + <div class="text col-sm-3 p-4">Password</div> + <div class="col-sm-9 p-4"> + <input + v-model.trim="password" + class=" + bg-white + w-1/3 + py-4 + px-4 + rounded-lg + text-gray-700 + bg-transparent + border border-gray-500 + hover:border-gray-700 + " + id="inline-profile-link" + type="text" + /> + <p + class="text-red-500 font-bold mt-2" + v-if="error && passwordErrMsg" + > + {{ passwordErrMsg }} + </p> + </div> </div> </div> + <div class="flex space-x-4 mt-2"> - <button class=" - - - bg-green-600 - text-xl font-bold rounded-lg p-5 text-white hover:bg-green-600 - - " @click="update(response)"> - Update Profile - </button> - <button class=" - - - bg-blue-600 - text-xl font-bold rounded-lg p-5 text-white hover:bg-blue-600 - - " @click="editMode=false"> - Cancel - </button> - </div> + <button + class=" + bg-green-600 + text-xl + font-bold + rounded-lg + p-5 + text-white + hover:bg-green-600 + " + @click="update(response)" + > + Update Profile + </button> + <button + class=" + bg-blue-600 + text-xl + font-bold + rounded-lg + p-5 + text-white + hover:bg-blue-600 + " + @click="close" + > + Cancel + </button> + </div> </div> - - </div> + <p class="text-red-500 font-bold mt-2" v-if="error && errorMsg"> + {{ errorMsg }} + </p> </div> <!-- <button v-if="userData !== null && (getRole === 'Contributor' || getRole === 'Maintainer')" @@ -265,15 +331,15 @@ </fetch-profile> <fetch-users v-if="getRole === 'Administrator'"> - <template slot-scope="{response, loading}"> + <template slot-scope="{ response, loading }"> <slot :response="response" :loading="loading"> <div v-if="loading || response === null"></div> <div v-else> <h4 class="round">User List</h4> - <user-table id="usersTable" :data="response" /> + <user-table id="usersTable" :data="response" /> </div> </slot> - </template> + </template> </fetch-users> </div> </template> @@ -281,121 +347,210 @@ <script> import FetchProfile from "@/components/CMS/fetchProfile"; import FetchUpdateItems from "@/components/CMS/fetchUpdateItems"; -import FetchUsers from "@/components/CMS/fetchUsers" -import UserTable from '../components/UserTable.vue'; -import BaseSpinner from '../components/UI/BaseSpinner.vue'; -import BaseToaster from '../components/UI/BaseToaster.vue'; +import FetchUsers from "@/components/CMS/fetchUsers"; +import UserTable from "../components/UserTable.vue"; +import BaseSpinner from "../components/UI/BaseSpinner.vue"; +import BaseToaster from "../components/UI/BaseToaster.vue"; -const _ = require('lodash') -let host = require('@/components/js/const').apiHost; +const _ = require("lodash"); +let host = require("@/components/js/const").apiHost; export default { name: "ProfilePage", components: { - FetchProfile, UserTable, FetchUsers, - BaseSpinner, BaseToaster + FetchProfile, + UserTable, + FetchUsers, + BaseSpinner, + BaseToaster, }, props: { msg: String, }, data() { return { - user: '', - motivation_text: '', - current_role: '', - scientific_discipline: '', - current_affiliation: '', - profile_link: '', - isDev: process.env.NODE_ENV === 'development', + user: "", + motivation_text: "", + current_role: "", + scientific_discipline: [], + current_affiliation: "", + profile_link: "", + password: "", + isDev: process.env.NODE_ENV === "development", editMode: false, - toasterIsOpen: false - } + toasterIsOpen: false, + error: false, + scientificDisciplineOptions: [ + { id: "1", discipline: "Physics" }, + { id: "2", discipline: "Chemistry" }, + { id: "3", discipline: "Biology" }, + { id: "4", discipline: "Computer_Science" }, + { id: "5", discipline: "Mathematics" }, + ], + selected: [], + isOpen: false, + showEditScientificDis: false, + showEditProfileLink: false, + showChangePassword: false, + scientificErrMsg: "", + profileLinkErrMsg: "", + passwordErrMsg: "", + errorMsg: "", + }; }, computed: { jwt: function () { - return this.$store.getters['User/jwt'] + return this.$store.getters["User/jwt"]; }, userData: function () { return this.$store.getters["User/userData"]; }, - getRole: function(){ - return this.$store.getters['User/userRole'] - } + getRole: function () { + return this.$store.getters["User/userRole"]; + }, }, methods: { - showDialog() { + close() { + this.editMode = false; + this.showEditScientificDis = false; + this.showEditProfileLink = false; + this.showChangePassword = false; + this.error = false; + this.scientificErrMsg = ""; + this.profileLinkErrMsg = ""; + this.passwordErrMsg = ""; + this.selected = []; + this.profile_link = ""; + this.password = ""; + }, + openScientificDisciplineEdit() { + this.editMode = true; + this.showEditScientificDis = true; + this.showEditProfileLink = false; + this.showChangePassword = false; + }, + openProfileLinkEdit() { + this.editMode = true; + this.showEditScientificDis = false; + this.showEditProfileLink = true; + this.showChangePassword = false; + }, + openChangePassword() { + this.editMode = true; + this.showEditScientificDis = false; + this.showEditProfileLink = false; + this.showChangePassword = true; + }, + showDialog() { this.toasterIsOpen = true; }, hideDialog() { this.toasterIsOpen = false; - - }, - showEditMode(){ -console.log(true); -this.editMode= true + showEditMode() { + console.log(true); + this.editMode = true; }, setRole(roleName) { //console.log("role name is,", roleName); - const vm = this - window.localStorage.setItem('roleName', roleName) - vm.$store.dispatch('User/setUserRole', roleName) - return roleName + const vm = this; + window.localStorage.setItem("roleName", roleName); + vm.$store.dispatch("User/setUserRole", roleName); + return roleName; }, async update(e) { - -console.log("user data", e); + console.log("user data", e); const vm = this; - if(vm.isDev) { - host = require('@/components/js/const').devApiHost; + if (vm.isDev) { + host = require("@/components/js/const").devApiHost; } const jwt = vm.jwt; - if(jwt === null) { + if (jwt === null) { vm.loaded = false; - return + return; } - vm.user= e.id + vm.user = e.id; + let dat; + if (this.showEditScientificDis) { + if (this.selected.length === 0) { + this.error = true; + this.scientificErrMsg = "Please select at least one discipline."; + return; + } + dat = { + id: vm.user, + + scientific_discipline: vm.selected, + }; + } else if (this.showEditProfileLink) { + if (!this.profile_link) { + this.error = true; + this.profileLinkErrMsg = "Please enter your profile link."; + return; + } + dat = { + id: vm.user, - let dat = { - id: vm.user, - motivation_text: vm.motivation_text, - current_role: vm.current_role, - current_affiliation: vm.current_affiliation, - profile_link: vm.profile_link, - scientific_discipline: vm.scientific_discipline - }; + profile_link: vm.profile_link, + }; + } else if (this.showChangePassword) { + if (!this.password) { + this.error = true; + this.passwordErrMsg = "Please enter a password."; + return; + } + dat = { + id: vm.user, + + password: vm.password, + }; + } + this.error = false; + this.scientificErrMsg = ""; + this.profileLinkErrMsg = ""; + this.passwordErrMsg = ""; + // let dat = { + // id: vm.user, + // profile_link: vm.profile_link, + // scientific_discipline: vm.selected, + // password: vm.password, + // }; + console.log(dat); try { const res = await this.axios.put(`${host}/api/users/${vm.user}`, dat, { headers: { - Authorization: `Bearer ${jwt}` - } + Authorization: `Bearer ${jwt}`, + }, }); - // console.log(res.data) - - await vm.$router.push('/profile') - } catch(error) { + console.log(res.data); + this.error = false; + this.toasterIsOpen = true; + this.selected = []; + this.profile_link = ""; + this.password = ""; + } catch (error) { // console.log(error.response.data.error.message) // console.log(error.response) - this.error = true - this.errorMsg = error + this.error = true; + this.errorMsg = error; } }, }, mounted: function () { - const vm = this - - if(vm.userData === null) { - this.$router.push('/login') + const vm = this; + + if (vm.userData === null) { + this.$router.push("/login"); } else { vm.user = vm.userData.id; vm.current_role = vm.userData.current_role; vm.scientific_discipline = vm.userData.scientific_discipline; - if(vm.scientific_discipline === null) { - vm.scientific_discipline = [] + if (vm.scientific_discipline === null) { + vm.scientific_discipline = []; } } }, diff --git a/web/src/views/SignUp.vue b/web/src/views/SignUp.vue index c9d4e372aaf003a75f9ccc154c78674d37ece25f..a2c30ce6644b80436c4b4691d4a0085bc67ed2c6 100644 --- a/web/src/views/SignUp.vue +++ b/web/src/views/SignUp.vue @@ -116,7 +116,7 @@ export default { }, async register(e) { const vm = this - vm.toasterIsOpen= true; + e.preventDefault() @@ -135,6 +135,7 @@ try { current_role: vm.current_role, scientific_discipline: vm.scientific_discipline }) + vm.toasterIsOpen= true; //vm.$router.push('login') } catch(e) { // console.error(e)