From 9f0676c92378d43ed55d4ac5f7a4b2ce2f1e0a2b Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Tue, 30 Jun 2026 21:22:17 +0700 Subject: [PATCH] feat: include and display media images for raw material prices and product variants in cutting management --- app/Services/Manage/CuttingService.php | 56 +++++++++++-------- .../js/pages/admin/manage/cuttings/Share.vue | 13 ++++- .../cuttings/table/CuttingGroupedTable.vue | 17 ++++-- resources/js/types/cutting.ts | 3 + 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php index f38c96c..3fd3612 100644 --- a/app/Services/Manage/CuttingService.php +++ b/app/Services/Manage/CuttingService.php @@ -35,8 +35,9 @@ public function paginateForIndex(array $tableQuery, User $user): LengthAwarePagi 'createdBy.profile', 'rejection.rejectedBy.profile', 'materials.rawMaterialPrice.rawMaterial:id,name,unit', + 'materials.rawMaterialPrice.media', 'results.productVariant.product:id,name', - 'results.productVariant:id,product_id,name', + 'results.productVariant.media', ]) ->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void { $search = $tableQuery['search']; @@ -62,6 +63,7 @@ public function paginateForIndex(array $tableQuery, User $user): LengthAwarePagi $cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user)); $cutting->setAttribute('is_editable', $cutting->status->isEditable()); $this->appendCostPreview($cutting); + $this->appendPhotos($cutting); $cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m)); return $cutting; @@ -75,8 +77,9 @@ public function getInProgressCuttings(User $user): Collection 'createdBy.profile', 'rejection.rejectedBy.profile', 'materials.rawMaterialPrice.rawMaterial:id,name,unit', + 'materials.rawMaterialPrice.media', 'results.productVariant.product:id,name', - 'results.productVariant:id,product_id,name', + 'results.productVariant.media', ]) ->inProgress() ->latest() @@ -85,6 +88,7 @@ public function getInProgressCuttings(User $user): Collection $cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user)); $cutting->setAttribute('is_editable', $cutting->status->isEditable()); $this->appendCostPreview($cutting); + $this->appendPhotos($cutting); $cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m)); }); } @@ -96,8 +100,9 @@ public function getCompletedCuttings(User $user): Collection 'createdBy.profile', 'rejection.rejectedBy.profile', 'materials.rawMaterialPrice.rawMaterial:id,name,unit', + 'materials.rawMaterialPrice.media', 'results.productVariant.product:id,name', - 'results.productVariant:id,product_id,name', + 'results.productVariant.media', ]) ->completed() ->latest() @@ -106,6 +111,7 @@ public function getCompletedCuttings(User $user): Collection $cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user)); $cutting->setAttribute('is_editable', $cutting->status->isEditable()); $this->appendCostPreview($cutting); + $this->appendPhotos($cutting); $cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m)); }); } @@ -187,14 +193,37 @@ public function findForEdit(Cutting $cutting): Cutting 'rejection.rejectedBy.profile', ]); + $this->appendPhotos($cutting); + $cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m)); + + return $cutting; + } + + public function findForShare(Cutting $cutting): Cutting + { + $cutting->load([ + 'createdBy.profile', + 'materials.rawMaterialPrice.rawMaterial:id,name,unit', + 'materials.rawMaterialPrice.media', + 'results.productVariant.product:id,name', + 'results.productVariant.media', + ]); + + $this->appendCostPreview($cutting); + $this->appendPhotos($cutting); + $cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m)); + + return $cutting; + } + + private function appendPhotos(Cutting $cutting): void + { $cutting->materials->each(function (CuttingMaterial $material): void { $price = $material->rawMaterialPrice; if ($price) { $price->setAttribute('images', MediaPresenter::collection($price, 'images')); } - - $this->breakMaterialCircularReference($material); }); $cutting->results->each(function (CuttingResult $result): void { @@ -207,23 +236,6 @@ public function findForEdit(Cutting $cutting): Cutting ); } }); - - return $cutting; - } - - public function findForShare(Cutting $cutting): Cutting - { - $cutting->load([ - 'createdBy.profile', - 'materials.rawMaterialPrice.rawMaterial:id,name,unit', - 'results.productVariant.product:id,name', - 'results.productVariant:id,product_id,name', - ]); - - $this->appendCostPreview($cutting); - $cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m)); - - return $cutting; } public function draftMaterialsForUser(User $user): array diff --git a/resources/js/pages/admin/manage/cuttings/Share.vue b/resources/js/pages/admin/manage/cuttings/Share.vue index d3ca33c..b961a5c 100644 --- a/resources/js/pages/admin/manage/cuttings/Share.vue +++ b/resources/js/pages/admin/manage/cuttings/Share.vue @@ -10,6 +10,7 @@ import { TableRow, } from '@/components/ui/table'; import { cuttingStatusBadgeVariant } from '@/constants/cutting-status'; +import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue'; import type { CuttingListItem } from '@/types/cutting'; const props = defineProps<{ @@ -120,13 +121,14 @@ const groupedResults = computed(() => { Varian + Foto Pemakaian