From 23cc3271904b4f4172322b265bb926645054976c Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sat, 1 Aug 2026 10:14:47 +0700 Subject: [PATCH] Refactor code for improved readability and consistency across multiple files - Adjusted indentation and formatting in login, permissions, profile, and security pages for better readability. - Enhanced the clarity of conditional statements and function calls in permissions and profile components. - Updated type definitions in vite-env.d.ts for better code structure. - Cleaned up array mapping syntax in ProductTest.php for consistency. --- .../Admin/Finance/CashAccountController.php | 2 +- .../Finance/EmployeeAdvanceController.php | 2 +- .../Admin/Finance/ExpenseController.php | 2 +- .../Admin/Finance/PayrollController.php | 4 +- .../Admin/HR/EmployeeController.php | 2 +- .../Admin/HR/LeaveRequestController.php | 2 +- .../Admin/Master/CategoryController.php | 2 +- .../Admin/Master/CustomerController.php | 2 +- .../Admin/Master/ProductController.php | 9 +- .../Admin/Master/SupplierController.php | 2 +- app/Http/Controllers/Admin/RoleController.php | 2 +- app/Http/Controllers/Controller.php | 3 + .../Requests/Admin/Master/ProductRequest.php | 2 +- app/Models/ProductPrice.php | 1 - app/Models/ProductVariant.php | 2 +- app/Services/Admin/Master/ProductService.php | 4 +- resources/css/app.css | 321 +++---- resources/js/components/app-logo-icon.tsx | 4 +- resources/js/components/app-sidebar.tsx | 16 +- resources/js/components/camera-capture.tsx | 20 +- resources/js/components/data-table.tsx | 161 ++-- resources/js/components/date-picker.tsx | 78 +- resources/js/components/file-upload.tsx | 63 +- .../js/components/image-preview-modal.tsx | 17 +- resources/js/components/location-map.tsx | 18 +- resources/js/components/nav-user.tsx | 7 +- resources/js/components/pwa-update-toast.tsx | 8 +- resources/js/components/rupiah-input.tsx | 4 +- resources/js/hooks/use-file-upload.ts | 57 +- resources/js/hooks/use-initials.tsx | 4 +- resources/js/hooks/use-mobile.ts | 30 +- .../js/layouts/app/app-sidebar-layout.tsx | 5 +- .../js/layouts/auth/auth-card-layout.tsx | 6 +- resources/js/layouts/settings/layout.tsx | 4 +- resources/js/lib/upload.ts | 23 +- .../admin/finance/cash-account/columns.tsx | 20 +- .../admin/finance/cash-account/index.tsx | 555 ++++++++---- .../cash-account/transaction-columns.tsx | 84 +- .../finance/employee-advance/columns.tsx | 64 +- .../admin/finance/employee-advance/index.tsx | 285 +++++-- .../pages/admin/finance/expense/columns.tsx | 53 +- .../js/pages/admin/finance/expense/index.tsx | 354 +++++--- .../admin/finance/payroll-period/columns.tsx | 95 ++- .../admin/finance/payroll-period/index.tsx | 137 +-- .../finance/payroll-period/show-columns.tsx | 107 ++- .../admin/finance/payroll-period/show.tsx | 213 +++-- .../js/pages/admin/hr/attendance/index.tsx | 381 +++++++-- .../js/pages/admin/hr/employee/columns.tsx | 53 +- .../js/pages/admin/hr/employee/create.tsx | 149 +++- resources/js/pages/admin/hr/employee/edit.tsx | 175 +++- .../js/pages/admin/hr/employee/index.tsx | 204 +++-- .../pages/admin/hr/leave-request/columns.tsx | 49 +- .../js/pages/admin/hr/leave-request/index.tsx | 372 ++++++--- .../pages/admin/master/category/columns.tsx | 16 +- .../js/pages/admin/master/category/index.tsx | 169 ++-- .../pages/admin/master/customer/columns.tsx | 32 +- .../js/pages/admin/master/customer/index.tsx | 209 +++-- .../js/pages/admin/master/product/columns.tsx | 145 +++- .../js/pages/admin/master/product/create.tsx | 707 +++++++++++----- .../js/pages/admin/master/product/edit.tsx | 789 +++++++++++++----- .../js/pages/admin/master/product/index.tsx | 208 +++-- .../pages/admin/master/supplier/columns.tsx | 32 +- .../js/pages/admin/master/supplier/index.tsx | 209 +++-- resources/js/pages/admin/roles/columns.tsx | 16 +- resources/js/pages/admin/roles/create.tsx | 110 +-- resources/js/pages/admin/roles/edit.tsx | 114 +-- resources/js/pages/admin/roles/index.tsx | 101 ++- resources/js/pages/admin/settings/index.tsx | 621 +++++++++++--- resources/js/pages/auth/login.tsx | 6 +- resources/js/pages/settings/permissions.tsx | 80 +- resources/js/pages/settings/profile.tsx | 77 +- resources/js/pages/settings/security.tsx | 23 +- resources/js/types/vite-env.d.ts | 9 +- tests/Feature/Admin/Master/ProductTest.php | 11 +- 74 files changed, 5508 insertions(+), 2415 deletions(-) diff --git a/app/Http/Controllers/Admin/Finance/CashAccountController.php b/app/Http/Controllers/Admin/Finance/CashAccountController.php index 35391ab..fb784ff 100644 --- a/app/Http/Controllers/Admin/Finance/CashAccountController.php +++ b/app/Http/Controllers/Admin/Finance/CashAccountController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Finance; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Finance\CashTransactionRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\CashTransaction; use App\Services\Admin\Finance\CashAccountService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php b/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php index 75ad0a7..1031240 100644 --- a/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php +++ b/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Finance; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Finance\EmployeeAdvanceRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\EmployeeAdvance; use App\Services\Admin\Finance\EmployeeAdvanceService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/Finance/ExpenseController.php b/app/Http/Controllers/Admin/Finance/ExpenseController.php index 478634c..47f9244 100644 --- a/app/Http/Controllers/Admin/Finance/ExpenseController.php +++ b/app/Http/Controllers/Admin/Finance/ExpenseController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Finance; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Finance\ExpenseRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\Expense; use App\Services\Admin\Finance\ExpenseService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/Finance/PayrollController.php b/app/Http/Controllers/Admin/Finance/PayrollController.php index d1b8676..5ef7549 100644 --- a/app/Http/Controllers/Admin/Finance/PayrollController.php +++ b/app/Http/Controllers/Admin/Finance/PayrollController.php @@ -16,7 +16,7 @@ public function __construct( public function pay(Payroll $payroll): RedirectResponse { return $this->handleAction( - fn() => $this->service->pay($payroll), + fn () => $this->service->pay($payroll), 'Gaji berhasil dibayar.', 'admin.finance.payroll-periods.show', parameters: ['payroll_period' => $payroll->payroll_period_id] @@ -26,7 +26,7 @@ public function pay(Payroll $payroll): RedirectResponse public function cancel(Payroll $payroll): RedirectResponse { return $this->handleAction( - fn() => $this->service->cancel($payroll), + fn () => $this->service->cancel($payroll), 'Gaji berhasil dibatalkan.', 'admin.finance.payroll-periods.show', parameters: ['payroll_period' => $payroll->payroll_period_id] diff --git a/app/Http/Controllers/Admin/HR/EmployeeController.php b/app/Http/Controllers/Admin/HR/EmployeeController.php index 6b64a86..53ca1bb 100644 --- a/app/Http/Controllers/Admin/HR/EmployeeController.php +++ b/app/Http/Controllers/Admin/HR/EmployeeController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\HR; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\HR\EmployeeRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\User; use App\Services\Admin\HR\EmployeeService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/HR/LeaveRequestController.php b/app/Http/Controllers/Admin/HR/LeaveRequestController.php index 5fcb915..e941d04 100644 --- a/app/Http/Controllers/Admin/HR/LeaveRequestController.php +++ b/app/Http/Controllers/Admin/HR/LeaveRequestController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\HR; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\HR\LeaveRequestRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\LeaveRequest; use App\Services\Admin\HR\LeaveRequestService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/Master/CategoryController.php b/app/Http/Controllers/Admin/Master/CategoryController.php index bafb34a..417e160 100644 --- a/app/Http/Controllers/Admin/Master/CategoryController.php +++ b/app/Http/Controllers/Admin/Master/CategoryController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Master; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\CategoryRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\Category; use App\Services\Admin\Master\CategoryService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/Master/CustomerController.php b/app/Http/Controllers/Admin/Master/CustomerController.php index bdb1576..e660dbd 100644 --- a/app/Http/Controllers/Admin/Master/CustomerController.php +++ b/app/Http/Controllers/Admin/Master/CustomerController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Master; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\CustomerRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\Customer; use App\Services\Admin\Master\CustomerService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/Master/ProductController.php b/app/Http/Controllers/Admin/Master/ProductController.php index f4d89d8..a10f081 100644 --- a/app/Http/Controllers/Admin/Master/ProductController.php +++ b/app/Http/Controllers/Admin/Master/ProductController.php @@ -2,10 +2,9 @@ namespace App\Http\Controllers\Admin\Master; -use App\Enums\ProductStatus; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\ProductRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\Product; use App\Services\Admin\Master\CategoryService; use App\Services\Admin\Master\ProductService; @@ -41,7 +40,7 @@ public function create(): Response public function store(ProductRequest $request): RedirectResponse { return $this->handleAction( - fn() => $this->service->create($request->validated()), + fn () => $this->service->create($request->validated()), 'Produk berhasil ditambahkan.', 'admin.master.products.index', 'admin.master.products.create' @@ -59,7 +58,7 @@ public function edit(Product $product): Response public function update(ProductRequest $request, Product $product): RedirectResponse { return $this->handleAction( - fn() => $this->service->update($product, $request->validated()), + fn () => $this->service->update($product, $request->validated()), 'Produk berhasil diperbarui.', 'admin.master.products.index', 'admin.master.products.edit', @@ -70,7 +69,7 @@ public function update(ProductRequest $request, Product $product): RedirectRespo public function destroy(Product $product): RedirectResponse { return $this->handleAction( - fn() => $this->service->delete($product), + fn () => $this->service->delete($product), 'Produk berhasil dihapus.', 'admin.master.products.index' ); diff --git a/app/Http/Controllers/Admin/Master/SupplierController.php b/app/Http/Controllers/Admin/Master/SupplierController.php index b638c4a..eed93c9 100644 --- a/app/Http/Controllers/Admin/Master/SupplierController.php +++ b/app/Http/Controllers/Admin/Master/SupplierController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Master; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\SupplierRequest; +use App\Http\Requests\PaginatedRequest; use App\Models\Supplier; use App\Services\Admin\Master\SupplierService; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Admin/RoleController.php b/app/Http/Controllers/Admin/RoleController.php index bf57541..11b29ff 100644 --- a/app/Http/Controllers/Admin/RoleController.php +++ b/app/Http/Controllers/Admin/RoleController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\RoleRequest; +use App\Http\Requests\PaginatedRequest; use App\Services\Admin\Settings\RoleService; use Illuminate\Http\RedirectResponse; use Inertia\Inertia; diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 080b518..7303495 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -13,13 +13,16 @@ protected function handleAction(callable $action, string $successMessage, string try { $action(); Inertia::flash('toast', ['type' => 'success', 'message' => $successMessage]); + return to_route($redirectRoute, $parameters); } catch (ValidationException $e) { $firstError = collect($e->errors())->flatten()->first(); Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']); + return to_route($errorRoute ?? $redirectRoute, $parameters); } catch (\Exception $e) { Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]); + return to_route($errorRoute ?? $redirectRoute, $parameters); } } diff --git a/app/Http/Requests/Admin/Master/ProductRequest.php b/app/Http/Requests/Admin/Master/ProductRequest.php index 6abac09..09a2cc6 100644 --- a/app/Http/Requests/Admin/Master/ProductRequest.php +++ b/app/Http/Requests/Admin/Master/ProductRequest.php @@ -65,7 +65,7 @@ public function rules(): array 'variants.*.reject_stock' => ['required', 'integer', 'min:0'], 'variants.*.retail_stock' => ['required', 'integer', 'min:0'], 'variants.*.photo_key' => ['required', 'string', 'max:500'], - 'variants.*.prices' => ['required_if:use_same_price,false', 'nullable', 'array', ...(!$useSamePrice ? ['size:9'] : [])], + 'variants.*.prices' => ['required_if:use_same_price,false', 'nullable', 'array', ...(! $useSamePrice ? ['size:9'] : [])], 'variants.*.prices.*.id' => ['nullable', 'integer'], 'variants.*.prices.*.type' => ['required_if:use_same_price,false', 'nullable', Rule::in(PriceType::values())], 'variants.*.prices.*.price' => ['required_if:use_same_price,false', 'nullable', 'integer', 'min:0'], diff --git a/app/Models/ProductPrice.php b/app/Models/ProductPrice.php index 74ada8d..41e9ee0 100644 --- a/app/Models/ProductPrice.php +++ b/app/Models/ProductPrice.php @@ -11,7 +11,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\SoftDeletes; #[Guarded(['id'])] #[Appends(['type_label'])] diff --git a/app/Models/ProductVariant.php b/app/Models/ProductVariant.php index 862568b..aa6427c 100644 --- a/app/Models/ProductVariant.php +++ b/app/Models/ProductVariant.php @@ -14,7 +14,7 @@ #[Guarded(['id'])] class ProductVariant extends Model implements HasMedia { - use HasFactory, SoftDeletes, InteractsWithMedia; + use HasFactory, InteractsWithMedia, SoftDeletes; public function orderItems(): HasMany { diff --git a/app/Services/Admin/Master/ProductService.php b/app/Services/Admin/Master/ProductService.php index 47d5616..ff70f8e 100644 --- a/app/Services/Admin/Master/ProductService.php +++ b/app/Services/Admin/Master/ProductService.php @@ -2,10 +2,9 @@ namespace App\Services\Admin\Master; -use App\Enums\PriceType; use App\Models\Product; -use App\Models\ProductVariant; use App\Models\ProductPrice; +use App\Models\ProductVariant; use App\Services\S3PresignedService; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; @@ -123,6 +122,7 @@ public function getForEdit(Product $product): array $variants = $product->productVariants->map(function (ProductVariant $variant) { $media = $variant->getMedia('photos')->first(); + return [ 'id' => $variant->id, 'name' => $variant->name, diff --git a/resources/css/app.css b/resources/css/app.css index c0263e7..6b0c801 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,9 +1,9 @@ @import 'tailwindcss'; @import 'tw-animate-css'; -@import "tw-animate-css"; -@import "shadcn/tailwind.css"; -@import "@fontsource-variable/inter"; +@import 'tw-animate-css'; +@import 'shadcn/tailwind.css'; +@import '@fontsource-variable/inter'; @source '../views'; @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; @@ -65,137 +65,74 @@ @theme { } :root { - --background: - oklch(1 0 0); - --foreground: - oklch(0.145 0 0); - --card: - oklch(1 0 0); - --card-foreground: - oklch(0.145 0 0); - --popover: - oklch(1 0 0); - --popover-foreground: - oklch(0.145 0 0); - --primary: - oklch(0.555 0.163 48.998); - --primary-foreground: - oklch(0.987 0.022 95.277); - --secondary: - oklch(0.967 0.001 286.375); - --secondary-foreground: - oklch(0.21 0.006 285.885); - --muted: - oklch(0.97 0 0); - --muted-foreground: - oklch(0.556 0 0); - --accent: - oklch(0.97 0 0); - --accent-foreground: - oklch(0.205 0 0); - --destructive: - oklch(0.577 0.245 27.325); + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.555 0.163 48.998); + --primary-foreground: oklch(0.987 0.022 95.277); + --secondary: oklch(0.967 0.001 286.375); + --secondary-foreground: oklch(0.21 0.006 285.885); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); --destructive-foreground: oklch(0.577 0.245 27.325); - --border: - oklch(0.922 0 0); - --input: - oklch(0.922 0 0); - --ring: - oklch(0.708 0 0); - --chart-1: - oklch(0.879 0.169 91.605); - --chart-2: - oklch(0.769 0.188 70.08); - --chart-3: - oklch(0.666 0.179 58.318); - --chart-4: - oklch(0.555 0.163 48.998); - --chart-5: - oklch(0.473 0.137 46.201); - --radius: - 0.625rem; - --sidebar: - oklch(0.985 0 0); - --sidebar-foreground: - oklch(0.145 0 0); - --sidebar-primary: - oklch(0.666 0.179 58.318); - --sidebar-primary-foreground: - oklch(0.987 0.022 95.277); - --sidebar-accent: - oklch(0.97 0 0); - --sidebar-accent-foreground: - oklch(0.205 0 0); - --sidebar-border: - oklch(0.922 0 0); - --sidebar-ring: - oklch(0.708 0 0); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.879 0.169 91.605); + --chart-2: oklch(0.769 0.188 70.08); + --chart-3: oklch(0.666 0.179 58.318); + --chart-4: oklch(0.555 0.163 48.998); + --chart-5: oklch(0.473 0.137 46.201); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.666 0.179 58.318); + --sidebar-primary-foreground: oklch(0.987 0.022 95.277); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { - --background: - oklch(0.145 0 0); - --foreground: - oklch(0.985 0 0); - --card: - oklch(0.205 0 0); - --card-foreground: - oklch(0.985 0 0); - --popover: - oklch(0.205 0 0); - --popover-foreground: - oklch(0.985 0 0); - --primary: - oklch(0.473 0.137 46.201); - --primary-foreground: - oklch(0.987 0.022 95.277); - --secondary: - oklch(0.274 0.006 286.033); - --secondary-foreground: - oklch(0.985 0 0); - --muted: - oklch(0.269 0 0); - --muted-foreground: - oklch(0.708 0 0); - --accent: - oklch(0.269 0 0); - --accent-foreground: - oklch(0.985 0 0); - --destructive: - oklch(0.704 0.191 22.216); + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.473 0.137 46.201); + --primary-foreground: oklch(0.987 0.022 95.277); + --secondary: oklch(0.274 0.006 286.033); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); --destructive-foreground: oklch(0.637 0.237 25.331); - --border: - oklch(1 0 0 / 10%); - --input: - oklch(1 0 0 / 15%); - --ring: - oklch(0.556 0 0); - --chart-1: - oklch(0.879 0.169 91.605); - --chart-2: - oklch(0.769 0.188 70.08); - --chart-3: - oklch(0.666 0.179 58.318); - --chart-4: - oklch(0.555 0.163 48.998); - --chart-5: - oklch(0.473 0.137 46.201); - --sidebar: - oklch(0.205 0 0); - --sidebar-foreground: - oklch(0.985 0 0); - --sidebar-primary: - oklch(0.769 0.188 70.08); - --sidebar-primary-foreground: - oklch(0.279 0.077 45.635); - --sidebar-accent: - oklch(0.269 0 0); - --sidebar-accent-foreground: - oklch(0.985 0 0); - --sidebar-border: - oklch(1 0 0 / 10%); - --sidebar-ring: - oklch(0.556 0 0); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.879 0.169 91.605); + --chart-2: oklch(0.769 0.188 70.08); + --chart-3: oklch(0.666 0.179 58.318); + --chart-4: oklch(0.555 0.163 48.998); + --chart-5: oklch(0.473 0.137 46.201); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.769 0.188 70.08); + --sidebar-primary-foreground: oklch(0.279 0.077 45.635); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } @layer base { @@ -206,90 +143,50 @@ @layer base { body { @apply bg-background text-foreground; } - html { - @apply font-sans; + html { + @apply font-sans; } } @theme inline { - --font-heading: - var(--font-sans); - --font-sans: - 'Inter Variable', sans-serif; - --color-sidebar-ring: - var(--sidebar-ring); - --color-sidebar-border: - var(--sidebar-border); - --color-sidebar-accent-foreground: - var(--sidebar-accent-foreground); - --color-sidebar-accent: - var(--sidebar-accent); - --color-sidebar-primary-foreground: - var(--sidebar-primary-foreground); - --color-sidebar-primary: - var(--sidebar-primary); - --color-sidebar-foreground: - var(--sidebar-foreground); - --color-sidebar: - var(--sidebar); - --color-chart-5: - var(--chart-5); - --color-chart-4: - var(--chart-4); - --color-chart-3: - var(--chart-3); - --color-chart-2: - var(--chart-2); - --color-chart-1: - var(--chart-1); - --color-ring: - var(--ring); - --color-input: - var(--input); - --color-border: - var(--border); - --color-destructive: - var(--destructive); - --color-accent-foreground: - var(--accent-foreground); - --color-accent: - var(--accent); - --color-muted-foreground: - var(--muted-foreground); - --color-muted: - var(--muted); - --color-secondary-foreground: - var(--secondary-foreground); - --color-secondary: - var(--secondary); - --color-primary-foreground: - var(--primary-foreground); - --color-primary: - var(--primary); - --color-popover-foreground: - var(--popover-foreground); - --color-popover: - var(--popover); - --color-card-foreground: - var(--card-foreground); - --color-card: - var(--card); - --color-foreground: - var(--foreground); - --color-background: - var(--background); - --radius-sm: - calc(var(--radius) * 0.6); - --radius-md: - calc(var(--radius) * 0.8); - --radius-lg: - var(--radius); - --radius-xl: - calc(var(--radius) * 1.4); - --radius-2xl: - calc(var(--radius) * 1.8); - --radius-3xl: - calc(var(--radius) * 2.2); - --radius-4xl: - calc(var(--radius) * 2.6); -} \ No newline at end of file + --font-heading: var(--font-sans); + --font-sans: 'Inter Variable', sans-serif; + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --color-foreground: var(--foreground); + --color-background: var(--background); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); +} diff --git a/resources/js/components/app-logo-icon.tsx b/resources/js/components/app-logo-icon.tsx index 4c42534..f9fe683 100644 --- a/resources/js/components/app-logo-icon.tsx +++ b/resources/js/components/app-logo-icon.tsx @@ -2,6 +2,8 @@ import type { ImgHTMLAttributes } from 'react'; import logo from '../../../public/assets/logo.png'; -export default function AppLogoIcon(props: ImgHTMLAttributes) { +export default function AppLogoIcon( + props: ImgHTMLAttributes, +) { return Logo; } diff --git a/resources/js/components/app-sidebar.tsx b/resources/js/components/app-sidebar.tsx index 9cf1a94..6b97053 100644 --- a/resources/js/components/app-sidebar.tsx +++ b/resources/js/components/app-sidebar.tsx @@ -106,7 +106,10 @@ function MenuGroup({ label, items }: { label: string; items: NavMenuItem[] }) { {items.map((item) => ( - + {item.title} @@ -151,7 +154,11 @@ export function AppSidebar() { - + {dasborItem.title} @@ -164,7 +171,10 @@ export function AppSidebar() { - + {analisaItem.title} diff --git a/resources/js/components/camera-capture.tsx b/resources/js/components/camera-capture.tsx index 636e26c..5857df5 100644 --- a/resources/js/components/camera-capture.tsx +++ b/resources/js/components/camera-capture.tsx @@ -25,7 +25,9 @@ export function CameraCapture({ onCapture, onClose }: CameraCaptureProps) { } setError(null); } catch { - setError('Tidak dapat mengakses kamera. Pastikan izin kamera diberikan.'); + setError( + 'Tidak dapat mengakses kamera. Pastikan izin kamera diberikan.', + ); } }, []); @@ -81,14 +83,24 @@ export function CameraCapture({ onCapture, onClose }: CameraCaptureProps) { {error ? (
-

{error}

+

+ {error} +

) : capturedImage ? (
- Captured + Captured
- diff --git a/resources/js/components/data-table.tsx b/resources/js/components/data-table.tsx index 76c73f4..f2b7e2b 100644 --- a/resources/js/components/data-table.tsx +++ b/resources/js/components/data-table.tsx @@ -4,7 +4,7 @@ import { KeyboardSensor, PointerSensor, useSensor, - useSensors + useSensors, } from '@dnd-kit/core'; import { SortableContext, @@ -17,9 +17,15 @@ import { flexRender, getCoreRowModel, getExpandedRowModel, - useReactTable + useReactTable, } from '@tanstack/react-table'; -import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, GripVertical } from 'lucide-react'; +import { + ChevronLeft, + ChevronRight, + ChevronsLeft, + ChevronsRight, + GripVertical, +} from 'lucide-react'; import * as React from 'react'; import { Button } from '@/components/ui/button'; @@ -167,8 +173,8 @@ export function DataTable({ }: DataTableProps) { const [expanded, setExpanded] = React.useState(() => { if (!defaultExpanded || !data.length) { -return {}; -} + return {}; + } const initial: Record = {}; data.forEach((item, index) => { @@ -194,17 +200,17 @@ return {}; const visibleColumns = isSortable ? [ - { - id: 'drag', - header: '', - cell: () => , - meta: { - className: 'w-[40px]', - headerClassName: 'w-[40px]', - }, - } as ColumnDef, - ...columns, - ] + { + id: 'drag', + header: '', + cell: () => , + meta: { + className: 'w-[40px]', + headerClassName: 'w-[40px]', + }, + } as ColumnDef, + ...columns, + ] : columns; const sensors = useSensors( @@ -261,8 +267,8 @@ return {}; function handleSort(columnId: string) { if (!onSortChange) { -return; -} + return; + } const newDirection = currentSort?.column === columnId && currentSort?.direction === 'asc' @@ -282,25 +288,31 @@ return; handleSearchChange(event.target.value)} + onChange={(event) => + handleSearchChange(event.target.value) + } className="max-w-sm" /> )} {toolbar} -
+
{isServerMode && onPerPageChange && ( )} @@ -320,18 +332,18 @@ return; ( header.column.columnDef .meta as { - headerClassName?: string; - } + headerClassName?: string; + } )?.headerClassName } > {header.isPlaceholder ? null : flexRender( - header.column.columnDef - .header, - header.getContext(), - )} + header.column.columnDef + .header, + header.getContext(), + )} ))} @@ -374,8 +386,8 @@ return; .column .columnDef .meta as { - className?: string; - } + className?: string; + } ) ?.className } @@ -394,55 +406,58 @@ return; ) : ( - table - .getRowModel() - .rows.map((row) => ( - - - {row - .getVisibleCells() - .map((cell) => ( - - {flexRender( + table.getRowModel().rows.map((row) => ( + + + {row + .getVisibleCells() + .map((cell) => ( + - ))} - - {renderSubRow && row.getIsExpanded() && ( + .meta as { + className?: string; + } + )?.className + } + > + {flexRender( + cell.column + .columnDef + .cell, + cell.getContext(), + )} + + ))} + + {renderSubRow && + row.getIsExpanded() && (
- {renderSubRow(row, localSearch)} + {renderSubRow( + row, + localSearch, + )}
)} -
- )) + + )) ) ) : ( @@ -530,7 +545,9 @@ return; - + diff --git a/resources/js/components/pwa-update-toast.tsx b/resources/js/components/pwa-update-toast.tsx index 904ca8e..a36199b 100644 --- a/resources/js/components/pwa-update-toast.tsx +++ b/resources/js/components/pwa-update-toast.tsx @@ -12,7 +12,8 @@ export function PWAUpdateToast() { const handleUpdateAvailable = () => { toast.info('Update tersedia!', { - description: 'Versi baru aplikasi telah tersedia. Klik untuk memperbarui.', + description: + 'Versi baru aplikasi telah tersedia. Klik untuk memperbarui.', duration: Infinity, action: { label: 'Update', @@ -28,7 +29,10 @@ export function PWAUpdateToast() { return () => { window.removeEventListener('sw-offline-ready', handleOfflineReady); - window.removeEventListener('sw-update-available', handleUpdateAvailable); + window.removeEventListener( + 'sw-update-available', + handleUpdateAvailable, + ); }; }, []); diff --git a/resources/js/components/rupiah-input.tsx b/resources/js/components/rupiah-input.tsx index 79236db..158c5fb 100644 --- a/resources/js/components/rupiah-input.tsx +++ b/resources/js/components/rupiah-input.tsx @@ -40,7 +40,9 @@ export function RupiahInput({ className, }: RupiahInputProps) { const isControlled = value !== undefined; - const [displayValue, setDisplayValue] = useState(formatRupiah(isControlled ? value : defaultValue)); + const [displayValue, setDisplayValue] = useState( + formatRupiah(isControlled ? value : defaultValue), + ); const lastValidRef = useRef(isControlled ? value : defaultValue); if (isControlled) { diff --git a/resources/js/hooks/use-file-upload.ts b/resources/js/hooks/use-file-upload.ts index 448ff6c..5835587 100644 --- a/resources/js/hooks/use-file-upload.ts +++ b/resources/js/hooks/use-file-upload.ts @@ -18,27 +18,54 @@ export function useFileUpload() { preview: null, }); - const upload = useCallback(async (file: File, folder?: string): Promise => { - setState({ uploading: true, progress: 0, error: null, key: null, preview: null }); + const upload = useCallback( + async (file: File, folder?: string): Promise => { + setState({ + uploading: true, + progress: 0, + error: null, + key: null, + preview: null, + }); - try { - const preview = URL.createObjectURL(file); - setState((prev) => ({ ...prev, preview, progress: 30 })); + try { + const preview = URL.createObjectURL(file); + setState((prev) => ({ ...prev, preview, progress: 30 })); - const key = await uploadFile(file, folder); - setState((prev) => ({ ...prev, key, uploading: false, progress: 100 })); + const key = await uploadFile(file, folder); + setState((prev) => ({ + ...prev, + key, + uploading: false, + progress: 100, + })); - return key; - } catch (err) { - const message = err instanceof UploadError ? err.message : 'Terjadi kesalahan saat mengunggah file.'; - setState((prev) => ({ ...prev, error: message, uploading: false })); + return key; + } catch (err) { + const message = + err instanceof UploadError + ? err.message + : 'Terjadi kesalahan saat mengunggah file.'; + setState((prev) => ({ + ...prev, + error: message, + uploading: false, + })); - return null; - } - }, []); + return null; + } + }, + [], + ); const reset = useCallback(() => { - setState({ uploading: false, progress: 0, error: null, key: null, preview: null }); + setState({ + uploading: false, + progress: 0, + error: null, + key: null, + preview: null, + }); }, []); const setKey = useCallback((key: string | null) => { diff --git a/resources/js/hooks/use-initials.tsx b/resources/js/hooks/use-initials.tsx index 701886d..7a7b8c3 100644 --- a/resources/js/hooks/use-initials.tsx +++ b/resources/js/hooks/use-initials.tsx @@ -9,8 +9,8 @@ function getInitial(name: string): string { export function useInitials(): GetInitialsFn { return useCallback((fullName: string): string => { if (!fullName) { -return ''; -} + return ''; + } const names = fullName.trim().split(/\s+/u).filter(Boolean); diff --git a/resources/js/hooks/use-mobile.ts b/resources/js/hooks/use-mobile.ts index 77ab35a..3cb95b5 100644 --- a/resources/js/hooks/use-mobile.ts +++ b/resources/js/hooks/use-mobile.ts @@ -1,20 +1,24 @@ -import * as React from "react" +import * as React from 'react'; -const MOBILE_BREAKPOINT = 768 +const MOBILE_BREAKPOINT = 768; export function useIsMobile() { - const [isMobile, setIsMobile] = React.useState(undefined) + const [isMobile, setIsMobile] = React.useState( + undefined, + ); - React.useEffect(() => { - const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) - const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - } - mql.addEventListener("change", onChange) - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) + React.useEffect(() => { + const mql = window.matchMedia( + `(max-width: ${MOBILE_BREAKPOINT - 1}px)`, + ); + const onChange = () => { + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + }; + mql.addEventListener('change', onChange); + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - return () => mql.removeEventListener("change", onChange) - }, []) + return () => mql.removeEventListener('change', onChange); + }, []); - return !!isMobile + return !!isMobile; } diff --git a/resources/js/layouts/app/app-sidebar-layout.tsx b/resources/js/layouts/app/app-sidebar-layout.tsx index cfe43ab..6b12216 100644 --- a/resources/js/layouts/app/app-sidebar-layout.tsx +++ b/resources/js/layouts/app/app-sidebar-layout.tsx @@ -11,7 +11,10 @@ export default function AppSidebarLayout({ return ( - + {children} diff --git a/resources/js/layouts/auth/auth-card-layout.tsx b/resources/js/layouts/auth/auth-card-layout.tsx index 9bc88bb..6e9472a 100644 --- a/resources/js/layouts/auth/auth-card-layout.tsx +++ b/resources/js/layouts/auth/auth-card-layout.tsx @@ -26,7 +26,11 @@ export default function AuthCardLayout({ className="flex items-center gap-2 self-center font-medium" >
- Logo + Logo
diff --git a/resources/js/layouts/settings/layout.tsx b/resources/js/layouts/settings/layout.tsx index aaa93ae..2025891 100644 --- a/resources/js/layouts/settings/layout.tsx +++ b/resources/js/layouts/settings/layout.tsx @@ -73,9 +73,7 @@ export default function SettingsLayout({ children }: PropsWithChildren) { -
- {children} -
+
{children}
); diff --git a/resources/js/lib/upload.ts b/resources/js/lib/upload.ts index 2d54497..eaab328 100644 --- a/resources/js/lib/upload.ts +++ b/resources/js/lib/upload.ts @@ -15,7 +15,12 @@ export class UploadError extends Error { } function getSessionCookie(): string { - return document.cookie.split('; ').find((c) => c.startsWith('XSRF-TOKEN='))?.split('=')[1] ?? ''; + return ( + document.cookie + .split('; ') + .find((c) => c.startsWith('XSRF-TOKEN=')) + ?.split('=')[1] ?? '' + ); } export async function requestPresignedUrl( @@ -31,7 +36,11 @@ export async function requestPresignedUrl( 'X-Requested-With': 'XMLHttpRequest', 'X-XSRF-TOKEN': decodeURIComponent(getSessionCookie()), }, - body: JSON.stringify({ file_name: fileName, mime_type: mimeType, folder }), + body: JSON.stringify({ + file_name: fileName, + mime_type: mimeType, + folder, + }), }); if (!response.ok) { @@ -59,14 +68,20 @@ export async function uploadToS3(uploadUrl: string, file: File): Promise { export async function uploadFile(file: File, folder?: string): Promise { if (!ALLOWED_TYPES.includes(file.type)) { - throw new UploadError('Tipe file tidak didukung. Hanya JPG, PNG, WebP, dan GIF yang diizinkan.'); + throw new UploadError( + 'Tipe file tidak didukung. Hanya JPG, PNG, WebP, dan GIF yang diizinkan.', + ); } if (file.size > MAX_FILE_SIZE) { throw new UploadError('Ukuran file melebihi batas 10MB.'); } - const { upload_url, key } = await requestPresignedUrl(file.name, file.type, folder); + const { upload_url, key } = await requestPresignedUrl( + file.name, + file.type, + folder, + ); await uploadToS3(upload_url, file); return key; diff --git a/resources/js/pages/admin/finance/cash-account/columns.tsx b/resources/js/pages/admin/finance/cash-account/columns.tsx index 598d187..e68513a 100644 --- a/resources/js/pages/admin/finance/cash-account/columns.tsx +++ b/resources/js/pages/admin/finance/cash-account/columns.tsx @@ -30,9 +30,7 @@ export function createCashAccountColumns( id: 'no', header: () => No, cell: ({ row }) => ( - - {row.index + 1} - + {row.index + 1} ), meta: { className: 'w-[50px] text-center', @@ -46,9 +44,7 @@ export function createCashAccountColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Nama @@ -68,9 +64,7 @@ export function createCashAccountColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Saldo @@ -101,16 +95,12 @@ export function createCashAccountColumns( - - Edit - + Edit diff --git a/resources/js/pages/admin/finance/cash-account/index.tsx b/resources/js/pages/admin/finance/cash-account/index.tsx index 7e943ac..6905755 100644 --- a/resources/js/pages/admin/finance/cash-account/index.tsx +++ b/resources/js/pages/admin/finance/cash-account/index.tsx @@ -1,5 +1,11 @@ import { Form, Head, router } from '@inertiajs/react'; -import { ArrowDownToLine, ArrowUpFromLine, Filter, Wallet, X } from 'lucide-react'; +import { + ArrowDownToLine, + ArrowUpFromLine, + Filter, + Wallet, + X, +} from 'lucide-react'; import { useCallback, useState } from 'react'; import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; @@ -18,11 +24,28 @@ import { } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; import { formatCurrency } from '@/lib/utils'; -import { index as cashAccountIndex, deposit, withdrawal } from '@/routes/admin/finance/cash-accounts'; -import { update as updateTransaction, destroy as destroyTransaction } from '@/routes/admin/finance/cash-accounts/transactions'; +import { + index as cashAccountIndex, + deposit, + withdrawal, +} from '@/routes/admin/finance/cash-accounts'; +import { + update as updateTransaction, + destroy as destroyTransaction, +} from '@/routes/admin/finance/cash-accounts/transactions'; import { createTransactionColumns } from './transaction-columns'; import type { CashTransaction } from './transaction-columns'; @@ -46,27 +69,47 @@ type Props = { }; }; -export default function CashAccountIndex({ cashAccount, transactions, filters }: Props) { +export default function CashAccountIndex({ + cashAccount, + transactions, + filters, +}: Props) { const [depositOpen, setDepositOpen] = useState(false); const [withdrawalOpen, setWithdrawalOpen] = useState(false); const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); const [filterOpen, setFilterOpen] = useState(false); - const [depositReceiptKey, setDepositReceiptKey] = useState(null); + const [depositReceiptKey, setDepositReceiptKey] = useState( + null, + ); const [depositUploading, setDepositUploading] = useState(false); - const [depositFileMeta, setDepositFileMeta] = useState<{ size: number; type: string } | null>(null); + const [depositFileMeta, setDepositFileMeta] = useState<{ + size: number; + type: string; + } | null>(null); - const [withdrawalReceiptKey, setWithdrawalReceiptKey] = useState(null); + const [withdrawalReceiptKey, setWithdrawalReceiptKey] = useState< + string | null + >(null); const [withdrawalUploading, setWithdrawalUploading] = useState(false); - const [withdrawalFileMeta, setWithdrawalFileMeta] = useState<{ size: number; type: string } | null>(null); + const [withdrawalFileMeta, setWithdrawalFileMeta] = useState<{ + size: number; + type: string; + } | null>(null); const [editReceiptKey, setEditReceiptKey] = useState(null); const [editUploading, setEditUploading] = useState(false); - const [editFileMeta, setEditFileMeta] = useState<{ size: number; type: string } | null>(null); + const [editFileMeta, setEditFileMeta] = useState<{ + size: number; + type: string; + } | null>(null); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: transactions.current_page, @@ -86,24 +129,32 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: newFilters[key as keyof typeof newFilters] = value; } - router.get(cashAccountIndex(), { - ...newFilters, - page: 1, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + cashAccountIndex(), + { + ...newFilters, + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function clearFilters() { - router.get(cashAccountIndex(), { - page: 1, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + cashAccountIndex(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); setFilterOpen(false); } @@ -118,49 +169,68 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: } function handlePageChange(page: number) { - router.get(cashAccountIndex(), { - ...filters, - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + cashAccountIndex(), + { + ...filters, + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function handlePerPageChange(perPage: number) { - router.get(cashAccountIndex(), { - ...filters, - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + cashAccountIndex(), + { + ...filters, + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(cashAccountIndex(), { - ...filters, - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); - }, [pagination.per_page, sort, filters]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + cashAccountIndex(), + { + ...filters, + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); + }, + [pagination.per_page, sort, filters], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(cashAccountIndex(), { - ...filters, - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { preserveState: true, replace: true }); + router.get( + cashAccountIndex(), + { + ...filters, + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { preserveState: true, replace: true }, + ); } const columns = createTransactionColumns({ @@ -207,7 +277,9 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }:
@@ -238,11 +316,17 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }:
- - @@ -279,20 +363,27 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: toolbar={filterToolbar} /> - { - setDepositOpen(open); + { + setDepositOpen(open); - if (!open) { - setDepositReceiptKey(null); - setDepositFileMeta(null); - } - }}> - -
{ - setDepositOpen(false); + if (!open) { setDepositReceiptKey(null); setDepositFileMeta(null); - }}> + } + }} + > + + { + setDepositOpen(false); + setDepositReceiptKey(null); + setDepositFileMeta(null); + }} + > {({ errors, processing }) => ( <> @@ -301,46 +392,95 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }:
- - + +
- +
- - - - + + + + - +
- - @@ -349,20 +489,27 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }:
- { - setWithdrawalOpen(open); + { + setWithdrawalOpen(open); - if (!open) { - setWithdrawalReceiptKey(null); - setWithdrawalFileMeta(null); - } - }}> - - { - setWithdrawalOpen(false); + if (!open) { setWithdrawalReceiptKey(null); setWithdrawalFileMeta(null); - }}> + } + }} + > + + { + setWithdrawalOpen(false); + setWithdrawalReceiptKey(null); + setWithdrawalFileMeta(null); + }} + > {({ errors, processing }) => ( <> @@ -371,46 +518,104 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }:
- - + +
- +
- - - - + + + + + -
- - @@ -431,61 +636,121 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: > {editing && ( - { - setEditing(null); - setEditReceiptKey(null); - setEditFileMeta(null); - }}> + { + setEditing(null); + setEditReceiptKey(null); + setEditFileMeta(null); + }} + > {({ errors, processing }) => ( <> - Edit Transaksi + + Edit Transaksi +
- - + +
+ -
- - - - + + + + - +
- - diff --git a/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx b/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx index eda194f..f473b80 100644 --- a/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx +++ b/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx @@ -33,14 +33,18 @@ export type CashTransaction = { function formatDate(dateString: string): string { const date = new Date(dateString); - return date.toLocaleDateString('id-ID', { - day: '2-digit', - month: 'short', - year: 'numeric', - }) + ' ' + date.toLocaleTimeString('id-ID', { - hour: '2-digit', - minute: '2-digit', - }); + return ( + date.toLocaleDateString('id-ID', { + day: '2-digit', + month: 'short', + year: 'numeric', + }) + + ' ' + + date.toLocaleTimeString('id-ID', { + hour: '2-digit', + minute: '2-digit', + }) + ); } function getTypeLabel(type: string): string { @@ -105,9 +109,7 @@ export function createTransactionColumns( id: 'no', header: () => No, cell: ({ row }) => ( - - {row.index + 1} - + {row.index + 1} ), meta: { className: 'w-[50px] text-center', @@ -121,9 +123,7 @@ export function createTransactionColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Tanggal @@ -142,8 +142,14 @@ export function createTransactionColumns( return (
- {getTypeLabel(transaction.type)} - {getReferenceLabel(transaction.reference?.type ?? '')} + + {getTypeLabel(transaction.type)} + + + {getReferenceLabel( + transaction.reference?.type ?? '', + )} +
); }, @@ -155,9 +161,7 @@ export function createTransactionColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Jumlah @@ -169,8 +173,15 @@ export function createTransactionColumns( const isDeposit = transaction.type === 'deposit'; return ( - - {isDeposit ? '+' : '-'} {formatCurrency(row.getValue('amount') as number)} + + {isDeposit ? '+' : '-'}{' '} + {formatCurrency(row.getValue('amount') as number)} ); }, @@ -182,9 +193,7 @@ export function createTransactionColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Saldo Setelah @@ -192,14 +201,18 @@ export function createTransactionColumns( ), cell: ({ row }) => ( - {formatCurrency(row.getValue('balance_after') as number)} + + {formatCurrency(row.getValue('balance_after') as number)} + ), }, { accessorKey: 'description', header: () => Keterangan, cell: ({ row }) => ( - {row.getValue('description') as string} + + {row.getValue('description') as string} + ), }, { @@ -212,7 +225,12 @@ export function createTransactionColumns( return -; } - return ; + return ( + + ); }, }, { @@ -233,7 +251,9 @@ export function createTransactionColumns( }, cell: ({ row }) => { const transaction = row.original; - const canEdit = transaction.type === 'deposit' || transaction.type === 'withdrawal'; + const canEdit = + transaction.type === 'deposit' || + transaction.type === 'withdrawal'; if (!canEdit) { return -; @@ -252,9 +272,7 @@ export function createTransactionColumns( - - Edit - + Edit @@ -262,7 +280,9 @@ export function createTransactionColumns( diff --git a/resources/js/pages/admin/finance/employee-advance/columns.tsx b/resources/js/pages/admin/finance/employee-advance/columns.tsx index 2357ad1..f2f214d 100644 --- a/resources/js/pages/admin/finance/employee-advance/columns.tsx +++ b/resources/js/pages/admin/finance/employee-advance/columns.tsx @@ -1,5 +1,11 @@ import type { ColumnDef } from '@tanstack/react-table'; -import { ArrowUpDown, CheckCircle, CircleDollarSign, Pencil, Trash2 } from 'lucide-react'; +import { + ArrowUpDown, + CheckCircle, + CircleDollarSign, + Pencil, + Trash2, +} from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { @@ -30,14 +36,18 @@ export type EmployeeAdvance = { function formatDate(dateString: string): string { const date = new Date(dateString); - return date.toLocaleDateString('id-ID', { - day: '2-digit', - month: 'short', - year: 'numeric', - }) + ' ' + date.toLocaleTimeString('id-ID', { - hour: '2-digit', - minute: '2-digit', - }); + return ( + date.toLocaleDateString('id-ID', { + day: '2-digit', + month: 'short', + year: 'numeric', + }) + + ' ' + + date.toLocaleTimeString('id-ID', { + hour: '2-digit', + minute: '2-digit', + }) + ); } function formatShortDate(dateString: string): string { @@ -100,9 +110,7 @@ export function createEmployeeAdvanceColumns( id: 'no', header: () => No, cell: ({ row }) => ( - - {row.index + 1} - + {row.index + 1} ), meta: { className: 'w-[50px] text-center', @@ -116,9 +124,7 @@ export function createEmployeeAdvanceColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Tanggal @@ -135,7 +141,11 @@ export function createEmployeeAdvanceColumns( cell: ({ row }) => { const employee = row.original.employee; - return {employee?.user?.user_profile?.full_name ?? '-'}; + return ( + + {employee?.user?.user_profile?.full_name ?? '-'} + + ); }, }, { @@ -145,9 +155,7 @@ export function createEmployeeAdvanceColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Jumlah @@ -155,7 +163,7 @@ export function createEmployeeAdvanceColumns( ), cell: ({ row }) => ( - + - {formatCurrency(row.getValue('amount') as number)} ), @@ -164,7 +172,9 @@ export function createEmployeeAdvanceColumns( accessorKey: 'description', header: () => Keterangan, cell: ({ row }) => ( - {row.getValue('description') as string} + + {row.getValue('description') as string} + ), }, { @@ -174,9 +184,7 @@ export function createEmployeeAdvanceColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Jatuh Tempo @@ -184,7 +192,9 @@ export function createEmployeeAdvanceColumns( ), cell: ({ row }) => ( - {formatShortDate(row.getValue('due_date') as string)} + + {formatShortDate(row.getValue('due_date') as string)} + ), }, { @@ -257,9 +267,7 @@ export function createEmployeeAdvanceColumns( - - Edit - + Edit diff --git a/resources/js/pages/admin/finance/employee-advance/index.tsx b/resources/js/pages/admin/finance/employee-advance/index.tsx index 5ea28a7..7ed7591 100644 --- a/resources/js/pages/admin/finance/employee-advance/index.tsx +++ b/resources/js/pages/admin/finance/employee-advance/index.tsx @@ -17,7 +17,14 @@ import { } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { destroy, index as employeeAdvanceIndex, store, update, approve, pay } from '@/routes/admin/finance/employee-advances'; +import { + destroy, + index as employeeAdvanceIndex, + store, + update, + approve, + pay, +} from '@/routes/admin/finance/employee-advances'; import { createEmployeeAdvanceColumns } from './columns'; import type { EmployeeAdvance } from './columns'; @@ -38,9 +45,14 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { const [approving, setApproving] = useState(null); const [paying, setPaying] = useState(null); const [dueDate, setDueDate] = useState(undefined); - const [editingDueDate, setEditingDueDate] = useState(undefined); + const [editingDueDate, setEditingDueDate] = useState( + undefined, + ); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: employeeAdvances.current_page, @@ -72,9 +84,13 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { return; } - router.post(approve(approving.id), {}, { - onSuccess: () => setApproving(null), - }); + router.post( + approve(approving.id), + {}, + { + onSuccess: () => setApproving(null), + }, + ); } function handlePay() { @@ -82,51 +98,74 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { return; } - router.post(pay(paying.id), {}, { - onSuccess: () => setPaying(null), - }); + router.post( + pay(paying.id), + {}, + { + onSuccess: () => setPaying(null), + }, + ); } function handlePageChange(page: number) { - router.get(employeeAdvanceIndex.url(), { - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + employeeAdvanceIndex.url(), + { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function handlePerPageChange(perPage: number) { - router.get(employeeAdvanceIndex.url(), { - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + employeeAdvanceIndex.url(), + { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(employeeAdvanceIndex.url(), { - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); - }, [pagination.per_page, sort]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + employeeAdvanceIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); + }, + [pagination.per_page, sort], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(employeeAdvanceIndex.url(), { - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { preserveState: true, replace: true }); + router.get( + employeeAdvanceIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { preserveState: true, replace: true }, + ); } const columns = createEmployeeAdvanceColumns({ @@ -147,13 +186,16 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { Kasbon
- { - setCreateOpen(open); + { + setCreateOpen(open); - if (!open) { - setDueDate(undefined); - } - }}> + if (!open) { + setDueDate(undefined); + } + }} + > - setCreateOpen(false)}> + setCreateOpen(false)} + > {({ errors, processing }) => { - return ( <> - Tambah Kasbon + + Tambah Kasbon +
- - + +
- +
- + - +
), cell: ({ row }) => ( - + - {formatCurrency(row.getValue('amount') as number)} ), @@ -176,16 +181,12 @@ export function createExpenseColumns( - - Edit - + Edit diff --git a/resources/js/pages/admin/finance/expense/index.tsx b/resources/js/pages/admin/finance/expense/index.tsx index c79bcbf..2095da0 100644 --- a/resources/js/pages/admin/finance/expense/index.tsx +++ b/resources/js/pages/admin/finance/expense/index.tsx @@ -17,7 +17,12 @@ import { } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { destroy, index as expenseIndex, store, update } from '@/routes/admin/finance/expenses'; +import { + destroy, + index as expenseIndex, + store, + update, +} from '@/routes/admin/finance/expenses'; import { createExpenseColumns } from './columns'; import type { Expense } from './columns'; @@ -35,14 +40,25 @@ export default function ExpenseIndex({ expenses }: Props) { const [createOpen, setCreateOpen] = useState(false); const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); - const [createReceiptKey, setCreateReceiptKey] = useState(null); + const [createReceiptKey, setCreateReceiptKey] = useState( + null, + ); const [editReceiptKey, setEditReceiptKey] = useState(null); const [createUploading, setCreateUploading] = useState(false); const [editUploading, setEditUploading] = useState(false); - const [createFileMeta, setCreateFileMeta] = useState<{ size: number; type: string } | null>(null); - const [editFileMeta, setEditFileMeta] = useState<{ size: number; type: string } | null>(null); + const [createFileMeta, setCreateFileMeta] = useState<{ + size: number; + type: string; + } | null>(null); + const [editFileMeta, setEditFileMeta] = useState<{ + size: number; + type: string; + } | null>(null); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: expenses.current_page, @@ -52,45 +68,64 @@ export default function ExpenseIndex({ expenses }: Props) { }; function handlePageChange(page: number) { - router.get(expenseIndex.url(), { - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + expenseIndex.url(), + { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function handlePerPageChange(perPage: number) { - router.get(expenseIndex.url(), { - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + expenseIndex.url(), + { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(expenseIndex.url(), { - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); - }, [pagination.per_page, sort]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + expenseIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); + }, + [pagination.per_page, sort], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(expenseIndex.url(), { - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { preserveState: true, replace: true }); + router.get( + expenseIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { preserveState: true, replace: true }, + ); } function handleDelete() { @@ -122,14 +157,17 @@ export default function ExpenseIndex({ expenses }: Props) { Pengeluaran - { - setCreateOpen(open); + { + setCreateOpen(open); - if (!open) { - setCreateReceiptKey(null); - setCreateFileMeta(null); - } - }}> + if (!open) { + setCreateReceiptKey(null); + setCreateFileMeta(null); + } + }} + > - { - setCreateOpen(false); - setCreateReceiptKey(null); - setCreateFileMeta(null); - }}> + { + setCreateOpen(false); + setCreateReceiptKey(null); + setCreateFileMeta(null); + }} + > {({ errors, processing }) => { - return ( <> - Tambah Pengeluaran + + Tambah Pengeluaran +
- - + +
- +
- - - - + + + + + -
@@ -240,48 +339,114 @@ export default function ExpenseIndex({ expenses }: Props) { > {editing && ( - { - setEditing(null); - setEditReceiptKey(null); - setEditFileMeta(null); - }}> + { + setEditing(null); + setEditReceiptKey(null); + setEditFileMeta(null); + }} + > {({ errors, processing }) => { - return ( <> - Edit Pengeluaran + + Edit Pengeluaran +
- - - + + +
- + + -
- - - - + + + + + -
@@ -296,13 +461,16 @@ export default function ExpenseIndex({ expenses }: Props) { diff --git a/resources/js/pages/admin/finance/payroll-period/columns.tsx b/resources/js/pages/admin/finance/payroll-period/columns.tsx index e6e5715..d584529 100644 --- a/resources/js/pages/admin/finance/payroll-period/columns.tsx +++ b/resources/js/pages/admin/finance/payroll-period/columns.tsx @@ -27,8 +27,19 @@ export type PayrollPeriod = { }; const MONTH_NAMES = [ - '', 'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', - 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember', + '', + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember', ]; function formatPeriod(period: PayrollPeriod): string { @@ -72,9 +83,7 @@ export function createPayrollPeriodColumns( id: 'no', header: () => No, cell: ({ row }) => ( - - {row.index + 1} - + {row.index + 1} ), meta: { className: 'w-[50px] text-center', @@ -88,9 +97,7 @@ export function createPayrollPeriodColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Periode @@ -98,14 +105,18 @@ export function createPayrollPeriodColumns( ), cell: ({ row }) => ( - {formatPeriod(row.original)} + + {formatPeriod(row.original)} + ), }, { accessorKey: 'payrolls_count', header: () => Jumlah Karyawan, cell: ({ row }) => ( - {row.getValue('payrolls_count') as number} + + {row.getValue('payrolls_count') as number} + ), }, { @@ -115,9 +126,7 @@ export function createPayrollPeriodColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Total Gaji @@ -126,7 +135,10 @@ export function createPayrollPeriodColumns( ), cell: ({ row }) => ( - {formatCurrency((row.getValue('payrolls_sum_total_amount') as number) ?? 0)} + {formatCurrency( + (row.getValue('payrolls_sum_total_amount') as number) ?? + 0, + )} ), }, @@ -137,9 +149,7 @@ export function createPayrollPeriodColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Bonus @@ -147,11 +157,19 @@ export function createPayrollPeriodColumns( ), cell: ({ row }) => { - const value = (row.getValue('payrolls_sum_bonus_amount') as number) ?? 0; + const value = + (row.getValue('payrolls_sum_bonus_amount') as number) ?? 0; return ( - 0 ? 'text-green-600 font-medium' : 'text-muted-foreground'}> - {value > 0 ? '+ ' : ''}{formatCurrency(value)} + 0 + ? 'font-medium text-green-600' + : 'text-muted-foreground' + } + > + {value > 0 ? '+ ' : ''} + {formatCurrency(value)} ); }, @@ -163,9 +181,7 @@ export function createPayrollPeriodColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Potongan @@ -173,11 +189,20 @@ export function createPayrollPeriodColumns( ), cell: ({ row }) => { - const value = (row.getValue('payrolls_sum_deduction_amount') as number) ?? 0; + const value = + (row.getValue('payrolls_sum_deduction_amount') as number) ?? + 0; return ( - 0 ? 'text-red-600 font-medium' : 'text-muted-foreground'}> - {value > 0 ? '- ' : ''}{formatCurrency(value)} + 0 + ? 'font-medium text-red-600' + : 'text-muted-foreground' + } + > + {value > 0 ? '- ' : ''} + {formatCurrency(value)} ); }, @@ -195,13 +220,19 @@ export function createPayrollPeriodColumns( return (
{paid > 0 && ( - {paid} dibayar + + {paid} dibayar + )} {unpaid > 0 && ( - {unpaid} menunggu + + {unpaid} menunggu + )} {cancelled > 0 && ( - {cancelled} dibatalkan + + {cancelled} dibatalkan + )}
); @@ -229,11 +260,7 @@ export function createPayrollPeriodColumns(
- ), cell: ({ row }) => ( - {formatCurrency(row.getValue('base_salary') as number)} + + {formatCurrency(row.getValue('base_salary') as number)} + ), }, { @@ -123,9 +139,7 @@ export function createPayrollColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Bonus @@ -136,8 +150,13 @@ export function createPayrollColumns( const value = row.getValue('bonus_amount') as number; return ( - 0 ? 'text-green-600 font-medium' : ''}> - {value > 0 ? '+ ' : ''}{formatCurrency(value)} + 0 ? 'font-medium text-green-600' : '' + } + > + {value > 0 ? '+ ' : ''} + {formatCurrency(value)} ); }, @@ -149,9 +168,7 @@ export function createPayrollColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Potongan @@ -162,8 +179,11 @@ export function createPayrollColumns( const value = row.getValue('deduction_amount') as number; return ( - 0 ? 'text-red-600 font-medium' : ''}> - {value > 0 ? '- ' : ''}{formatCurrency(value)} + 0 ? 'font-medium text-red-600' : ''} + > + {value > 0 ? '- ' : ''} + {formatCurrency(value)} ); }, @@ -175,9 +195,7 @@ export function createPayrollColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Total @@ -185,7 +203,9 @@ export function createPayrollColumns( ), cell: ({ row }) => ( - {formatCurrency(row.getValue('total_amount') as number)} + + {formatCurrency(row.getValue('total_amount') as number)} + ), }, { @@ -209,16 +229,31 @@ export function createPayrollColumns( return (
{adjustments.map((adj: PayrollAdjustment) => ( -
- - {adj.type === 'bonus' ? '+' : '-'} {formatCurrency(adj.amount)} +
+ + {adj.type === 'bonus' ? '+' : '-'}{' '} + {formatCurrency(adj.amount)} - + {adj.description} {payroll.status === 'unpaid' && ( @@ -265,7 +302,9 @@ export function createPayrollColumns( @@ -280,7 +319,9 @@ export function createPayrollColumns( diff --git a/resources/js/pages/admin/finance/payroll-period/show.tsx b/resources/js/pages/admin/finance/payroll-period/show.tsx index 798cecd..3ce5063 100644 --- a/resources/js/pages/admin/finance/payroll-period/show.tsx +++ b/resources/js/pages/admin/finance/payroll-period/show.tsx @@ -15,9 +15,7 @@ import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { formatCurrency } from '@/lib/utils'; import { destroy as adjustmentDestroy } from '@/routes/admin/finance/payroll-adjustments'; -import { - index as payrollPeriodsIndex -} from '@/routes/admin/finance/payroll-periods'; +import { index as payrollPeriodsIndex } from '@/routes/admin/finance/payroll-periods'; import { cancel as payrollCancel, pay as payrollPay, @@ -40,31 +38,55 @@ type Props = { }; const MONTH_NAMES = [ - '', 'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', - 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember', + '', + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember', ]; export default function PayrollPeriodShow({ payrollPeriod }: Props) { const [paying, setPaying] = useState(null); const [cancelling, setCancelling] = useState(null); - const [addingAdjustment, setAddingAdjustment] = useState(null); - const [deletingAdjustment, setDeletingAdjustment] = useState<{ adjustment: PayrollAdjustment; payrollId: number } | null>(null); + const [addingAdjustment, setAddingAdjustment] = useState( + null, + ); + const [deletingAdjustment, setDeletingAdjustment] = useState<{ + adjustment: PayrollAdjustment; + payrollId: number; + } | null>(null); const [adjustmentType, setAdjustmentType] = useState('bonus'); function handlePay() { if (!paying) return; - router.post(payrollPay(paying.id), {}, { - onSuccess: () => setPaying(null), - }); + router.post( + payrollPay(paying.id), + {}, + { + onSuccess: () => setPaying(null), + }, + ); } function handleCancel() { if (!cancelling) return; - router.post(payrollCancel(cancelling.id), {}, { - onSuccess: () => setCancelling(null), - }); + router.post( + payrollCancel(cancelling.id), + {}, + { + onSuccess: () => setCancelling(null), + }, + ); } function handleDeleteAdjustment() { @@ -87,26 +109,45 @@ export default function PayrollPeriodShow({ payrollPeriod }: Props) { }, }); - const totalBaseSalary = payrollPeriod.payrolls.reduce((sum, p) => sum + p.base_salary, 0); - const totalBonus = payrollPeriod.payrolls.reduce((sum, p) => sum + p.bonus_amount, 0); - const totalDeduction = payrollPeriod.payrolls.reduce((sum, p) => sum + p.deduction_amount, 0); - const totalAmount = payrollPeriod.payrolls.reduce((sum, p) => sum + p.total_amount, 0); + const totalBaseSalary = payrollPeriod.payrolls.reduce( + (sum, p) => sum + p.base_salary, + 0, + ); + const totalBonus = payrollPeriod.payrolls.reduce( + (sum, p) => sum + p.bonus_amount, + 0, + ); + const totalDeduction = payrollPeriod.payrolls.reduce( + (sum, p) => sum + p.deduction_amount, + 0, + ); + const totalAmount = payrollPeriod.payrolls.reduce( + (sum, p) => sum + p.total_amount, + 0, + ); return ( <> - +

- Gaji {MONTH_NAMES[payrollPeriod.month]} {payrollPeriod.year} + Gaji {MONTH_NAMES[payrollPeriod.month]}{' '} + {payrollPeriod.year}

- {payrollPeriod.payrolls.length} karyawan · Status: {payrollPeriod.status === 'open' ? 'Terbuka' : 'Ditutup'} + {payrollPeriod.payrolls.length} karyawan · + Status:{' '} + {payrollPeriod.status === 'open' + ? 'Terbuka' + : 'Ditutup'}

- - diff --git a/resources/js/pages/admin/hr/attendance/index.tsx b/resources/js/pages/admin/hr/attendance/index.tsx index de51bbb..75bb990 100644 --- a/resources/js/pages/admin/hr/attendance/index.tsx +++ b/resources/js/pages/admin/hr/attendance/index.tsx @@ -3,12 +3,32 @@ import { LocationMap } from '@/components/location-map'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { index as attendanceIndex, store, update } from '@/routes/admin/hr/attendances'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { + index as attendanceIndex, + store, + update, +} from '@/routes/admin/hr/attendances'; import { Head, router } from '@inertiajs/react'; import { addMonths, format, subMonths } from 'date-fns'; import { id } from 'date-fns/locale'; -import { CalendarCheck, CalendarDays, CheckCircle2, ChevronLeft, ChevronRight, Clock, LogIn, LogOut, UserX, Wallet } from 'lucide-react'; +import { + CalendarCheck, + CalendarDays, + CheckCircle2, + ChevronLeft, + ChevronRight, + Clock, + LogIn, + LogOut, + UserX, + Wallet, +} from 'lucide-react'; import { useMemo, useState } from 'react'; import { toast } from 'sonner'; @@ -56,12 +76,20 @@ function getFirstDayOfMonth(year: number, month: number): number { } function isSameDay(d1: Date, d2: Date): boolean { - return d1.getDate() === d2.getDate() && d1.getMonth() === d2.getMonth() && d1.getFullYear() === d2.getFullYear(); + return ( + d1.getDate() === d2.getDate() && + d1.getMonth() === d2.getMonth() && + d1.getFullYear() === d2.getFullYear() + ); } function checkIsToday(date: Date): boolean { const t = new Date(); - return date.getDate() === t.getDate() && date.getMonth() === t.getMonth() && date.getFullYear() === t.getFullYear(); + return ( + date.getDate() === t.getDate() && + date.getMonth() === t.getMonth() && + date.getFullYear() === t.getFullYear() + ); } function isWeekend(date: Date): boolean { @@ -69,7 +97,11 @@ function isWeekend(date: Date): boolean { return day === 0 || day === 6; } -function isLate(checkInAt: string | null, officeHour: number, officeMinute: number): boolean { +function isLate( + checkInAt: string | null, + officeHour: number, + officeMinute: number, +): boolean { if (!checkInAt) return false; const d = new Date(checkInAt); const h = d.getHours(); @@ -77,7 +109,11 @@ function isLate(checkInAt: string | null, officeHour: number, officeMinute: numb return h > officeHour || (h === officeHour && m > officeMinute); } -function getLateMinutes(checkInAt: string | null, officeHour: number, officeMinute: number): number { +function getLateMinutes( + checkInAt: string | null, + officeHour: number, + officeMinute: number, +): number { if (!checkInAt || !isLate(checkInAt, officeHour, officeMinute)) return 0; const d = new Date(checkInAt); const officeStart = new Date(d); @@ -93,14 +129,29 @@ function formatMinutes(minutes: number | null): string { return `${hours} jam ${mins} menit`; } -export default function AttendanceIndex({ attendances, todayAttendance, currentYear, currentMonth, monthStats, hrSettings }: Props) { - const [officeHour, officeMinute] = hrSettings.scheduled_check_in_time.split(':').map(Number); - const [viewDate, setViewDate] = useState(new Date(currentYear, currentMonth - 1)); +export default function AttendanceIndex({ + attendances, + todayAttendance, + currentYear, + currentMonth, + monthStats, + hrSettings, +}: Props) { + const [officeHour, officeMinute] = hrSettings.scheduled_check_in_time + .split(':') + .map(Number); + const [viewDate, setViewDate] = useState( + new Date(currentYear, currentMonth - 1), + ); const [selectedDate, setSelectedDate] = useState(new Date()); const [showCamera, setShowCamera] = useState(false); - const [actionType, setActionType] = useState<'check-in' | 'check-out'>('check-in'); + const [actionType, setActionType] = useState<'check-in' | 'check-out'>( + 'check-in', + ); const [locationLoading, setLocationLoading] = useState(false); - const [detailAttendance, setDetailAttendance] = useState(null); + const [detailAttendance, setDetailAttendance] = useState( + null, + ); const viewYear = viewDate.getFullYear(); const viewMonth = viewDate.getMonth() + 1; @@ -121,7 +172,10 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY const calendarDays = useMemo(() => { const daysInMonth = getDaysInMonth(viewYear, viewMonth); const firstDay = getFirstDayOfMonth(viewYear, viewMonth); - const prevMonthDays = getDaysInMonth(viewYear, viewMonth === 1 ? 12 : viewMonth - 1); + const prevMonthDays = getDaysInMonth( + viewYear, + viewMonth === 1 ? 12 : viewMonth - 1, + ); const days: { day: number; isCurrentMonth: boolean; date: Date }[] = []; @@ -129,18 +183,30 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY const d = prevMonthDays - i; const m = viewMonth === 1 ? 12 : viewMonth - 1; const y = viewMonth === 1 ? viewYear - 1 : viewYear; - days.push({ day: d, isCurrentMonth: false, date: new Date(y, m - 1, d) }); + days.push({ + day: d, + isCurrentMonth: false, + date: new Date(y, m - 1, d), + }); } for (let i = 1; i <= daysInMonth; i++) { - days.push({ day: i, isCurrentMonth: true, date: new Date(viewYear, viewMonth - 1, i) }); + days.push({ + day: i, + isCurrentMonth: true, + date: new Date(viewYear, viewMonth - 1, i), + }); } const remaining = 42 - days.length; for (let i = 1; i <= remaining; i++) { const m = viewMonth === 12 ? 1 : viewMonth + 1; const y = viewMonth === 12 ? viewYear + 1 : viewYear; - days.push({ day: i, isCurrentMonth: false, date: new Date(y, m - 1, i) }); + days.push({ + day: i, + isCurrentMonth: false, + date: new Date(y, m - 1, i), + }); } return days; @@ -164,20 +230,30 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY setLocationLoading(false); const formData = new FormData(); formData.append('photo', dataUrl); - formData.append('latitude', position.coords.latitude.toString()); - formData.append('longitude', position.coords.longitude.toString()); + formData.append( + 'latitude', + position.coords.latitude.toString(), + ); + formData.append( + 'longitude', + position.coords.longitude.toString(), + ); if (actionType === 'check-in') { router.post(store(), formData, { preserveScroll: true }); } else if (actionType === 'check-out' && todayAttendance) { - router.put(update(todayAttendance.id), formData, { preserveScroll: true }); + router.put(update(todayAttendance.id), formData, { + preserveScroll: true, + }); } }, () => { setLocationLoading(false); - toast.error('Gagal mendapatkan lokasi. Pastikan izin lokasi diberikan.'); + toast.error( + 'Gagal mendapatkan lokasi. Pastikan izin lokasi diberikan.', + ); }, - { enableHighAccuracy: true, timeout: 10000 } + { enableHighAccuracy: true, timeout: 10000 }, ); }; @@ -205,7 +281,9 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY
-

Presensi

+

+ Presensi +

{/* Alert Status Presensi */} @@ -219,33 +297,53 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY
- Masuk: - {formatTime(todayAttendance?.check_in_at)} + + Masuk: + + + {formatTime( + todayAttendance?.check_in_at, + )} +
{hasCheckedOut ? ( <> - Pulang: - {formatTime(todayAttendance?.check_out_at)} + + Pulang: + + + {formatTime( + todayAttendance?.check_out_at, + )} + ) : ( <> - Pulang: - Belum + + Pulang: + + + Belum + )}
) : ( -

Anda belum melakukan presensi hari ini

+

+ Anda belum melakukan presensi hari ini +

)}
{locationLoading && ( - Mendapatkan lokasi... + + Mendapatkan lokasi... + )}
-

Hari Kerja

-

{monthStats.working_days}

+

+ Hari Kerja +

+

+ {monthStats.working_days} +

@@ -288,8 +394,12 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY
-

Hadir

-

{monthStats.present}

+

+ Hadir +

+

+ {monthStats.present} +

@@ -299,8 +409,12 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY
-

Tidak Hadir

-

{monthStats.absent}

+

+ Tidak Hadir +

+

+ {monthStats.absent} +

@@ -310,41 +424,72 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY
-

Cuti

-

{monthStats.leave}

+

+ Cuti +

+

+ {monthStats.leave} +

- + {/* Calendar Header */}
- - {format(viewDate, 'MMM', { locale: id })} + + {format(viewDate, 'MMM', { + locale: id, + })}
- {format(viewDate, 'dd')} + + {format(viewDate, 'dd')} +

- {format(viewDate, 'MMMM yyyy', { locale: id })} + {format(viewDate, 'MMMM yyyy', { + locale: id, + })}

- - -
@@ -353,7 +498,10 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY {/* Weekday Headers */}
{WEEKDAYS.map((day) => ( -
+
{day}
))} @@ -364,8 +512,14 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY {calendarDays.map((cell, idx) => { const dateStr = format(cell.date, 'yyyy-MM-dd'); const attendance = attendanceDates.get(dateStr); - const isSelected = isSameDay(cell.date, selectedDate); - const isTodayDate = isSameDay(cell.date, new Date()); + const isSelected = isSameDay( + cell.date, + selectedDate, + ); + const isTodayDate = isSameDay( + cell.date, + new Date(), + ); const today = new Date(); today.setHours(0, 0, 0, 0); @@ -373,20 +527,39 @@ export default function AttendanceIndex({ attendances, todayAttendance, currentY cellDate.setHours(0, 0, 0, 0); const isPastDate = cellDate < today; - const showAbsent = cell.isCurrentMonth && isPastDate && !isWeekend(cell.date) && !attendance; + const showAbsent = + cell.isCurrentMonth && + isPastDate && + !isWeekend(cell.date) && + !attendance; - const late = attendance ? isLate(attendance.check_in_at, officeHour, officeMinute) : false; - const lateMins = attendance ? getLateMinutes(attendance.check_in_at, officeHour, officeMinute) : 0; + const late = attendance + ? isLate( + attendance.check_in_at, + officeHour, + officeMinute, + ) + : false; + const lateMins = attendance + ? getLateMinutes( + attendance.check_in_at, + officeHour, + officeMinute, + ) + : 0; return ( - - Edit - + Edit @@ -221,7 +224,9 @@ export function createEmployeeColumns( @@ -236,7 +241,9 @@ export function createEmployeeColumns( diff --git a/resources/js/pages/admin/hr/employee/create.tsx b/resources/js/pages/admin/hr/employee/create.tsx index bc944a7..f0dee26 100644 --- a/resources/js/pages/admin/hr/employee/create.tsx +++ b/resources/js/pages/admin/hr/employee/create.tsx @@ -36,7 +36,7 @@ export default function EmployeeCreate() { Tambah Pegawai
-
diff --git a/resources/js/pages/admin/hr/employee/edit.tsx b/resources/js/pages/admin/hr/employee/edit.tsx index 717b115..519448b 100644 --- a/resources/js/pages/admin/hr/employee/edit.tsx +++ b/resources/js/pages/admin/hr/employee/edit.tsx @@ -45,13 +45,19 @@ type Props = { export default function EmployeeEdit({ employee }: Props) { const [joinDate, setJoinDate] = useState( - employee.employee?.join_date ? new Date(employee.employee.join_date) : undefined + employee.employee?.join_date + ? new Date(employee.employee.join_date) + : undefined, ); const [resignDate, setResignDate] = useState( - employee.employee?.resign_date ? new Date(employee.employee.resign_date) : undefined + employee.employee?.resign_date + ? new Date(employee.employee.resign_date) + : undefined, ); const [birthDate, setBirthDate] = useState( - employee.user_profile?.birth_date ? new Date(employee.user_profile.birth_date) : undefined + employee.user_profile?.birth_date + ? new Date(employee.user_profile.birth_date) + : undefined, ); return ( @@ -65,7 +71,7 @@ export default function EmployeeEdit({ employee }: Props) { Edit Pegawai
-
-
+
diff --git a/resources/js/pages/admin/hr/employee/index.tsx b/resources/js/pages/admin/hr/employee/index.tsx index 25402ea..d1d7d67 100644 --- a/resources/js/pages/admin/hr/employee/index.tsx +++ b/resources/js/pages/admin/hr/employee/index.tsx @@ -5,9 +5,26 @@ import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; import type { PaginationState, SortState } from '@/components/data-table'; import { Button } from '@/components/ui/button'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; -import { destroy, create as employeeCreate, edit as employeeEdit, index as employeeIndex, toggleActive, resetPassword as resetPasswordRoute } from '@/routes/admin/hr/employees'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { + destroy, + create as employeeCreate, + edit as employeeEdit, + index as employeeIndex, + toggleActive, + resetPassword as resetPasswordRoute, +} from '@/routes/admin/hr/employees'; import type { Employee } from './columns'; import { createEmployeeColumns } from './columns'; @@ -28,10 +45,14 @@ type Props = { export default function EmployeeIndex({ employees, filters }: Props) { const [deleting, setDeleting] = useState(null); - const [resetPasswordTarget, setResetPasswordTarget] = useState(null); + const [resetPasswordTarget, setResetPasswordTarget] = + useState(null); const [filterOpen, setFilterOpen] = useState(false); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: employees.current_page, @@ -51,71 +72,98 @@ export default function EmployeeIndex({ employees, filters }: Props) { newFilters[key as keyof typeof newFilters] = value; } - router.get(employeeIndex.url(), { - ...newFilters, - page: 1, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + employeeIndex.url(), + { + ...newFilters, + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function clearFilters() { - router.get(employeeIndex.url(), { - page: 1, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + employeeIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); setFilterOpen(false); } function handlePageChange(page: number) { - router.get(employeeIndex.url(), { - ...filters, - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + employeeIndex.url(), + { + ...filters, + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function handlePerPageChange(perPage: number) { - router.get(employeeIndex.url(), { - ...filters, - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + employeeIndex.url(), + { + ...filters, + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(employeeIndex.url(), { - ...filters, - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); - }, [pagination.per_page, sort, filters]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + employeeIndex.url(), + { + ...filters, + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); + }, + [pagination.per_page, sort, filters], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(employeeIndex.url(), { - ...filters, - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { preserveState: true, replace: true }); + router.get( + employeeIndex.url(), + { + ...filters, + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { preserveState: true, replace: true }, + ); } function handleDelete() { @@ -133,9 +181,13 @@ export default function EmployeeIndex({ employees, filters }: Props) { return; } - router.post(resetPasswordRoute.url(resetPasswordTarget.id), {}, { - onSuccess: () => setResetPasswordTarget(null), - }); + router.post( + resetPasswordRoute.url(resetPasswordTarget.id), + {}, + { + onSuccess: () => setResetPasswordTarget(null), + }, + ); } const columns = createEmployeeColumns({ @@ -183,17 +235,29 @@ export default function EmployeeIndex({ employees, filters }: Props) { @@ -205,7 +269,9 @@ export default function EmployeeIndex({ employees, filters }: Props) { applyFilter('gender', value)} + onValueChange={(value) => + applyFilter('gender', value) + } > @@ -232,7 +300,9 @@ export default function EmployeeIndex({ employees, filters }: Props) { Semua Laki-laki - Perempuan + + Perempuan +
diff --git a/resources/js/pages/admin/hr/leave-request/columns.tsx b/resources/js/pages/admin/hr/leave-request/columns.tsx index 2264ad6..03d27d3 100644 --- a/resources/js/pages/admin/hr/leave-request/columns.tsx +++ b/resources/js/pages/admin/hr/leave-request/columns.tsx @@ -7,7 +7,13 @@ import { TooltipTrigger, } from '@/components/ui/tooltip'; import type { ColumnDef } from '@tanstack/react-table'; -import { ArrowUpDown, CheckCircle, Pencil, Trash2, XCircle } from 'lucide-react'; +import { + ArrowUpDown, + CheckCircle, + Pencil, + Trash2, + XCircle, +} from 'lucide-react'; export type LeaveRequest = { id: number; @@ -74,16 +80,15 @@ type CreateColumnsParams = { export function createLeaveRequestColumns( params: CreateColumnsParams, ): ColumnDef[] { - const { handleEdit, handleDeleteClick, handleApprove, handleReject } = params; + const { handleEdit, handleDeleteClick, handleApprove, handleReject } = + params; return [ { id: 'no', header: () => No, cell: ({ row }) => ( - - {row.index + 1} - + {row.index + 1} ), meta: { className: 'w-[50px] text-center', @@ -96,7 +101,11 @@ export function createLeaveRequestColumns( cell: ({ row }) => { const employee = row.original.employee; - return {employee?.user?.user_profile?.full_name ?? '-'}; + return ( + + {employee?.user?.user_profile?.full_name ?? '-'} + + ); }, }, { @@ -106,9 +115,7 @@ export function createLeaveRequestColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Tanggal Mulai @@ -116,7 +123,9 @@ export function createLeaveRequestColumns( ), cell: ({ row }) => ( - {formatShortDate(row.getValue('start_date') as string)} + + {formatShortDate(row.getValue('start_date') as string)} + ), }, { @@ -126,9 +135,7 @@ export function createLeaveRequestColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Tanggal Selesai @@ -136,7 +143,9 @@ export function createLeaveRequestColumns( ), cell: ({ row }) => ( - {formatShortDate(row.getValue('end_date') as string)} + + {formatShortDate(row.getValue('end_date') as string)} + ), }, { @@ -146,9 +155,7 @@ export function createLeaveRequestColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Hari @@ -224,16 +231,12 @@ export function createLeaveRequestColumns( - - Edit - + Edit diff --git a/resources/js/pages/admin/hr/leave-request/index.tsx b/resources/js/pages/admin/hr/leave-request/index.tsx index 1bccb5c..61daca2 100644 --- a/resources/js/pages/admin/hr/leave-request/index.tsx +++ b/resources/js/pages/admin/hr/leave-request/index.tsx @@ -15,9 +15,26 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; -import { approve, destroy, index as leaveRequestIndex, reject, store, update } from '@/routes/admin/hr/leave-requests'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { + approve, + destroy, + index as leaveRequestIndex, + reject, + store, + update, +} from '@/routes/admin/hr/leave-requests'; import type { LeaveRequest } from './columns'; import { createLeaveRequestColumns } from './columns'; @@ -42,11 +59,18 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { const [rejecting, setRejecting] = useState(null); const [startDate, setStartDate] = useState(undefined); const [endDate, setEndDate] = useState(undefined); - const [editingStartDate, setEditingStartDate] = useState(undefined); - const [editingEndDate, setEditingEndDate] = useState(undefined); + const [editingStartDate, setEditingStartDate] = useState( + undefined, + ); + const [editingEndDate, setEditingEndDate] = useState( + undefined, + ); const [filterOpen, setFilterOpen] = useState(false); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: leaveRequests.current_page, @@ -76,24 +100,32 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { newFilters[key as keyof typeof newFilters] = value; } - router.get(leaveRequestIndex(), { - ...newFilters, - page: 1, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + leaveRequestIndex(), + { + ...newFilters, + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function clearFilters() { - router.get(leaveRequestIndex(), { - page: 1, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + leaveRequestIndex(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); setFilterOpen(false); } @@ -112,9 +144,13 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { return; } - router.post(approve(approving.id), {}, { - onSuccess: () => setApproving(null), - }); + router.post( + approve(approving.id), + {}, + { + onSuccess: () => setApproving(null), + }, + ); } function handleReject() { @@ -122,55 +158,78 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { return; } - router.post(reject(rejecting.id), {}, { - onSuccess: () => setRejecting(null), - }); + router.post( + reject(rejecting.id), + {}, + { + onSuccess: () => setRejecting(null), + }, + ); } function handlePageChange(page: number) { - router.get(leaveRequestIndex(), { - ...filters, - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + leaveRequestIndex(), + { + ...filters, + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } function handlePerPageChange(perPage: number) { - router.get(leaveRequestIndex(), { - ...filters, - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); + router.get( + leaveRequestIndex(), + { + ...filters, + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(leaveRequestIndex(), { - ...filters, - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { preserveState: true, replace: true }); - }, [pagination.per_page, sort, filters]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + leaveRequestIndex(), + { + ...filters, + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { preserveState: true, replace: true }, + ); + }, + [pagination.per_page, sort, filters], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(leaveRequestIndex(), { - ...filters, - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { preserveState: true, replace: true }); + router.get( + leaveRequestIndex(), + { + ...filters, + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { preserveState: true, replace: true }, + ); } const columns = createLeaveRequestColumns({ @@ -216,17 +275,29 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) {
@@ -246,14 +317,17 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { Cuti
- { - setCreateOpen(open); + { + setCreateOpen(open); - if (!open) { - setStartDate(undefined); - setEndDate(undefined); - } - }}> + if (!open) { + setStartDate(undefined); + setEndDate(undefined); + } + }} + > - setCreateOpen(false)}> + setCreateOpen(false)} + > {({ errors, processing }) => { - return ( <> - Tambah Permohonan Cuti + + Tambah Permohonan Cuti +
- + - +
- + - +
- - Edit - + Edit
diff --git a/resources/js/pages/admin/master/category/index.tsx b/resources/js/pages/admin/master/category/index.tsx index 28ff069..ced2424 100644 --- a/resources/js/pages/admin/master/category/index.tsx +++ b/resources/js/pages/admin/master/category/index.tsx @@ -15,7 +15,12 @@ import { } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { destroy, index as categoryIndex, store, update } from '@/routes/admin/master/categories'; +import { + destroy, + index as categoryIndex, + store, + update, +} from '@/routes/admin/master/categories'; import { createCategoryColumns } from './columns'; import type { Category } from './columns'; @@ -34,7 +39,10 @@ export default function CategoryIndex({ categories }: Props) { const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: categories.current_page, @@ -44,57 +52,76 @@ export default function CategoryIndex({ categories }: Props) { }; function handlePageChange(page: number) { - router.get(categoryIndex.url(), { - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { - preserveState: true, - replace: true, - }); + router.get( + categoryIndex.url(), + { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { + preserveState: true, + replace: true, + }, + ); } function handlePerPageChange(perPage: number) { - router.get(categoryIndex.url(), { - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { - preserveState: true, - replace: true, - }); + router.get( + categoryIndex.url(), + { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { + preserveState: true, + replace: true, + }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(categoryIndex.url(), { - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { - preserveState: true, - replace: true, - }); - }, [pagination.per_page, sort]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + categoryIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { + preserveState: true, + replace: true, + }, + ); + }, + [pagination.per_page, sort], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(categoryIndex.url(), { - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { - preserveState: true, - replace: true, - }); + router.get( + categoryIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { + preserveState: true, + replace: true, + }, + ); } function handleDelete() { @@ -134,37 +161,49 @@ export default function CategoryIndex({ categories }: Props) { - setCreateOpen(false)}> + setCreateOpen(false)} + > {({ errors, processing }) => { - return ( <> - Tambah Kategori + + Tambah Kategori +
- +
), cell: ({ row }) => ( - - {row.getValue('phone_number') as string ?? '-'} - + {(row.getValue('phone_number') as string) ?? '-'} ), }, { @@ -90,9 +82,7 @@ export function createCustomerColumns( variant="ghost" className="-ml-3 h-8" onClick={() => - column.toggleSorting( - column.getIsSorted() === 'asc', - ) + column.toggleSorting(column.getIsSorted() === 'asc') } > Alamat @@ -100,8 +90,8 @@ export function createCustomerColumns( ), cell: ({ row }) => ( - - {row.getValue('address') as string ?? '-'} + + {(row.getValue('address') as string) ?? '-'} ), }, @@ -123,16 +113,12 @@ export function createCustomerColumns( - - Edit - + Edit
diff --git a/resources/js/pages/admin/master/customer/index.tsx b/resources/js/pages/admin/master/customer/index.tsx index e4f4911..2b2a1b7 100644 --- a/resources/js/pages/admin/master/customer/index.tsx +++ b/resources/js/pages/admin/master/customer/index.tsx @@ -16,7 +16,12 @@ import { } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { index as customerIndex, destroy, store, update } from '@/routes/admin/master/customers'; +import { + index as customerIndex, + destroy, + store, + update, +} from '@/routes/admin/master/customers'; import type { Customer } from './columns'; import { createCustomerColumns } from './columns'; @@ -35,7 +40,10 @@ export default function CustomerIndex({ customers }: Props) { const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); const [search, setSearch] = useState(''); - const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + const [sort, setSort] = useState({ + column: 'created_at', + direction: 'desc', + }); const pagination: PaginationState = { current_page: customers.current_page, @@ -45,57 +53,76 @@ export default function CustomerIndex({ customers }: Props) { }; function handlePageChange(page: number) { - router.get(customerIndex.url(), { - page, - per_page: pagination.per_page, - search, - sort: sort.column, - direction: sort.direction, - }, { - preserveState: true, - replace: true, - }); + router.get( + customerIndex.url(), + { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, + { + preserveState: true, + replace: true, + }, + ); } function handlePerPageChange(perPage: number) { - router.get(customerIndex.url(), { - page: 1, - per_page: perPage, - search, - sort: sort.column, - direction: sort.direction, - }, { - preserveState: true, - replace: true, - }); + router.get( + customerIndex.url(), + { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, + { + preserveState: true, + replace: true, + }, + ); } - const handleSearchChange = useCallback((value: string) => { - setSearch(value); - router.get(customerIndex.url(), { - page: 1, - per_page: pagination.per_page, - search: value, - sort: sort.column, - direction: sort.direction, - }, { - preserveState: true, - replace: true, - }); - }, [pagination.per_page, sort]); + const handleSearchChange = useCallback( + (value: string) => { + setSearch(value); + router.get( + customerIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, + { + preserveState: true, + replace: true, + }, + ); + }, + [pagination.per_page, sort], + ); function handleSortChange(column: string, direction: 'asc' | 'desc') { setSort({ column, direction }); - router.get(customerIndex.url(), { - page: 1, - per_page: pagination.per_page, - search, - sort: column, - direction, - }, { - preserveState: true, - replace: true, - }); + router.get( + customerIndex.url(), + { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, + { + preserveState: true, + replace: true, + }, + ); } function handleDelete() { @@ -135,32 +162,46 @@ export default function CustomerIndex({ customers }: Props) { - setCreateOpen(false)}> + setCreateOpen(false)} + > {({ errors, processing }) => { - return ( <> - Tambah Customer + + Tambah Customer +
- +
- - + +
@@ -336,9 +395,7 @@ export function createProductColumns( - - Edit - + Edit
@@ -346,7 +403,9 @@ export function createProductColumns( diff --git a/resources/js/pages/admin/master/product/create.tsx b/resources/js/pages/admin/master/product/create.tsx index b55fe57..47e1fbb 100644 --- a/resources/js/pages/admin/master/product/create.tsx +++ b/resources/js/pages/admin/master/product/create.tsx @@ -9,7 +9,14 @@ import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Textarea } from '@/components/ui/textarea'; import { index as productIndex, store } from '@/routes/admin/master/products'; import { Form, Head } from '@inertiajs/react'; -import { ArrowLeft, Copy, ClipboardPaste, Check, Plus, Trash2 } from 'lucide-react'; +import { + ArrowLeft, + Copy, + ClipboardPaste, + Check, + Plus, + Trash2, +} from 'lucide-react'; import { useCallback, useRef, useState } from 'react'; type Category = { @@ -50,7 +57,8 @@ type VariantState = { export default function ProductCreate({ categories }: Props) { const [categoryIds, setCategoryIds] = useState([]); const [useSamePrice, setUseSamePrice] = useState(true); - const [sharedPrices, setSharedPrices] = useState>(createEmptyPrices()); + const [sharedPrices, setSharedPrices] = + useState>(createEmptyPrices()); const [variants, setVariants] = useState([ { name: '', @@ -85,34 +93,43 @@ export default function ProductCreate({ categories }: Props) { setVariants((prev) => prev.filter((_, i) => i !== index)); }, []); - const updateVariant = useCallback((index: number, field: keyof VariantState, value: unknown) => { - setVariants((prev) => { - const updated = [...prev]; - (updated[index] as Record)[field] = value; - return updated; - }); - }, []); + const updateVariant = useCallback( + (index: number, field: keyof VariantState, value: unknown) => { + setVariants((prev) => { + const updated = [...prev]; + (updated[index] as Record)[field] = value; + return updated; + }); + }, + [], + ); - const updateVariantPrice = useCallback((variantIndex: number, priceIndex: number, value: number) => { - setVariants((prev) => { - const updated = [...prev]; - updated[variantIndex] = { - ...updated[variantIndex], - prices: updated[variantIndex].prices.map((p, i) => - i === priceIndex ? { ...p, price: value } : p - ), - }; - return updated; - }); - }, []); + const updateVariantPrice = useCallback( + (variantIndex: number, priceIndex: number, value: number) => { + setVariants((prev) => { + const updated = [...prev]; + updated[variantIndex] = { + ...updated[variantIndex], + prices: updated[variantIndex].prices.map((p, i) => + i === priceIndex ? { ...p, price: value } : p, + ), + }; + return updated; + }); + }, + [], + ); - const updateSharedPrice = useCallback((priceIndex: number, value: number) => { - setSharedPrices((prev) => { - const updated = [...prev]; - updated[priceIndex] = { ...updated[priceIndex], price: value }; - return updated; - }); - }, []); + const updateSharedPrice = useCallback( + (priceIndex: number, value: number) => { + setSharedPrices((prev) => { + const updated = [...prev]; + updated[priceIndex] = { ...updated[priceIndex], price: value }; + return updated; + }); + }, + [], + ); const [copiedIndex, setCopiedIndex] = useState(null); @@ -129,10 +146,16 @@ export default function ProductCreate({ categories }: Props) { const pastePrices = useCallback((variantIndex: number) => { navigator.clipboard.readText().then((text) => { try { - const prices = JSON.parse(text) as Array<{ type: string; price: number }>; + const prices = JSON.parse(text) as Array<{ + type: string; + price: number; + }>; setVariants((prev) => { const updated = [...prev]; - updated[variantIndex] = { ...updated[variantIndex], prices }; + updated[variantIndex] = { + ...updated[variantIndex], + prices, + }; return updated; }); } catch { @@ -145,7 +168,7 @@ export default function ProductCreate({ categories }: Props) { setVariants((prev) => { const sourcePrices = prev[variantIndex].prices; return prev.map((v, i) => - i === variantIndex ? v : { ...v, prices: [...sourcePrices] } + i === variantIndex ? v : { ...v, prices: [...sourcePrices] }, ); }); }, []); @@ -154,10 +177,12 @@ export default function ProductCreate({ categories }: Props) { return { category_ids: categoryIds, use_same_price: useSamePrice, - shared_prices: useSamePrice ? sharedPrices.map((p) => ({ - type: p.type, - price: Number(p.price), - })) : [], + shared_prices: useSamePrice + ? sharedPrices.map((p) => ({ + type: p.type, + price: Number(p.price), + })) + : [], variants: variantsRef.current.map((v) => ({ name: v.name, stock: Number(v.stock), @@ -166,7 +191,10 @@ export default function ProductCreate({ categories }: Props) { photo_key: v.photo, prices: useSamePrice ? [] - : v.prices.map((p) => ({ type: p.type, price: Number(p.price) })), + : v.prices.map((p) => ({ + type: p.type, + price: Number(p.price), + })), })), }; } @@ -177,7 +205,9 @@ export default function ProductCreate({ categories }: Props) {
-

Tambah Produk

+

+ Tambah Produk +