diff --git a/package-lock.json b/package-lock.json index 67f7720d8f38f07390dc4520e8c0863b2ca5b714..48f47d2a68c7625508106ca651eeac7650da8e24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "axios": "^0.25.0", "bootstrap": "^5.1.3", "core-js": "^3.6.5", + "jquery": "^3.6.0", "vue": "^3.0.0", "vue-router": "^4.0.12", "vue-select": "^4.0.0-beta.3" @@ -8501,6 +8502,11 @@ "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", "dev": true }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, "node_modules/js-message": { "version": "1.0.7", "resolved": "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz", @@ -21964,6 +21970,11 @@ "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", "dev": true }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, "js-message": { "version": "1.0.7", "resolved": "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz", diff --git a/package.json b/package.json index cda5f0833934a0a709220525a6d1b9386e641527..997dd32021d8e81eb96b522b3de7b263fbd17f2d 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "axios": "^0.25.0", "bootstrap": "^5.1.3", "core-js": "^3.6.5", + "jquery": "^3.6.0", "vue": "^3.0.0", "vue-router": "^4.0.12", "vue-select": "^4.0.0-beta.3" diff --git a/src/components/Modal.vue b/src/components/Modal.vue new file mode 100644 index 0000000000000000000000000000000000000000..f7ce79986a1b2ee5e3e0412d3a63c02a500b7ecb --- /dev/null +++ b/src/components/Modal.vue @@ -0,0 +1,125 @@ +<script> + export default { + name: 'Modal', + props:{ type: String }, + methods: { + close() { + this.$emit('close'); + }, + }, + emits:['close'], + }; +</script> + +<template> + <div class="modal-backdrop"> + <div class="modal"> + + <header class="modal-header"> + <slot name="header"> + This is title + </slot> + <button type="button" class="btn-close" @click="close"> + <div style="padding: 10px 10px 10px 0px;"> + <i class="icon ion-ios-close-outline" ></i> + </div> + + </button> + </header> + + <section class="modal-body"> + <slot name="body"> + This is body + </slot> + </section> + + <!-- <footer class="modal-footer"> + <slot name="footer"> + This is footer + </slot> + <button type="button" class="btn-green" @click="close"> + Close Modal + </button> + </footer> --> + + </div> + </div> +</template> + +<style> + .modal-backdrop { + position: absolute; + top: 50%; + bottom: 0; + left: 50%; + right: 0; + transform: translate(-50%, -50%); + background-color: rgba(0, 0, 0, 0); + display: flex; + justify-content: center; + align-items: center; + } + + .modal { + background: #FFFFFF; + box-shadow: 1px 3px 7px rgba(0, 0, 0, 0.3); + border-radius: 20px; + border: 1px solid #6992b4; + /* overflow-x: auto; */ + overflow: hidden; + width: 50%; + height: 30%; + display: flex; + flex-direction: column; + top: 50%; + bottom: 0; + left: 50%; + right: 0; + transform: translate(-50%, -50%); + } + + /* .modal-footer, */ + .modal-header { + padding: 15px; + display: flex; + } + + + .modal-header { + position: relative; + border-bottom: 1px solid #eeeeee; + color: #6992b4; + justify-content: space-between; + } + + /* .modal-footer { + border-top: 1px solid #eeeeee; + flex-direction: column; + justify-content: flex-end; + } */ + + .modal-body { + position: relative; + padding: 20px 10px; + } + + .btn-close { + position: absolute; + top: 0; + right: 0; + border: none; + font-size: 20px; + + cursor: pointer; + font-weight: bold; + color: #6992b4; + background: transparent; + } + + .btn-green { + color: white; + background: #6992b4; + border: 1px solid #6992b4; + border-radius: 2px; + } +</style> \ No newline at end of file diff --git a/src/components/header.vue b/src/components/header.vue index fdfa4ca9d34292b6271d7a32b98dce337909e565..c952bf54c5c22bd0b8b474c448e1cdc965d4c033 100644 --- a/src/components/header.vue +++ b/src/components/header.vue @@ -29,11 +29,14 @@ <div class="d-flex flex-row-reverse justify-content-start align-items-center illustration" > - <i - class="icon ion-ios-person-outline text-red" - style="font-size: 65px" - ></i> - <h2 class="text-red" style="text-align: right">Hello, username</h2> + <button @click="showModal()" class="profile-btn"> + <i + class="icon ion-ios-person-outline text-red" + style="font-size: 65px" + ></i> + </button> + <!-- <Name :name="this.name"/> --> + <h2 class="text-red" style="text-align: right">Hello, {{name}}</h2> </div> </div> </div> @@ -41,20 +44,99 @@ <hr style="border: 1px solid red" /> </div> + <Modal class="profile-modal" + v-show="isModalVisible" + @close="closeModal" + > + <template v-slot:header>Menu Pilihan</template> + <template v-slot:body> + <!-- warna biru, link ke halaman profil --> + <button @click="toProfile">Lihat Profil</button> + <!-- warna merah --> + <button @click="toLogout">Keluar</button> + </template> + + </Modal> </template> <script> +import Modal from "../components/modal"; +//import Name from "../components/name"; +import { HTTP } from '../http-common' + export default { name: "Header", + components: { + Modal + // Name + }, + // props:{ username: String }, data() { return { nav_active: true, + isModalVisible: false, + profile_employee:[], + profile_admin:[], + name:"", + id: null, + user_id: null, + is_admin: false, }; }, methods: { onclick() { this.nav_active = !this.nav_active; }, + showModal(){ + this.isModalVisible = true; + }, + closeModal(){ + this.isModalVisible = false; + //console.log(this.isModalVisible) + }, + toProfile(){ + //console.log("profile") + if (this.is_admin){ + this.$router.push({ name: "profil-admin", params: { id: this.id }}); + } else { + this.$router.push({ name: "profil-user", params: { user_id: this.user_id }}); + } + + }, + toLogout(){ + console.log("logout") + //panggil api logout (delete token) + //data user jadi null + //pastiin dia gabisa ke halaman lain lagi + }, + getProfile(){ + HTTP.get("users/profile").then((res)=>{ + if (res.data.success == true){ + this.is_admin = res.data.data.is_admin + if (this.is_admin){ + //console.log(this.is_admin) + this.profile_admin = res.data.data + this.name = this.profile_admin.username + this.id = this.profile_admin.id + + } else { + //console.log(res.data.data.profile) + this.profile_employee = res.data.data.profile + this.name = this.profile_employee.name + this.user_id = this.profile_employee.user_id + } + //console.log(this.name) + }}) + }, + }, + // computed:{ + // getName(){ + // this.username = this.name + // return this.username + // } + // }, + mounted(){ + this.getProfile(); }, }; </script> @@ -75,4 +157,14 @@ export default { .logo{ width: 100px; } +.profile-btn{ + text-decoration: none; + border: none; + background-color: transparent; +} +/* butuh buat akses class di dalem class modal */ +.profile-modal{ + width: 20em; + height: 35em; +} </style> diff --git a/src/components/name.vue b/src/components/name.vue new file mode 100644 index 0000000000000000000000000000000000000000..018d6746694830a4c4f7f1fa811bef344154ee05 --- /dev/null +++ b/src/components/name.vue @@ -0,0 +1,11 @@ +<template> + <h2 class="text-red" style="text-align: right">Hello, {{name}}</h2> +</template> + +<script> + +export default { + name: "Name", + props:{name: String}, +}; +</script> \ No newline at end of file diff --git a/src/components/passinput.vue b/src/components/passinput.vue new file mode 100644 index 0000000000000000000000000000000000000000..9ef45843e96cf77a2f78bb02c959b224bfc40953 --- /dev/null +++ b/src/components/passinput.vue @@ -0,0 +1,33 @@ +<template> + <div class="mb-3 me-3"> + <label :for="id" class="text-blue pe-2">{{title}}</label> + <button type="button" @click="switchVisibility" style="border: none; background-color: white; color: #6992b4"> + <i :class="icon" ></i> + </button> + <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" :type="passwordFieldType" id="id" class="form-control" required> + + </div> +</template> + +<script> +export default { + props: ['id','modelValue', 'title'], + emits:['update:modelValue'], + data(){ + return{ + passwordFieldType: "password", + icon: "icon ion-eye-disabled" + } + }, + methods: { + switchVisibility() { + if (this.passwordFieldType === "password"){ + this.passwordFieldType = "text"; + this.icon = "icon ion-eye"; + } else { + this.passwordFieldType = "password" + this.icon = "icon ion-eye-disabled"; + } + }, +}} +</script> diff --git a/src/http-common.js b/src/http-common.js index 44da233e4de33f0432230b95f20d831af1822761..63ae394d54e7c26ca09481c43120a4f7270467dd 100644 --- a/src/http-common.js +++ b/src/http-common.js @@ -3,8 +3,7 @@ import axios from 'axios'; const token = localStorage.getItem('token') export const HTTP = axios.create({ - baseURL: `https://simkpi-backend.herokuapp.com/api`, - // baseURL: 'localhost:8000/api/', + baseURL: `http://simkpi-backend.herokuapp.com/api/`, headers: { Accept: 'application/json', Authorization: `Bearer ${token}` diff --git a/src/router/index.js b/src/router/index.js index 95314beaecbf50a05d9b1960038a58cbb85c5051..2ccb3a02e48a9b1ce39f261ed5a8737d51550659 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,7 +1,8 @@ import { createRouter, createWebHistory } from "vue-router"; -// import Home from "../views/Home.vue"; -import uProfil from "../views/uProfil.vue"; -import aProfil from "../views/aProfil.vue"; +import Home from "../views/Home.vue"; +import ProfilUser from "../views/ProfilUser.vue"; +import ProfilAdmin from "../views/ProfilAdmin.vue"; +import ChangePass from "../views/ChangePass.vue"; import Login from "../views/Login.vue"; import UserIndex from "../views/UserIndex.vue"; import AdminIndex from "../views/AdminIndex.vue"; @@ -32,14 +33,19 @@ const routes = [ component: Login, }, { - path: "/uProfil", - name: "uProfil", - component: uProfil, + path: "/profil-user/:user_id", + name: "profil-user", + component: ProfilUser, }, { - path: "/aProfil", - name: "aProfil", - component: aProfil, + path: "/profil-admin/:id", + name: "profil-admin", + component: ProfilAdmin, + }, + { + path: "/change-pass", + name: "change-pass", + component: ChangePass, }, { path: "/user", diff --git a/src/views/ChangePass.vue b/src/views/ChangePass.vue new file mode 100644 index 0000000000000000000000000000000000000000..18089ca9d1abaa50716850d95ef90531c9cd446a --- /dev/null +++ b/src/views/ChangePass.vue @@ -0,0 +1,108 @@ +<template> + <div class="container-fluid"> + <div class="row flex-nowrap"> + <Sidebar current_page = "About" /> + <div class="col ps-md-2 pt-2"> + <Header /> + <div class="row p-3"> + <h1 class="text-blue">Ubah Kata Sandi</h1> + <hr class="my-4 " style="border: 1px solid #6992b4"> + </div> + <form @submit.prevent="save" autocomplete="off" id="formAdmin"> + <div class="row px-5"> + <div class="col"> + <Passinput id="currentPass" title="Kata Sandi Lama" v-model="current_password"/> + <Passinput id="newPass" title="Kata Sandi Baru" v-model="new_password"/> + <Passinput id="confirmNewPass" title="Konfirmasi Kata Sandi Baru" v-model="new_password_confirmation"/> + + <button type="submit" class="btn-blue p-1" >Simpan Kata Sandi</button> + </div> + </div> + </form> + </div> + </div> + </div> +</template> + + +<script> + +import Header from "../components/header" +import Sidebar from "../components/sidebar" +import Passinput from "../components/passinput" +import { HTTP } from '../http-common' + + +export default { + name: "ChangePass", + components: { + Header, + Sidebar, + Passinput + }, + data(){ + return{ + current_password: "", + new_password:"", + new_password_confirmation:"", + } + }, + methods: { + switchVisibility() { + if (this.passwordFieldType === "password"){ + this.passwordFieldType = "text"; + this.icon = "icon ion-eye"; + } else { + this.passwordFieldType = "password" + this.icon = "icon ion-eye-disabled"; + } + }, + save(e){ + console.log("save") + e.preventDefault(); + let data = { + current_password: this.current_password, + new_password: this.new_password, + new_password_confirmation: this.new_password_confirmation, + } + if (this.current_password != "" && this.new_password != "" && this.new_password_confirmation != ""){ + data.current_password = this.current_password + data.new_password = this.new_password + data.new_password_confirmation = this.new_password_confirmation + + HTTP.put(`users/change-password`, data, { + headers: { + 'Content-Type': 'application/json' + } + }).then((res)=>{ + if (res.status == 200){ + alert("Kata sandi berhasil diganti") + } + }).catch(() => alert("Gagal mengganti kata sandi")) + } + } + } +} +</script> + +<style scoped> +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + min-height: 100vh; + background-color: #fff; +} + +.btn-blue { + background-color: #6992b4; + color: #f1f7fc; + border-radius: 8px; + margin-right: 5px; +} + + +</style> \ No newline at end of file diff --git a/src/views/DepartemenIndex.vue b/src/views/DepartemenIndex.vue index f5ef49314fa619013337e701bedd4009758388a2..e8702249c5d61c12165c888daa5c1084f3ad484a 100644 --- a/src/views/DepartemenIndex.vue +++ b/src/views/DepartemenIndex.vue @@ -10,14 +10,19 @@ <h1 class="text-blue">Daftar Departemen</h1> </div> <div class="col"> - <button class="btn float-end">Tambah Departemen</button> + <button + class="btn float-end" + @click="showModal('addDept')" + > + Tambah Departemen + </button> </div> </div> <div class="row p-2"> <div class="search float-end col-3"> <div class="row"> <div class="col-10"> - <input + <input class="search-input p-1" v-model="filter" type="text" @@ -46,14 +51,47 @@ </div> </div> </div> + <Modal + v-show="isModalVisible" + @close="closeModal" + > + + <!-- <div v-if="type === 'addDept'"> --> + + <template v-slot:header> + <template v-if="type === 'addDept'"> Tambah Departemen </template> + <template v-if="type === 'editDept'"> Edit Departemen </template> + + + </template> + + <template v-slot:body> + <!-- fill with form --> + <template v-if="type === 'addDept'"> + <form @submit="insert" autocomplete="off" id="formAddDept"> + <label for="deptInput">Nama Departemen</label> + <input v-model="deptnameadd" type="text" id="deptInput" class="form-control"> + <button type="submit" class="btn-blue p-1" >Simpan</button> + </form> + </template> + <template v-if="type === 'editDept'"> + <form @submit="edit" autocomplete="off" id="formEditDept"> + <label for="deptEdit">Nama Departemen</label> + <input v-model="deptnameedit" type="text" id="deptEdit" class="form-control"> + <button type="submit" class="btn-blue p-1" >Simpan</button> + </form> + </template> + </template> + </Modal> </div> + </template> <script> import Table from "../components/table"; import Header from "../components/header"; import Sidebar from "../components/sidebar"; -import { HTTP } from "../http-common"; +import Modal from "../components/modal"; export default { name: "DepartemenIndex", @@ -61,9 +99,14 @@ export default { Table, Header, Sidebar, + Modal, }, data() { return { + type:"", + isModalVisible: false, + deptnameadd:"", + deptnameedit:"", dept: [], temp_dept: [ { @@ -102,7 +145,33 @@ export default { filter: "", }; }, + props:{}, methods: { + showModal(type){ + switch(type){ + case "addDept": + this.type = "addDept"; + break + case "editDept": + this.type = "editDept"; + break + } + this.isModalVisible = true; + }, + closeModal(){ + this.isModalVisible = false; + //console.log(this.isModalVisible) + }, + insert(e){ + e.preventDefault(); + let formValue = this.deptnameadd + console.log(formValue) + alert("Dept berhasil ditambahkan") + document.getElementById("formAddDept").reset(); + }, + // addDept(data){ + // console.log(data); + // }, getDept() { // di sini ambil data admin dari database HTTP.get("departments").then((res)=>{ @@ -116,9 +185,54 @@ export default { deleteDept(id) { console.log(id); }, + edit(e){ + e.preventDefault(); + + //let prevDept = this.temp_dept[parseInt(id)-1] + //console.log(prevDept.nama) + + //get data from form + let formValue = this.deptnameedit + console.log(formValue) + console.log(typeof formValue) //udah jalan sampe sini + //console.log(id) //id undefined + //console.log(this.id) //undefined + + //this.temp_dept[parseInt(this.id)-1].nama = formValue + + // methods: { + // // ... + // fillData(selected){ + // this.datacollection.datasets[0].label = selected; + // }, + + + // let prevDept = this.temp_dept[parseInt(id)-1].nama + // prevDept = formValue + // console.log(prevDept) + + alert("Dept berhasil diedit") + + document.getElementById("formEditDept").reset(); + }, + editDept(id) { - console.log(id); + //console.log(id); + this.showModal("editDept"); + + //get data + let dept = this.temp_dept[parseInt(id)-1] + this.deptnameedit = dept.nama + //console.log(this.deptnameedit) + + //change data + + + }, + // updateDept(event){ + // console.log(event); + // } }, mounted() { this.getDept(); @@ -157,4 +271,14 @@ export default { .search-input:focus { outline: none; } +.modal { + width: 600px; + max-width: 100%; + position: absolute; + float: left; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + margin: auto; +} </style> diff --git a/src/views/aProfil.vue b/src/views/ProfilAdmin.vue similarity index 66% rename from src/views/aProfil.vue rename to src/views/ProfilAdmin.vue index 1ef4fbe0995905bd982bea115420f6a4c10e1380..939ef700f0baa4ad0fd05e4355373c66ce214ad0 100644 --- a/src/views/aProfil.vue +++ b/src/views/ProfilAdmin.vue @@ -13,14 +13,14 @@ <table class="table table-borderless"> <tbody> <tr> - <td class="py-3 text-blue-bold">Nama</td> - <td class="py-3">asoygeboy</td> + <td class="py-3 text-blue-bold">Username</td> + <td class="py-3">{{username}}</td> <td class="py-3 text-blue-bold"></td> <td class="py-3"></td> </tr> <tr> <td class="py-3 text-blue-bold">Email</td> - <td class="py-3">asoy@gmail.com</td> + <td class="py-3">{{email}}</td> <td class="py-3 text-blue-bold"></td> <td class="py-3"></td> </tr> @@ -36,13 +36,35 @@ <script> import Header from "../components/header"; import Sidebar from "../components/sidebar"; +import { HTTP } from '../http-common'; export default { - name: "aProfil", + name: "ProfilAdmin", components: { Header, Sidebar, }, + data(){ + return{ + username:"", + email:"" + } + }, + methods:{ + getProfile(){ + HTTP.get("users/profile").then((res)=>{ + if (res.data.success == true){ + //console.log(res.data.data.profile) + this.profile = res.data.data + this.username = this.profile.username + this.email = this.profile.email + }}) + }, + }, + mounted(){ + this.id = this.$route.params.id; + this.getProfile(); + } }; </script> diff --git a/src/views/uProfil.vue b/src/views/ProfilUser.vue similarity index 55% rename from src/views/uProfil.vue rename to src/views/ProfilUser.vue index 60aa09d81082d0f5466845ac00bfea6984326aa8..660935627d2ec3e00fd817c07b03dad9b68a8fd3 100644 --- a/src/views/uProfil.vue +++ b/src/views/ProfilUser.vue @@ -14,31 +14,31 @@ <tbody> <tr> <td class="py-3 text-blue-bold">Nama</td> - <td class="py-3">asoygeboy</td> + <td class="py-3">{{name}}</td> <td class="py-3 text-blue-bold">Username</td> - <td class="py-3">asoygeboy</td> + <td class="py-3">{{username}}</td> </tr> <tr> <td class="py-3 text-blue-bold">NIK</td> - <td class="py-3">123456789</td> + <td class="py-3">{{nik}}</td> <td class="py-3 text-blue-bold">Email</td> - <td class="py-3">asoy@gmail.com</td> + <td class="py-3">{{email}}</td> </tr> <tr> <td class="py-3 text-blue-bold">Departemen</td> - <td class="py-3">Keagamaan dan Sosial</td> + <td class="py-3">{{departemen}}</td> <td class="py-3"></td> <td class="py-3"></td> </tr> <tr> <td class="py-3 text-blue-bold">Jabatan</td> - <td class="py-3">Associate Manager</td> + <td class="py-3">{{jabatan}}</td> <td class="py-3"></td> <td class="py-3"></td> </tr> <tr> <td class="py-3 text-blue-bold">Atasan</td> - <td class="py-3">Adrian Bayu</td> + <td class="py-3">{{atasan_name}}</td> <td class="py-3"></td> <td class="py-3"></td> </tr> @@ -54,13 +54,58 @@ <script> import Header from "../components/header"; import Sidebar from "../components/sidebar"; +import { HTTP } from '../http-common' export default { - name: "uProfil", + name: "ProfilUser", components: { Header, Sidebar, }, + data(){ + return{ + profile:[], + name:"", + user_id:null, + nik:"", + departemen:"", + jabatan:"", + atasan:null, + atasan_name:null, + username:"", + email:"" + }; + + }, + methods:{ + getProfile(){ + HTTP.get("users/profile").then((res)=>{ + if (res.data.success == true){ + //console.log(res.data.data.profile) + this.profile = res.data.data.profile + this.name = this.profile.name + //this.name = res.data.data.profile.name + this.user_id = this.profile.user_id + //console.log(this.name) + this.nik = this.profile.nik + this.departemen = this.profile.department + this.jabatan = this.profile.position + this.username = res.data.data.username + this.email = res.data.data.email + + this.atasan = this.profile.manager + console.log(this.atasan) + if (this.atasan == null){ + this.atasan_name = "-" + } + }}) + }, + }, + + mounted(){ + this.user_id = this.$route.params.user_id; + this.getProfile(); + }, }; </script>