feat: implement analysis module with dedicated controller, view, and role-based permissions

This commit is contained in:
Yoga Pangestu 2026-06-23 14:15:32 +07:00
parent 04ee7c3426
commit 41ee835f1f
6 changed files with 118 additions and 1 deletions

View File

@ -9,6 +9,7 @@ enum Permission: string
use ProvidesEnumOptions;
case DASHBOARD_VIEW = 'dashboard.view';
case ANALYSIS_VIEW = 'analysis.view';
case EMPLOYEES_VIEW = 'employees.view';
case EMPLOYEES_CREATE = 'employees.create';
@ -117,6 +118,7 @@ public function label(): string
{
return match ($this) {
self::DASHBOARD_VIEW => 'Lihat Dashboard',
self::ANALYSIS_VIEW => 'Lihat Analisa',
self::EMPLOYEES_VIEW => 'Lihat Pegawai',
self::EMPLOYEES_CREATE => 'Tambah Pegawai',
@ -227,6 +229,7 @@ public function group(): string
{
return match ($this) {
self::DASHBOARD_VIEW => 'Umum',
self::ANALYSIS_VIEW => 'Umum',
self::EMPLOYEES_VIEW, self::EMPLOYEES_CREATE, self::EMPLOYEES_UPDATE,
self::EMPLOYEES_DELETE, self::EMPLOYEES_RESET_PASSWORD, self::EMPLOYEES_TOGGLE_STATUS => 'Pegawai',
self::ATTENDANCES_VIEW, self::ATTENDANCES_CREATE, self::ATTENDANCES_DELETE,

View File

@ -44,6 +44,7 @@ public function permissions(): array
self::DIREKTUR => [
Permission::DASHBOARD_VIEW,
Permission::ANALYSIS_VIEW,
Permission::EMPLOYEES_VIEW,
@ -90,6 +91,7 @@ public function permissions(): array
self::ADMIN_TOKO => [
Permission::DASHBOARD_VIEW,
Permission::ANALYSIS_VIEW,
Permission::STOCKS_VIEW,

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class AnalysisController extends Controller
{
public function index(Request $request): Response
{
return Inertia::render('admin/Analysis', [
'filters' => [
'search' => $request->query('search', ''),
'status' => $request->query('status', ''),
],
]);
}
}

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { Link, usePage } from '@inertiajs/vue3';
import { Banknote, CalendarDays, CheckCircle, Clock, FolderTree, History, Layers, LayoutDashboard, Package, Receipt, Scissors, Settings2, Shield, ShoppingBag, ShoppingCart, User, UserCheck, Users, Wallet, WalletCards, Warehouse } from '@lucide/vue';
import { Banknote, CalendarDays, CheckCircle, Clock, FolderTree, History, Layers, LayoutDashboard, Package, Receipt, Scissors, Settings2, Shield, ShoppingBag, ShoppingCart, TrendingUp, User, UserCheck, Users, Wallet, WalletCards, Warehouse } from '@lucide/vue';
import {
Sidebar,
SidebarContent,
@ -38,6 +38,7 @@ const menuGroups: MenuGroup[] = [
label: 'Menu',
items: [
{ title: 'Dasbor', href: admin.dashboard.url(), icon: LayoutDashboard },
{ title: 'Analisa', href: admin.analysis.url(), icon: TrendingUp, permission: 'analysis.view' },
],
},
{

View File

@ -0,0 +1,85 @@
<script setup lang="ts">
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from '@/components/ui/card';
import AdminLayout from '@/layouts/AdminLayout.vue';
import { Head } from '@inertiajs/vue3';
import { computed, ref, watch } from 'vue';
import admin from '@/routes/admin';
import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
import type { DataTableFilterDef } from '@/types/data-table';
import {
useDataTableQuery,
useDataTableQuerySync,
} from '@/composables/useDataTableQuery';
import { Presentation } from '@lucide/vue';
const props = defineProps<{
filters: {
search: string;
status?: string;
};
}>();
const search = ref(props.filters.search ?? '');
const { query, setSearch, setFilter, resetFilters, syncFromServer } =
useDataTableQuery({
url: admin.analysis.url(),
initial: { ...props.filters },
filterKeys: ['status'],
});
useDataTableQuerySync(() => props.filters, syncFromServer);
const filterDefs = computed<DataTableFilterDef[]>(() => [
{
key: 'status',
label: 'Status',
type: 'select',
options: [
{ value: 'active', label: 'Aktif' },
{ value: 'inactive', label: 'Nonaktif' },
],
},
]);
const filterValues = computed(() => ({
status: query.value.status ?? '',
}));
watch(search, (value) => {
setSearch(value);
});
watch(
() => props.filters.search,
(value) => {
search.value = value ?? '';
},
);
</script>
<template>
<Head title="Analisa" />
<AdminLayout>
<div class="flex flex-col gap-6">
<!-- Header -->
<div
class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"
>
<div class="space-y-1">
<h2 class="text-2xl font-bold tracking-tight">Analisa</h2>
<p class="text-sm text-muted-foreground">
Halaman analisa data dan performa toko.
</p>
</div>
</div>
</div>
</AdminLayout>
</template>

View File

@ -5,6 +5,7 @@
use App\Http\Controllers\Admin\Account\PasswordController;
use App\Http\Controllers\Admin\Account\PermissionsController;
use App\Http\Controllers\Admin\Account\ProfileController;
use App\Http\Controllers\Admin\AnalysisController;
use App\Http\Controllers\Admin\DashboardController;
use App\Http\Controllers\Admin\Finance\CashController;
use App\Http\Controllers\Admin\Finance\EmployeeAdvanceController;
@ -53,6 +54,10 @@
Route::get('/dashboard', [DashboardController::class, 'index'])
->name('dashboard');
Route::get('/analysis', [AnalysisController::class, 'index'])
->middleware('permission:'.Permission::ANALYSIS_VIEW->value)
->name('analysis');
Route::prefix('master')->name('master.')->group(function () {
Route::prefix('categories')->name('categories.')
->middleware('permission:'.Permission::CATEGORIES_VIEW->value)