Compare commits
2 Commits
6b9ec0515a
...
6204acc6aa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6204acc6aa | ||
|
|
c65f0a857b |
@ -22,7 +22,7 @@
|
|||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<div>
|
<div>
|
||||||
<label for="password" class="block text-sm font-medium">Password</label>
|
<label for="password" class="block text-sm font-medium">Password</label>
|
||||||
<InputField
|
<InputPassword
|
||||||
v-model="form.password"
|
v-model="form.password"
|
||||||
id="password"
|
id="password"
|
||||||
type="password"
|
type="password"
|
||||||
@ -77,10 +77,11 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import InputField from "@/components/InputField.vue";
|
import InputField from "@/components/InputField.vue";
|
||||||
import InputSelect from "@/components/InputSelect.vue";
|
import InputSelect from "@/components/InputSelect.vue";
|
||||||
|
import InputPassword from "./InputPassword.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "CreateAkun",
|
name: "CreateAkun",
|
||||||
components: { InputField, InputSelect },
|
components: { InputField, InputSelect, InputPassword },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: { nama: "", password: "", role: "" },
|
form: { nama: "", password: "", role: "" },
|
||||||
|
|||||||
@ -1,174 +1,210 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 flex items-center justify-center bg-black/65 z-50">
|
<div class="fixed inset-0 flex items-center justify-center bg-black/65 z-50">
|
||||||
<div class="bg-white rounded-lg p-6 w-96 shadow-lg">
|
<div class="bg-white rounded-lg p-6 w-96 shadow-lg">
|
||||||
<h2 class="text-lg font-bold mb-4">Edit Akun</h2>
|
<h2 class="text-lg font-bold mb-4">Edit Akun</h2>
|
||||||
|
|
||||||
<form @submit.prevent="updateAkun" class="space-y-3">
|
<form @submit.prevent="updateAkun" class="space-y-3">
|
||||||
<!-- Nama -->
|
<!-- Nama -->
|
||||||
<div>
|
<div>
|
||||||
<label for="nama" class="block text-sm font-medium">Nama</label>
|
<label for="nama" class="block text-sm font-medium">Nama</label>
|
||||||
<InputField
|
<InputField
|
||||||
v-model="form.nama"
|
v-model="form.nama"
|
||||||
id="nama"
|
id="nama"
|
||||||
type="text"
|
type="text"
|
||||||
:required="true"
|
:required="true"
|
||||||
@input="clearError('nama')"
|
@input="clearError('nama')"
|
||||||
/>
|
/>
|
||||||
<p v-if="errors.nama" class="text-red-500 text-sm">{{ errors.nama }}</p>
|
<p v-if="errors.nama" class="text-red-500 text-sm">{{ errors.nama }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<div>
|
<div>
|
||||||
<label for="password" class="block text-sm font-medium">Password</label>
|
<label for="password" class="block text-sm font-medium">Password</label>
|
||||||
<InputField
|
<InputPassword
|
||||||
v-model="form.password"
|
v-model="form.password"
|
||||||
id="password"
|
id="password"
|
||||||
type="password"
|
type="password"
|
||||||
:required="false"
|
:required="false"
|
||||||
@input="clearError('password')"
|
@input="clearError('password')"
|
||||||
/>
|
/>
|
||||||
<p class="text-sm">Kosongkan jika tidak ingin ubah password</p>
|
<p class="text-sm">Kosongkan jika tidak ingin ubah password</p>
|
||||||
<p v-if="errors.password" class="text-red-500 text-sm">{{ errors.password }}</p>
|
<p v-if="errors.password" class="text-red-500 text-sm">{{ errors.password }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Role -->
|
<!-- Confirm Password -->
|
||||||
<div>
|
<div v-if="form.password">
|
||||||
<label for="role" class="block text-sm font-medium">Peran</label>
|
<label for="confirmPassword" class="block text-sm font-medium">Konfirmasi Password</label>
|
||||||
<InputSelect
|
<InputPassword
|
||||||
v-model="form.role"
|
v-model="form.confirmPassword"
|
||||||
:options="[
|
id="confirmPassword"
|
||||||
{ value: 'owner', label: 'Owner' },
|
type="password"
|
||||||
{ value: 'kasir', label: 'Kasir' }
|
:required="false"
|
||||||
]"
|
@input="clearError('confirmPassword')"
|
||||||
placeholder="-- Pilih Peran --"
|
/>
|
||||||
@change="clearError('role')"
|
<p v-if="errors.confirmPassword" class="text-red-500 text-sm">
|
||||||
/>
|
{{ errors.confirmPassword }}
|
||||||
<p v-if="errors.role" class="text-red-500 text-sm">{{ errors.role }}</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tombol -->
|
<!-- Role -->
|
||||||
<div class="flex justify-end gap-2 mt-4">
|
<div>
|
||||||
<button
|
<label for="role" class="block text-sm font-medium">Peran</label>
|
||||||
type="button"
|
|
||||||
@click="$emit('close')"
|
<!-- 🔒 Kalau akun sendiri tampil readonly -->
|
||||||
class="bg-gray-300 hover:bg-gray-400 px-4 py-2 rounded"
|
<template v-if="isEditingSelf">
|
||||||
>
|
<p class="mt-1 px-3 py-2 border rounded bg-gray-100 text-gray-700">
|
||||||
Batal
|
{{ form.role === 'owner' ? 'Owner' : 'Kasir' }}
|
||||||
</button>
|
</p>
|
||||||
<button
|
</template>
|
||||||
type="submit"
|
|
||||||
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"
|
<!-- 🔓 Kalau akun lain bisa diubah -->
|
||||||
>
|
<template v-else>
|
||||||
Ubah
|
<InputSelect
|
||||||
</button>
|
v-model="form.role"
|
||||||
</div>
|
:options="[
|
||||||
</form>
|
{ value: 'owner', label: 'Owner' },
|
||||||
|
{ value: 'kasir', label: 'Kasir' }
|
||||||
<!-- Error global -->
|
]"
|
||||||
<p v-if="errorMessage" class="text-red-500 text-sm mt-3">
|
placeholder="-- Pilih Peran --"
|
||||||
{{ errorMessage }}
|
@change="clearError('role')"
|
||||||
</p>
|
/>
|
||||||
|
<p v-if="errors.role" class="text-red-500 text-sm">{{ errors.role }}</p>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tombol -->
|
||||||
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="$emit('close')"
|
||||||
|
class="bg-gray-300 hover:bg-gray-400 px-4 py-2 rounded"
|
||||||
|
>
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
:disabled="!isFormValid"
|
||||||
|
>
|
||||||
|
Ubah
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Error global -->
|
||||||
|
<p v-if="errorMessage" class="text-red-500 text-sm mt-3">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</template>
|
|
||||||
|
<script setup>
|
||||||
<script>
|
import { ref, computed, onMounted } from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import InputField from "@/components/InputField.vue";
|
import InputField from "@/components/InputField.vue";
|
||||||
import InputSelect from "@/components/InputSelect.vue";
|
import InputSelect from "@/components/InputSelect.vue";
|
||||||
|
import InputPassword from "./InputPassword.vue";
|
||||||
export default {
|
|
||||||
name: "EditAkun",
|
const props = defineProps({
|
||||||
props: {
|
|
||||||
akun: {
|
akun: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
components: { InputField, InputSelect },
|
|
||||||
data() {
|
const emit = defineEmits(["refresh", "close"]);
|
||||||
return {
|
|
||||||
form: {
|
const form = ref({
|
||||||
nama: this.akun?.nama || "",
|
nama: props.akun?.nama || "",
|
||||||
password: "",
|
password: "",
|
||||||
role: this.akun?.role || "",
|
confirmPassword: "",
|
||||||
},
|
role: props.akun?.role || "",
|
||||||
errors: { nama: "", password: "", role: "" },
|
});
|
||||||
errorMessage: "",
|
|
||||||
};
|
const errors = ref({ nama: "", password: "", confirmPassword: "", role: "" });
|
||||||
},
|
const errorMessage = ref("");
|
||||||
watch: {
|
const loggedInId = ref(localStorage.getItem("userId")); // 🔥 ambil dari localStorage
|
||||||
akun: {
|
|
||||||
handler(newVal) {
|
const isFormValid = computed(() => {
|
||||||
if (newVal) {
|
if (form.value.password && form.value.password !== form.value.confirmPassword) {
|
||||||
this.form = {
|
return false;
|
||||||
nama: newVal.nama || "",
|
}
|
||||||
password: "",
|
return (
|
||||||
role: newVal.role || "",
|
form.value.nama.trim() &&
|
||||||
};
|
form.value.role &&
|
||||||
this.errors = { nama: "", password: "", role: "" };
|
!errors.value.nama &&
|
||||||
this.errorMessage = "";
|
!errors.value.password &&
|
||||||
}
|
!errors.value.confirmPassword &&
|
||||||
},
|
!errors.value.role
|
||||||
deep: true,
|
);
|
||||||
immediate: true,
|
});
|
||||||
},
|
|
||||||
},
|
// 🔥 ini cek apakah akun yang diedit adalah akun sendiri
|
||||||
methods: {
|
const isEditingSelf = computed(() => {
|
||||||
clearError(field) {
|
return String(props.akun.id) === String(loggedInId.value);
|
||||||
this.errors[field] = "";
|
});
|
||||||
this.errorMessage = "";
|
|
||||||
},
|
const clearError = (field) => {
|
||||||
validateForm() {
|
errors.value[field] = "";
|
||||||
let valid = true;
|
errorMessage.value = "";
|
||||||
this.errors = { nama: "", password: "", role: "" };
|
};
|
||||||
|
|
||||||
if (!this.form.nama) {
|
const validateForm = () => {
|
||||||
this.errors.nama = "Nama wajib diisi";
|
let valid = true;
|
||||||
valid = false;
|
errors.value = { nama: "", password: "", confirmPassword: "", role: "" };
|
||||||
}
|
|
||||||
if (this.form.password && this.form.password.length < 6) {
|
if (!form.value.nama) {
|
||||||
this.errors.password = "Password minimal 6 karakter";
|
errors.value.nama = "Nama wajib diisi";
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
if (!this.form.role) {
|
if (form.value.password && form.value.password.length < 6) {
|
||||||
this.errors.role = "Role wajib dipilih";
|
errors.value.password = "Password minimal 6 karakter";
|
||||||
valid = false;
|
valid = false;
|
||||||
} else if (!["owner", "kasir"].includes(this.form.role)) {
|
}
|
||||||
this.errors.role = "Role harus owner atau kasir";
|
if (form.value.password && form.value.password !== form.value.confirmPassword) {
|
||||||
valid = false;
|
errors.value.confirmPassword = "Konfirmasi password tidak cocok";
|
||||||
}
|
valid = false;
|
||||||
|
}
|
||||||
return valid;
|
if (!form.value.role) {
|
||||||
},
|
errors.value.role = "Role wajib dipilih";
|
||||||
async updateAkun() {
|
valid = false;
|
||||||
if (!this.validateForm()) return;
|
}
|
||||||
|
|
||||||
try {
|
return valid;
|
||||||
const payload = { ...this.form };
|
};
|
||||||
if (!payload.password) delete payload.password;
|
|
||||||
|
const updateAkun = async () => {
|
||||||
await axios.put(`/api/user/${this.akun.id}`, payload, {
|
if (!validateForm()) return;
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
try {
|
||||||
},
|
const payload = { ...form.value };
|
||||||
|
if (!payload.password) delete payload.password;
|
||||||
|
delete payload.confirmPassword;
|
||||||
|
|
||||||
|
await axios.put(`/api/user/${props.akun.id}`, payload, {
|
||||||
|
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
|
||||||
|
});
|
||||||
|
|
||||||
|
emit("refresh");
|
||||||
|
emit("close");
|
||||||
|
} catch (err) {
|
||||||
|
if (err.response?.status === 422 && err.response.data.errors) {
|
||||||
|
const backendErrors = err.response.data.errors;
|
||||||
|
Object.keys(backendErrors).forEach((key) => {
|
||||||
|
errors.value[key] = backendErrors[key][0];
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
this.$emit("refresh");
|
errorMessage.value = err.response?.data?.message || "Gagal update akun.";
|
||||||
this.$emit("close");
|
|
||||||
} catch (err) {
|
|
||||||
if (err.response?.status === 422 && err.response.data.errors) {
|
|
||||||
const backendErrors = err.response.data.errors;
|
|
||||||
Object.keys(backendErrors).forEach((key) => {
|
|
||||||
this.errors[key] = backendErrors[key][0];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.errorMessage =
|
|
||||||
err.response?.data?.message || "Gagal update akun.";
|
|
||||||
}
|
|
||||||
console.error("Gagal update akun:", err);
|
|
||||||
}
|
}
|
||||||
},
|
console.error("Gagal update akun:", err);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
</script>
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log("Akun.id:", props.akun.id);
|
||||||
|
console.log("LoggedInId:", loggedInId.value);
|
||||||
|
console.log("isEditingSelf:", isEditingSelf.value);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative mb-8">
|
<div class="relative mb-1">
|
||||||
<input
|
<input
|
||||||
:type="showPassword ? 'text' : 'password'"
|
:type="showPassword ? 'text' : 'password'"
|
||||||
:value="modelValue"
|
:value="modelValue"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@input="$emit('update:modelValue', $event.target.value)"
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
class="mt-1 block w-full rounded-md shadow-sm sm:text-sm
|
class="mt-1 block w-full rounded-md shadow-sm sm:text-sm
|
||||||
bg-A text-D border-B focus:border-C
|
bg-A text-D border-B focus:border-C
|
||||||
focus:ring focus:ring-D focus:ring-opacity-50 p-2 pr-10"
|
focus:ring focus:ring-D focus:ring-opacity-50 p-2 pr-10"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@ -51,14 +51,14 @@
|
|||||||
|
|
||||||
<!-- Table Section -->
|
<!-- Table Section -->
|
||||||
<div
|
<div
|
||||||
class="bg-white rounded-lg shadow-md border border-C overflow-hidden"
|
class="bg-white rounded-lg shadow-md border border-D overflow-hidden"
|
||||||
>
|
>
|
||||||
<table class="w-full">
|
<table class="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="bg-C text-white">
|
<tr class="bg-C text-white">
|
||||||
<th class="px-6 py-4 text-center text-D border-r border-C">No</th>
|
<th class="px-6 py-4 text-center text-D border-r border-D">No</th>
|
||||||
<th class="px-6 py-4 text-center text-D border-r border-C">Nama</th>
|
<th class="px-6 py-4 text-center text-D border-r border-D">Nama</th>
|
||||||
<th class="px-6 py-4 text-center text-D border-r border-C">Peran</th>
|
<th class="px-6 py-4 text-center text-D border-r border-D">Peran</th>
|
||||||
<th class="px-6 py-4 text-center text-D">Aksi</th>
|
<th class="px-6 py-4 text-center text-D">Aksi</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -66,16 +66,16 @@
|
|||||||
<tr
|
<tr
|
||||||
v-for="(item, index) in akun"
|
v-for="(item, index) in akun"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="border-b border-C hover:bg-gray-50 transition duration-150"
|
class="border-b border-D hover:bg-gray-50 transition duration-150"
|
||||||
:class="{ 'bg-gray-50': index % 2 === 1 }"
|
:class="{ 'bg-gray-50': index % 2 === 1 }"
|
||||||
>
|
>
|
||||||
<td class="px-6 py-4 border-r border-C text-center font-medium text-gray-900">
|
<td class="px-6 py-4 border-r border-D text-center font-medium text-gray-900">
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 border-r border-C text-D">
|
<td class="px-6 py-4 border-r border-D text-D">
|
||||||
{{ item.nama }}
|
{{ item.nama }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 border-r border-C text-gray-800">
|
<td class="px-6 py-4 border-r border-D text-gray-800">
|
||||||
{{ item.role }}
|
{{ item.role }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 text-center">
|
<td class="px-6 py-4 text-center">
|
||||||
|
|||||||
@ -1,70 +1,86 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-center min-h-screen bg-[#0c4b66]">
|
<div class="flex items-center justify-center min-h-screen bg-[#0c4b66]">
|
||||||
<div class="bg-white p-8 rounded-2xl shadow-xl w-80 text-center">
|
<div class="bg-white p-8 rounded-2xl shadow-xl w-80 text-center">
|
||||||
<!-- Logo + Title -->
|
<!-- Logo + Title -->
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<img :src="logo" alt="Logo" class="mx-auto w-34 py-5" />
|
<img :src="logo" alt="Logo" class="mx-auto w-34 py-5" />
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Input -->
|
|
||||||
<div>
|
|
||||||
<InputField
|
|
||||||
v-model="username"
|
|
||||||
type="text"
|
|
||||||
placeholder="Username"
|
|
||||||
class="mb-4"
|
|
||||||
/>
|
|
||||||
<PasswordInput v-model="password" placeholder="Password" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Button -->
|
|
||||||
<button
|
|
||||||
@click="handleLogin"
|
|
||||||
:disabled="loading"
|
|
||||||
class="w-full py-2 bg-sky-400 hover:bg-sky-500 rounded font-bold text-gray-800 transition disabled:opacity-50"
|
|
||||||
>
|
|
||||||
{{ loading ? "Loading..." : "Login" }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Input -->
|
||||||
|
<div>
|
||||||
|
<InputField
|
||||||
|
v-model="username"
|
||||||
|
type="text"
|
||||||
|
placeholder="Username"
|
||||||
|
class="mb-4"
|
||||||
|
/>
|
||||||
|
<InputPassword v-model="password" placeholder="Password" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="errorMessage"
|
||||||
|
class="mt-2 text-red-500 text-xs font-medium text-left"
|
||||||
|
>
|
||||||
|
{{ errorMessage }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Button -->
|
||||||
|
<button
|
||||||
|
@click="handleLogin"
|
||||||
|
:disabled="loading"
|
||||||
|
class="w-full mt-6 py-2 bg-sky-400 hover:bg-sky-500 rounded font-bold text-gray-800 transition disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{{ loading ? "Loading..." : "Login" }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import logo from '@/../images/logo.png'
|
import logo from "@/../images/logo.png";
|
||||||
import InputField from "@/components/InputField.vue";
|
import InputField from "@/components/InputField.vue";
|
||||||
import PasswordInput from "@/components/InputPassword.vue";
|
import InputPassword from "@/components/InputPassword.vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const username = ref("");
|
const username = ref("");
|
||||||
const password = ref("");
|
const password = ref("");
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const errorMessage = ref("");
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
if (!username.value || !password.value) {
|
if (!username.value || !password.value) {
|
||||||
alert("Harap isi username dan password!");
|
errorMessage.value = "Harap isi username dan password!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
errorMessage.value = "";
|
||||||
const res = await axios.post("/api/login", {
|
try {
|
||||||
nama: username.value,
|
const res = await axios.post("/api/login", {
|
||||||
password: password.value,
|
nama: username.value,
|
||||||
});
|
password: password.value,
|
||||||
|
});
|
||||||
|
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
|
|
||||||
// Simpan token & role
|
// Simpan token & role
|
||||||
localStorage.setItem("token", data.token);
|
localStorage.setItem("token", data.token);
|
||||||
localStorage.setItem("role", data.role);
|
localStorage.setItem("role", data.role);
|
||||||
|
localStorage.setItem("userId", data.user.id);
|
||||||
|
localStorage.setItem("nama", data.user.nama);
|
||||||
|
localStorage.setItem("role", data.user.role);
|
||||||
|
|
||||||
// Redirect sesuai role
|
|
||||||
window.location.href = data.redirect;
|
|
||||||
|
|
||||||
} catch (error) {
|
// Redirect sesuai role
|
||||||
console.error(error);
|
window.location.href = data.redirect;
|
||||||
alert("Login gagal. Periksa username atau password.");
|
} catch (error) {
|
||||||
|
if (error.response?.data?.message) {
|
||||||
|
errorMessage.value = error.response.data.message;
|
||||||
|
} else {
|
||||||
|
errorMessage.value = "Login gagal. Periksa username atau password.";
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user