diff --git a/package-lock.json b/package-lock.json index 48f47d2a68c7625508106ca651eeac7650da8e24..6ab5819ad4921d0e9ded6be35466dfb3c1dd23c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "jquery": "^3.6.0", "vue": "^3.0.0", "vue-router": "^4.0.12", - "vue-select": "^4.0.0-beta.3" + "vue-select": "^4.0.0-beta.3", + "vue3-click-away": "^1.2.4" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", @@ -14050,6 +14051,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "node_modules/vue3-click-away": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/vue3-click-away/-/vue3-click-away-1.2.4.tgz", + "integrity": "sha512-O9Z2KlvIhJT8OxaFy04eiZE9rc1Mk/bp+70dLok68ko3Kr8AW5dU+j8avSk4GDQu94FllSr4m5ul4BpzlKOw1A==" + }, "node_modules/watchpack": { "version": "1.7.5", "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-1.7.5.tgz", @@ -26646,6 +26652,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vue3-click-away": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/vue3-click-away/-/vue3-click-away-1.2.4.tgz", + "integrity": "sha512-O9Z2KlvIhJT8OxaFy04eiZE9rc1Mk/bp+70dLok68ko3Kr8AW5dU+j8avSk4GDQu94FllSr4m5ul4BpzlKOw1A==" + }, "watchpack": { "version": "1.7.5", "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-1.7.5.tgz", diff --git a/package.json b/package.json index 997dd32021d8e81eb96b522b3de7b263fbd17f2d..64277b37aad127db8078cf44410d0302be922e99 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "jquery": "^3.6.0", "vue": "^3.0.0", "vue-router": "^4.0.12", - "vue-select": "^4.0.0-beta.3" + "vue-select": "^4.0.0-beta.3", + "vue3-click-away": "^1.2.4" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", diff --git a/src/components/dropdown.vue b/src/components/dropdown.vue new file mode 100644 index 0000000000000000000000000000000000000000..814abf6eacb9711a1149c6f46f01ef50359d456f --- /dev/null +++ b/src/components/dropdown.vue @@ -0,0 +1,114 @@ +<template> + <div class="relative"> + <div id="start-button"> + <button + href="#" + class="ms-1" + style="border: none; background-color:transparent" + @click="toggleVisibility" + + > + <slot name="start-button-item"> Start-button-content</slot> + </button> + </div> + <Transition name="fade"> + <div class="item-container"> + <ul v-if="isVisible" class="item-parent" :style="topMargin"> + <li class="item" style="margin-right:var(--right-margin)"> + <slot name="item-1"></slot> + </li> + <li class="item" style="margin-right:var(--left-margin)"> + <slot name="item-2"></slot> + </li> + </ul> + </div> + + </Transition> + </div> +</template> + +<script> +//import { mixin as VueClickAway } from "vue3-click-away"; + +export default{ + //mixins: [VueClickAway], + props:['type'], + data(){ + return{ + isVisible: false, + top: 0, + right: 0, + left: 0, + // bgColor: 'transparent', + } + }, + methods: { + toggleVisibility(){ + this.isVisible = !this.isVisible + }, + hideDropdown(){ + this.isVisible = false + }, + defineCSS(){ + if (this.type === "dropdownUser"){ + this.top = 2.08; + this.right = 7.5; + // this.bgColor = "white"; + } + else if (this.type === "addUser"){ + this.top = 10.25; + this.right = 3; + this.left = -4.5; + } + } + }, + computed: { + topMargin(){ + this.defineCSS(); + return{ + '--top-margin': (this.top) + "rem", + '--right-margin': (this.right) + "em", + '--left-margin': (this.left) + "em" + // '--bg-color': (this.bgColor) + } + } + } +} +</script> + + +<style scoped> + .fade-enter-active, + .fade-leave-active { + transition: all 0.1s ease-in-out; + } + + .fade-enter-from, + .fade-leave-to { + opacity: 0; + transform: translateX(12px); + } + .item-parent { + position: absolute; + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + justify-content: space-between; + align-items: baseline; + top: var(--top-margin); + /* border: 1px; + border-color: black; */ + + } + .item { + position: absolute; + list-style:none; + width: 150px; + /* background-color: var(--bg-color); */ + } + /* .item-container { + display: flex; + border-color: black; + border-style: solid; + } */ +</style> \ No newline at end of file diff --git a/src/components/header.vue b/src/components/header.vue index 8dafca220cfb533c71ed0684e0baed707a9493dd..dc5a957735f5de77fa122d604d0433186d444290 100644 --- a/src/components/header.vue +++ b/src/components/header.vue @@ -28,15 +28,28 @@ <div class="col"> <div class="d-flex flex-row-reverse justify-content-start align-items-center illustration" - > - <button @click="showModal()" class="profile-btn"> - <i - class="icon ion-ios-person-outline text-red" - style="font-size: 65px" + > + <Dropdown type="dropdownUser"> + <template v-slot:start-button-item> + <i @click="onDisplayName" + 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> + </template> + <template v-slot:item-1> + <button class="btn-blue" @click="toProfile"> + <svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path class="heroicon-ui" d="M12 12a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm9 11a1 1 0 0 1-2 0v-2a3 3 0 0 0-3-3H8a3 3 0 0 0-3 3v2a1 1 0 0 1-2 0v-2a5 5 0 0 1 5-5h8a5 5 0 0 1 5 5v2z"></path></svg> + <span class="ms-1" style="color: white; weight: lighter">Profil</span> + </button> + </template> + <template v-slot:item-2> + <button class="btn-red" @click="toLogout"> + <svg fill="white" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"></path><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></svg> + <span class="ms-1" style="color: white; weight: lighter">Keluar</span> + </button> + </template> + </Dropdown> + <Name v-if="isNameDisplayed" :value="this.name"></Name> </div> </div> </div> @@ -44,29 +57,18 @@ <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 class="btn-blue mb-2 ms-2" @click="toProfile">Lihat Profil</button> - <!-- warna merah --> - <button class="btn-red ms-4" @click="toLogout">Keluar</button> - </template> - - </Modal> </template> <script> -import Modal from "../components/modal"; +import Dropdown from "../components/dropdown"; +import Name from "../components/name" import { HTTP } from '../http-common' export default { name: "Header", components: { - Modal + Dropdown, + Name }, data() { return { @@ -74,7 +76,9 @@ export default { isModalVisible: false, profile_employee:[], profile_admin:[], + isNameDisplayed: true, name:"", + helloName:"", id: null, user_id: null, is_admin: false, @@ -85,12 +89,9 @@ export default { this.nav_active = !this.nav_active document.getElementById("toggleNav").click() }, - showModal(){ - this.isModalVisible = true; - }, - closeModal(){ - this.isModalVisible = false; - }, + onDisplayName(){ + this.isNameDisplayed = !this.isNameDisplayed; + }, toProfile(){ if (this.is_admin){ this.$router.push({ name: "profil-admin", params: { id: this.id }}); @@ -102,11 +103,7 @@ export default { toLogout(e){ e.preventDefault(); console.log("logout") - this.$router.push('login') - // var a = localStorage.getItem("token"); - // console.log(a) - // var b = localStorage.removeItem("token"); - // console.log(b) + this.$router.push({ path: '/login' }) localStorage.removeItem("token"); console.log('token removed') window.location.reload() @@ -126,6 +123,7 @@ export default { this.user_id = this.profile_employee.user_id } }}) + // console.log(this.isNameDisplayed) }, }, mounted(){ @@ -155,24 +153,13 @@ 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; - transform: translate(150%, -80%); -} .btn-red { - background: #f4476b; - border-radius: 15px; - color: white; - border: none; - padding: 4% 15% 4% 15%; +background: #f4476b; +border-radius: 15px; +color: white; +border: none; +padding: 2% 13% 2% 10%; } .btn-blue { @@ -180,7 +167,7 @@ export default { border-radius: 15px; color: white; border: none; - padding: 4% 15% 4% 15%; + padding: 2% 13% 2% 10%; } </style> diff --git a/src/components/name.vue b/src/components/name.vue index 018d6746694830a4c4f7f1fa811bef344154ee05..be2315632ff3171e8927d53718c36d0582835d5a 100644 --- a/src/components/name.vue +++ b/src/components/name.vue @@ -1,11 +1,11 @@ <template> - <h2 class="text-red" style="text-align: right">Hello, {{name}}</h2> + <h2 class="text-red" style="text-align: right">Hello, {{value}}</h2> </template> <script> export default { name: "Name", - props:{name: String}, + props:{value: String}, }; </script> \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 832bff200f952167d6b061554df04aca263c582c..ded9c880ce6dfef1278adb81b6d6d14bf9b07fb9 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,4 +1,4 @@ -import { createRouter, createWebHistory } from "vue-router"; +import { createRouter, createWebHashHistory } from "vue-router"; //import Home from "../views/Home.vue"; import ProfilUser from "../views/ProfilUser.vue"; import ProfilAdmin from "../views/ProfilAdmin.vue"; @@ -158,7 +158,8 @@ const routes = [ ]; const router = createRouter({ - history: createWebHistory(process.env.BASE_URL), + // history: createWebHistory(process.env.BASE_URL), + history: createWebHashHistory(), routes, }); diff --git a/src/views/DepartemenIndex.vue b/src/views/DepartemenIndex.vue index 8442c4bc9f497359dc583178c8af2e1b02442c36..ad67c0c26524311e331b47ba98822081088852e6 100644 --- a/src/views/DepartemenIndex.vue +++ b/src/views/DepartemenIndex.vue @@ -59,14 +59,9 @@ 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> @@ -114,21 +109,8 @@ export default { isModalVisible: false, deptnameadd:"", deptnameedit:"", + curr_id:"", dept: [], - temp_dept: [ - { - id: 1, - nama: "Keuangan", - }, - { - id: 2, - nama: "Marketing", - }, - { - id: 3, - nama: "Operasional", - }, - ], columns: { Id : { name : "Id", @@ -168,20 +150,31 @@ export default { }, 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(); + + let data = { + name: formValue + } + console.log(data.name) + + HTTP.post("departments", data, { + headers:{ + 'Content-Type': 'application/json' + } + }).then((res)=>{ + if (res.status == 200){ + alert("Departemen berhasil ditambahkan") + this.closeModal() + } + }).catch(()=>{ + alert("Gagal menambahkan Departemen") + }) }, - // addDept(data){ - // console.log(data); - // }, getDept() { - // di sini ambil data admin dari database HTTP.get("departments").then((res)=>{ if (res.data.success == true){ this.dept = res.data.data @@ -191,56 +184,54 @@ export default { console.log(id); }, deleteDept(id) { - console.log(id); + if (confirm("Yakin akan menghapus Departemen?")){ + HTTP.delete(`departments/${id}`).then((res) =>{ + if (res.status == 200){ + alert("Berhasil menghapus Departemen") + this.getDept() + } + }).catch( () => { + alert("Gagal Menghapus Departemen") + } + ) + } }, 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") + let data = { + name: formValue + } + HTTP.put(`departments/${this.curr_id}`, data, { + headers: { + 'Content-Type': 'application/json' + } + }).then((res)=>{ + if (res.status == 200){ + alert("Departemen berhasil diedit") + this.closeModal() + } + }).catch(() => alert("Gagal mengedit Departemen")) - 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 - - + HTTP.get(`departments/${id}`).then((res)=>{ + if (res.status == 200){ + this.deptnameedit = res.data.data.name + } + } + ) + this.curr_id = id; }, - // updateDept(event){ - // console.log(event); - // } }, mounted() { this.getDept(); diff --git a/src/views/Login.vue b/src/views/Login.vue index f1fbac30b58f2bfac806949d26d737abe483a4b3..0b7dd1e7c7dc3cdeee36bc3e7ea207ae7564aaf8 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -115,7 +115,11 @@ export default { }) .catch(() => alert("username atau password salah")); }, + }, + mounted(){ + document.getElementById("app").style.padding = "0" + } }; </script>