feat: add complete action for cuttings with notification and update route
This commit is contained in:
parent
7c160cb571
commit
703cdb8b8b
@ -95,6 +95,15 @@ public function destroy(Cutting $cutting): RedirectResponse
|
||||
);
|
||||
}
|
||||
|
||||
public function complete(Cutting $cutting): RedirectResponse
|
||||
{
|
||||
return $this->handleAction(
|
||||
fn () => $this->service->complete($cutting),
|
||||
'Cutting berhasil diselesaikan.',
|
||||
'admin.manage.cuttings.index'
|
||||
);
|
||||
}
|
||||
|
||||
public function materials(Cutting $cutting): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services\Admin\Manage;
|
||||
|
||||
use App\Enums\CuttingStatus;
|
||||
use App\Enums\Role;
|
||||
use App\Models\Cutting;
|
||||
use App\Models\CuttingMaterial;
|
||||
@ -500,4 +501,18 @@ public function destroy(Cutting $cutting): bool
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function complete(Cutting $cutting): Cutting
|
||||
{
|
||||
$cutting->update(['status' => CuttingStatus::COMPLETED]);
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
||||
title: 'Cutting Selesai',
|
||||
body: 'Cutting berhasil diselesaikan oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.cuttings.index'),
|
||||
);
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { Briefcase, ChevronDown, Copy, MessageCircle, Pencil, Share2, Trash2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { RowActions } from '@/components/data-display';
|
||||
import { ImagePreviewButton } from '@/components/dialogs';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -13,6 +11,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import { share as cuttingShare } from '@/routes/admin/manage/cuttings';
|
||||
import { ChevronDown, Pencil, ScissorsIcon, Share2, Trash2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import type { Cutting } from './columns';
|
||||
|
||||
function generateShareLink(cuttingId: number): string {
|
||||
@ -90,6 +90,7 @@ export type CuttingCardRowParams = {
|
||||
index: number;
|
||||
isExpanded: boolean;
|
||||
onToggleExpand: () => void;
|
||||
onComplete: (cutting: Cutting) => void;
|
||||
onEdit: (cutting: Cutting) => void;
|
||||
onDelete: (cutting: Cutting) => void;
|
||||
};
|
||||
@ -99,12 +100,12 @@ export function CuttingCardRow({
|
||||
index,
|
||||
isExpanded,
|
||||
onToggleExpand,
|
||||
onComplete,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: CuttingCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const [shareOpen, setShareOpen] = useState(false);
|
||||
const [copied, setCopied] = useState(false);
|
||||
const materialsCount = cutting.materials_count ?? 0;
|
||||
const totalUsage = cutting.total_usage ?? 0;
|
||||
const productName = cutting.product_name ?? '-';
|
||||
@ -254,6 +255,12 @@ export function CuttingCardRow({
|
||||
{(can('cuttings.update') || can('cuttings.delete')) && (
|
||||
<RowActions
|
||||
actions={[
|
||||
{
|
||||
label: 'Selesaikan',
|
||||
icon: <ScissorsIcon className="h-4 w-4" />,
|
||||
show: can('cuttings.complete') && cutting.status === 'in_progress',
|
||||
onClick: () => onComplete(cutting),
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
|
||||
@ -30,6 +30,7 @@ import {
|
||||
index as cuttingIndex,
|
||||
edit as cuttingEdit,
|
||||
materials as cuttingMaterials,
|
||||
complete as cuttingComplete,
|
||||
} from '@/routes/admin/manage/cuttings';
|
||||
import type { Cutting, CuttingMaterialDetail, CuttingCombination } from './columns';
|
||||
import { CuttingCardRow } from './cutting-card';
|
||||
@ -60,6 +61,7 @@ export default function CuttingIndex({
|
||||
}: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Cutting | null>(null);
|
||||
const [completing, setCompleting] = useState<Cutting | null>(null);
|
||||
const [loadedMaterials, setLoadedMaterials] = useState<Record<number, CuttingMaterialDetail[]>>({});
|
||||
const [loadedCombinations, setLoadedCombinations] = useState<Record<number, CuttingCombination[]>>({});
|
||||
const [loadingMaterials, setLoadingMaterials] = useState<Record<number, boolean>>({});
|
||||
@ -100,6 +102,16 @@ export default function CuttingIndex({
|
||||
});
|
||||
}
|
||||
|
||||
function handleComplete() {
|
||||
if (!completing) {
|
||||
return;
|
||||
}
|
||||
|
||||
router.patch(cuttingComplete.url(completing.id), {}, {
|
||||
onSuccess: () => setCompleting(null),
|
||||
});
|
||||
}
|
||||
|
||||
const selectedProductName = useMemo(
|
||||
() =>
|
||||
filterOptions.productNames.find(
|
||||
@ -261,6 +273,7 @@ export default function CuttingIndex({
|
||||
}
|
||||
isExpanded={isExpanded}
|
||||
onToggleExpand={onToggleExpand}
|
||||
onComplete={(c) => setCompleting(c)}
|
||||
onEdit={(c) => {
|
||||
router.visit(cuttingEdit.url(c.id));
|
||||
}}
|
||||
@ -290,6 +303,21 @@ export default function CuttingIndex({
|
||||
}
|
||||
onConfirm={handleDelete}
|
||||
/>
|
||||
|
||||
<DeleteConfirmDialog
|
||||
target={completing}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setCompleting(null);
|
||||
}
|
||||
}}
|
||||
title="Selesaikan Cutting"
|
||||
description={(cutting) =>
|
||||
`Apakah Anda yakin ingin menyelesaikan cutting "${cutting.cutting_results?.[0]?.product_name ?? '-'}"?`
|
||||
}
|
||||
confirmLabel="Selesaikan"
|
||||
onConfirm={handleComplete}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -72,6 +72,7 @@
|
||||
|
||||
Route::resource('cuttings', CuttingController::class)->middleware('permission:cuttings.view|cuttings.create|cuttings.update|cuttings.delete');
|
||||
Route::get('cuttings/{cutting}/materials', [CuttingController::class, 'materials'])->name('cuttings.materials')->middleware('permission:cuttings.view');
|
||||
Route::patch('cuttings/{cutting}/complete', [CuttingController::class, 'complete'])->name('cuttings.complete')->middleware('permission:cuttings.complete');
|
||||
|
||||
Route::resource('transactions', TransactionController::class)->except(['show'])->middleware('permission:orders.view|orders.create|orders.update|orders.delete');
|
||||
Route::patch('transactions/{transaction}/status', [TransactionController::class, 'updateStatus'])->name('transactions.updateStatus')->middleware('permission:orders.update');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user