[feat RoleMiddleware, update AuthControlller, app.php, BrankasList, TrayList, Login.vue, web.php
This commit is contained in:
parent
e1a0711082
commit
8e59b1f1f1
@ -29,10 +29,14 @@ class AuthController extends Controller
|
||||
// buat token Sanctum
|
||||
$token = $user->createToken('auth_token')->plainTextToken;
|
||||
|
||||
$redirectUrl = $user->role === 'owner' ? '/brankas' : '/kasir';
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Login berhasil',
|
||||
'user' => $user,
|
||||
'token' => $token,
|
||||
'redirect' => $redirectUrl,
|
||||
'role' => $user->role
|
||||
]);
|
||||
}
|
||||
|
||||
|
30
app/Http/Middleware/RoleMiddleware.php
Normal file
30
app/Http/Middleware/RoleMiddleware.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class RoleMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, ...$roles): Response
|
||||
{
|
||||
// cek apakah user login
|
||||
if (!$request->user()) {
|
||||
return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
}
|
||||
|
||||
// cek role user
|
||||
if (!in_array($request->user()->role, $roles)) {
|
||||
return response()->json(['message' => 'Forbidden'], 403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -15,6 +15,10 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
$middleware->validateCsrfTokens(except: [
|
||||
'api/*'
|
||||
]);
|
||||
|
||||
$middleware->alias([
|
||||
'role' => \App\Http\Middleware\RoleMiddleware::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
|
@ -45,7 +45,11 @@ const error = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await axios.get("/api/item"); // ganti sesuai URL backend
|
||||
const res = await axios.get("/api/item",{
|
||||
headers:{
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
}
|
||||
}); // ganti sesuai URL backend
|
||||
items.value = res.data; // pastikan backend return array of items
|
||||
console.log(res.data);
|
||||
|
||||
|
@ -139,8 +139,14 @@ const saveMove = async () => {
|
||||
if (!selectedTrayId.value || !selectedItem.value) return;
|
||||
try {
|
||||
await axios.put(`/api/item/${selectedItem.value.id}`, {
|
||||
id_nampan: selectedTrayId.value,
|
||||
id_produk: selectedItem.value.id_produk, // ikutkan id_produk karena API minta
|
||||
header:{
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
},
|
||||
body:{
|
||||
id_nampan: selectedTrayId.value,
|
||||
id_produk: selectedItem.value.id_produk, // ikutkan id_produk karena API minta
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
await refreshData();
|
||||
|
@ -1,48 +1,72 @@
|
||||
<template>
|
||||
<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">
|
||||
<!-- Logo + Title -->
|
||||
<div class="mb-6">
|
||||
<img :src="logo" alt="Logo" class="mx-auto w-34 py-5">
|
||||
</div>
|
||||
<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">
|
||||
<!-- Logo + Title -->
|
||||
<div class="mb-6">
|
||||
<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>
|
||||
<!-- Input -->
|
||||
<div>
|
||||
<InputField
|
||||
v-model="username"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
class="mb-4"
|
||||
/>
|
||||
<PasswordInput v-model="password" placeholder="Password" />
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<button
|
||||
@click="handleLogin"
|
||||
class="w-full py-2 bg-sky-400 hover:bg-sky-500 rounded font-bold text-gray-800 transition"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
<!-- 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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import logo from '@/../images/logo.png'
|
||||
import InputField from "@/components/InputField.vue";
|
||||
import PasswordInput from "@/components/InputPassword.vue";
|
||||
import axios from "axios";
|
||||
|
||||
const username = ref("");
|
||||
const password = ref("");
|
||||
import PasswordInput from "@/components/InputPassword.vue";
|
||||
// import { ref } from "vue";
|
||||
const loading = ref(false);
|
||||
|
||||
// const username = ref("");
|
||||
// const password = ref("");
|
||||
const handleLogin = async () => {
|
||||
if (!username.value || !password.value) {
|
||||
alert("Harap isi username dan password!");
|
||||
return;
|
||||
}
|
||||
|
||||
// const handleLogin = () => {
|
||||
// if (!username.value || !password.value) {
|
||||
// alert("Harap isi username dan password!");
|
||||
// return;
|
||||
// }
|
||||
// // Contoh: panggil API login
|
||||
// console.log("Login dengan:", username.value, password.value);
|
||||
// };
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await axios.post("/api/login", {
|
||||
nama: username.value,
|
||||
password: password.value,
|
||||
});
|
||||
|
||||
const data = res.data;
|
||||
|
||||
// Simpan token & role
|
||||
localStorage.setItem("token", data.token);
|
||||
localStorage.setItem("role", data.role);
|
||||
|
||||
// Redirect sesuai role
|
||||
window.location.href = data.redirect;
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert("Login gagal. Periksa username atau password.");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
103
routes/web.php
103
routes/web.php
@ -1,53 +1,37 @@
|
||||
<?php
|
||||
use App\Http\Controllers\AuthController;
|
||||
use App\Http\Controllers\FotoSementaraController;
|
||||
use App\Http\Controllers\ItemController;
|
||||
use App\Http\Controllers\KategoriController;
|
||||
use App\Http\Controllers\NampanController;
|
||||
use App\Http\Controllers\ProdukController;
|
||||
use App\Http\Controllers\SalesController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\TransaksiController;
|
||||
use App\Http\Controllers\LaporanController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
||||
Route::prefix('api')->group(function () {
|
||||
// Backend API
|
||||
Route::apiResource('nampan', NampanController::class);
|
||||
Route::apiResource('produk', ProdukController::class);
|
||||
Route::apiResource('item', ItemController::class);
|
||||
Route::apiResource('sales', SalesController::class);
|
||||
Route::apiResource('user', UserController::class);
|
||||
Route::apiResource('transaksi', TransaksiController::class);
|
||||
Route::apiResource('kategori', KategoriController::class);
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\AuthController;
|
||||
use App\Http\Controllers\FotoSementaraController;
|
||||
use App\Http\Controllers\ItemController;
|
||||
use App\Http\Controllers\KategoriController;
|
||||
use App\Http\Controllers\NampanController;
|
||||
use App\Http\Controllers\ProdukController;
|
||||
use App\Http\Controllers\SalesController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\TransaksiController;
|
||||
use App\Http\Controllers\LaporanController;
|
||||
use App\Models\Kategori;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
||||
// ============================
|
||||
// Backend API
|
||||
// ============================
|
||||
Route::prefix('api')->group(function () {
|
||||
Route::apiResource('nampan', NampanController::class);
|
||||
Route::apiResource('produk', ProdukController::class);
|
||||
Route::apiResource('item', ItemController::class);
|
||||
Route::apiResource('sales', SalesController::class);
|
||||
Route::apiResource('user', UserController::class);
|
||||
Route::apiResource('transaksi', TransaksiController::class);
|
||||
Route::apiResource('kategori', KategoriController::class);
|
||||
// Auth
|
||||
Route::post('/login', [AuthController::class, 'login'])->middleware('guest')->name('login');
|
||||
Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum')->name('logout');
|
||||
|
||||
Route::get('brankas', [ItemController::class, 'brankasItem']);
|
||||
Route::delete('kosongkan-nampan', [NampanController::class, 'kosongkan']);
|
||||
Route::middleware(['auth:sanctum', 'role:owner'])->group(function () {
|
||||
Route::apiResource('nampan', NampanController::class)->except(['index', 'show']);
|
||||
Route::apiResource('produk', ProdukController::class)->except(['index', 'show']);
|
||||
Route::apiResource('item', ItemController::class)->except(['index', 'show']);
|
||||
Route::apiResource('sales', SalesController::class)->except(['index', 'show']);
|
||||
Route::apiResource('kategori', KategoriController::class)->except(['index', 'show']);
|
||||
Route::apiResource('user', UserController::class);
|
||||
|
||||
// Foto Sementara
|
||||
Route::post('foto/upload', [FotoSementaraController::class, 'upload']);
|
||||
Route::delete('foto/hapus/{id}', [FotoSementaraController::class, 'hapus']);
|
||||
Route::get('foto/{user_id}', [FotoSementaraController::class, 'getAll']);
|
||||
Route::delete('foto/reset/{user_id}', [FotoSementaraController::class, 'reset']);
|
||||
// Custom Endpoint
|
||||
|
||||
// Laporan
|
||||
Route::get('laporan', [LaporanController::class, 'ringkasan']);
|
||||
Route::get('detail-laporan', [LaporanController::class, 'detail']);
|
||||
});
|
||||
|
||||
Route::get('brankas', [ItemController::class, 'brankasItem']);
|
||||
Route::delete('kosongkan-nampan', [NampanController::class, 'kosongkan']);
|
||||
|
||||
// Foto Sementara
|
||||
@ -56,11 +40,32 @@ Route::prefix('api')->group(function () {
|
||||
Route::get('foto/{user_id}', [FotoSementaraController::class, 'getAll']);
|
||||
Route::delete('foto/reset/{user_id}', [FotoSementaraController::class, 'reset']);
|
||||
|
||||
Route::post('/login', [AuthController::class, 'login'])->middleware('guest')->name('login');
|
||||
Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum')->name('logout');
|
||||
// Laporan
|
||||
Route::get('laporan', [LaporanController::class, 'ringkasan']);
|
||||
Route::get('detail-laporan', [LaporanController::class, 'detail']);
|
||||
});
|
||||
|
||||
// Frontend SPA
|
||||
Route::get('/{any}', function () {
|
||||
return view('app');
|
||||
})->where('any', '^(?!storage|api).*$');
|
||||
Route::middleware(['auth:sanctum', 'role:owner,kasir'])->group(function () {
|
||||
Route::apiResource('transaksi', TransaksiController::class);
|
||||
Route::get('produk', [ProdukController::class, 'index']);
|
||||
Route::get('produk/{id}', [ProdukController::class, 'show']);
|
||||
Route::get('nampan', [NampanController::class, 'index']);
|
||||
Route::get('nampan/{id}', [NampanController::class, 'show']);
|
||||
Route::get('item', [ItemController::class, 'index']);
|
||||
Route::get('item/{id}', [ItemController::class, 'show']);
|
||||
Route::get('sales', [SalesController::class, 'index']);
|
||||
Route::get('sales/{id}', [SalesController::class, 'show']);
|
||||
Route::get('kategori', [KategoriController::class, 'index']);
|
||||
Route::get('kategori/{id}', [KategoriController::class, 'show']);
|
||||
Route::get('brankas', [ItemController::class, 'brankasItem']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
// ============================
|
||||
// Frontend SPA (Vue / React dll.)
|
||||
// ============================
|
||||
Route::get('/{any}', function () {
|
||||
return view('app');
|
||||
})->where('any', '^(?!storage|api).*$');
|
||||
|
Loading…
Reference in New Issue
Block a user