refactor: enhance component structure in various forms by introducing computed properties and improving template syntax for better readability and maintainability
This commit is contained in:
parent
b78d512197
commit
4eea267756
@ -1,13 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Plus, Save } from '@lucide/vue';
|
import { Plus, Save } from '@lucide/vue';
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { apiFetch } from '@/lib/api';
|
|
||||||
import { useVariantList } from '@/composables/useVariantList';
|
|
||||||
import { appendMediaToFormData, createMediaUploadState } from '@/types/media';
|
|
||||||
import { formErrors } from '@/lib/form';
|
|
||||||
import { parseRupiah } from '@/lib/rupiah';
|
|
||||||
import type { EnumOption, RawMaterialPriceFormItem } from '@/types/raw-material';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -16,10 +10,16 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { FieldError } from '@/components/ui/field';
|
import { FieldError } from '@/components/ui/field';
|
||||||
|
import { useVariantList } from '@/composables/useVariantList';
|
||||||
|
import { apiFetch } from '@/lib/api';
|
||||||
|
import { formErrors } from '@/lib/form';
|
||||||
|
import { parseRupiah } from '@/lib/rupiah';
|
||||||
import RawMaterialInfoSection from '@/pages/admin/master/raw-materials/form/RawMaterialInfoSection.vue';
|
import RawMaterialInfoSection from '@/pages/admin/master/raw-materials/form/RawMaterialInfoSection.vue';
|
||||||
import RawMaterialSharedPriceSection from '@/pages/admin/master/raw-materials/form/RawMaterialSharedPriceSection.vue';
|
import RawMaterialSharedPriceSection from '@/pages/admin/master/raw-materials/form/RawMaterialSharedPriceSection.vue';
|
||||||
import RawMaterialVariantSection from '@/pages/admin/master/raw-materials/form/RawMaterialVariantSection.vue';
|
import RawMaterialVariantSection from '@/pages/admin/master/raw-materials/form/RawMaterialVariantSection.vue';
|
||||||
import type { CuttingRawMaterialCatalogItem } from '@/types/cutting';
|
import type { CuttingRawMaterialCatalogItem } from '@/types/cutting';
|
||||||
|
import { appendMediaToFormData, createMediaUploadState } from '@/types/media';
|
||||||
|
import type { EnumOption, RawMaterialPriceFormItem } from '@/types/raw-material';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
units: EnumOption[];
|
units: EnumOption[];
|
||||||
@ -34,7 +34,7 @@ const emit = defineEmits<{
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const selectPortalTarget = ref<HTMLElement>();
|
const selectPortalTarget = ref<HTMLElement>();
|
||||||
|
|
||||||
const isUploading = computed(() =>
|
const isUploading = computed(() =>
|
||||||
prices.value.some((p) => p.media.pendingUploads > 0)
|
prices.value.some((p) => p.media.pendingUploads > 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -190,31 +190,20 @@ async function submit() {
|
|||||||
|
|
||||||
<div class="scrollbar-thin flex-1 overflow-y-auto pr-1">
|
<div class="scrollbar-thin flex-1 overflow-y-auto pr-1">
|
||||||
<form id="quick-create-raw-material-form" @submit.prevent="submit" class="space-y-6">
|
<form id="quick-create-raw-material-form" @submit.prevent="submit" class="space-y-6">
|
||||||
<RawMaterialInfoSection :form="form" :units="units" method="post" :select-portal-target="selectPortalTarget" />
|
<RawMaterialInfoSection :form="form" :units="units" method="post"
|
||||||
|
:select-portal-target="selectPortalTarget" />
|
||||||
|
|
||||||
<RawMaterialSharedPriceSection
|
<RawMaterialSharedPriceSection :form="form" :prices="prices" :use-same-price="useSamePrice"
|
||||||
:form="form"
|
@toggle-use-same-price="toggleUseSamePrice" @set-shared-price="setSharedPrice" />
|
||||||
:prices="prices"
|
|
||||||
:use-same-price="useSamePrice"
|
|
||||||
@toggle-use-same-price="toggleUseSamePrice"
|
|
||||||
@set-shared-price="setSharedPrice"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<RawMaterialVariantSection
|
<RawMaterialVariantSection v-for="(price, index) in prices" :key="price.client_id" :form="form"
|
||||||
v-for="(price, index) in prices"
|
:price="price" :index="index" :total-prices="prices.length" :use-same-price="useSamePrice"
|
||||||
:key="price.client_id"
|
|
||||||
:form="form"
|
|
||||||
:price="price"
|
|
||||||
:index="index"
|
|
||||||
:total-prices="prices.length"
|
|
||||||
:use-same-price="useSamePrice"
|
|
||||||
:price-errors="(clientId, field) => priceErrors(form, clientId, field)"
|
:price-errors="(clientId, field) => priceErrors(form, clientId, field)"
|
||||||
@remove="removePrice(price.client_id)"
|
@remove="removePrice(price.client_id)"
|
||||||
@apply-price-to-all="applyPriceToAllVariants(price.client_id)"
|
@apply-price-to-all="applyPriceToAllVariants(price.client_id)"
|
||||||
@update:variant="setPriceField(price.client_id, 'variant', $event)"
|
@update:variant="setPriceField(price.client_id, 'variant', $event)"
|
||||||
@update:stock="setPriceField(price.client_id, 'stock', $event)"
|
@update:stock="setPriceField(price.client_id, 'stock', $event)"
|
||||||
@update:price="setPriceValue(price.client_id, $event)"
|
@update:price="setPriceValue(price.client_id, $event)" />
|
||||||
/>
|
|
||||||
|
|
||||||
<FieldError :errors="formErrors(form, 'prices')" />
|
<FieldError :errors="formErrors(form, 'prices')" />
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Save } from '@lucide/vue';
|
import { Save } from '@lucide/vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||||
import MediaDropzone from '@/components/media/MediaDropzone.vue';
|
import MediaDropzone from '@/components/media/MediaDropzone.vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@ -71,11 +72,8 @@ const isUploading = computed(() => photoState.value.pendingUploads > 0);
|
|||||||
|
|
||||||
<Field v-if="canComplete">
|
<Field v-if="canComplete">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<Switch
|
<Switch id="status-completed" :model-value="form.status === OrderStatus.COMPLETED"
|
||||||
id="status-completed"
|
@update:model-value="form.status = $event ? OrderStatus.COMPLETED : OrderStatus.PENDING" />
|
||||||
:model-value="form.status === OrderStatus.COMPLETED"
|
|
||||||
@update:model-value="form.status = $event ? OrderStatus.COMPLETED : OrderStatus.PENDING"
|
|
||||||
/>
|
|
||||||
<Label for="status-completed" class="cursor-pointer text-sm">
|
<Label for="status-completed" class="cursor-pointer text-sm">
|
||||||
Pesanan selesai
|
Pesanan selesai
|
||||||
</Label>
|
</Label>
|
||||||
@ -92,15 +90,8 @@ const isUploading = computed(() => photoState.value.pendingUploads > 0);
|
|||||||
<FieldError :errors="formErrors(form, 'notes')" />
|
<FieldError :errors="formErrors(form, 'notes')" />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<MediaDropzone
|
<MediaDropzone v-if="showPhotoInput" id="order-photos" v-model="photoState" label="Bukti Transaksi" :max-files="1"
|
||||||
v-if="showPhotoInput"
|
required :errors="formErrors(form, 'photos')" />
|
||||||
id="order-photos"
|
|
||||||
v-model="photoState"
|
|
||||||
label="Bukti Transaksi"
|
|
||||||
:max-files="1"
|
|
||||||
required
|
|
||||||
:errors="formErrors(form, 'photos')"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field v-if="isCreateMode && canCreate">
|
<Field v-if="isCreateMode && canCreate">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
@ -112,16 +103,12 @@ const isUploading = computed(() => photoState.value.pendingUploads > 0);
|
|||||||
<div v-if="printAfterSave" class="mt-2 flex items-center gap-2 pl-1">
|
<div v-if="printAfterSave" class="mt-2 flex items-center gap-2 pl-1">
|
||||||
<span class="text-xs text-muted-foreground">Ukuran kertas:</span>
|
<span class="text-xs text-muted-foreground">Ukuran kertas:</span>
|
||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
<button
|
<button v-for="size in ([PaperSize.MM_58, PaperSize.MM_80] as const)" :key="size" type="button"
|
||||||
v-for="size in ([PaperSize.MM_58, PaperSize.MM_80] as const)"
|
|
||||||
:key="size"
|
|
||||||
type="button"
|
|
||||||
class="inline-flex h-7 cursor-pointer items-center rounded-md border px-2.5 text-xs font-medium transition-colors"
|
class="inline-flex h-7 cursor-pointer items-center rounded-md border px-2.5 text-xs font-medium transition-colors"
|
||||||
:class="selectedPaperSize === size
|
:class="selectedPaperSize === size
|
||||||
? 'border-primary bg-primary/5 text-primary'
|
? 'border-primary bg-primary/5 text-primary'
|
||||||
: 'border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground'"
|
: 'border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground'"
|
||||||
@click="selectedPaperSize = size"
|
@click="selectedPaperSize = size">
|
||||||
>
|
|
||||||
{{ size }}
|
{{ size }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { DecimalInput } from '@/components/form/decimal-input';
|
import { DecimalInput } from '@/components/form/decimal-input';
|
||||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
import { Save } from '@lucide/vue';
|
import { Save } from '@lucide/vue';
|
||||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||||
import MediaDropzone from '@/components/media/MediaDropzone.vue';
|
import MediaDropzone from '@/components/media/MediaDropzone.vue';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useForm } from '@inertiajs/vue3';
|
import { useForm } from '@inertiajs/vue3';
|
||||||
import { Plus, Save } from '@lucide/vue';
|
import { Plus, Save } from '@lucide/vue';
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { FieldError } from '@/components/ui/field';
|
import { FieldError } from '@/components/ui/field';
|
||||||
@ -46,7 +46,7 @@ function createClientId(): string {
|
|||||||
return `price-${crypto.randomUUID()}`;
|
return `price-${crypto.randomUUID()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isUploading = computed(() =>
|
const isUploading = computed(() =>
|
||||||
prices.value.some((p) => p.media.pendingUploads > 0)
|
prices.value.some((p) => p.media.pendingUploads > 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -190,29 +190,16 @@ function submit() {
|
|||||||
<div class="grid gap-6">
|
<div class="grid gap-6">
|
||||||
<RawMaterialInfoSection :form="form" :units="units" :method="method" />
|
<RawMaterialInfoSection :form="form" :units="units" :method="method" />
|
||||||
|
|
||||||
<RawMaterialSharedPriceSection
|
<RawMaterialSharedPriceSection :form="form" :prices="prices" :use-same-price="useSamePrice"
|
||||||
:form="form"
|
@toggle-use-same-price="toggleUseSamePrice" @set-shared-price="setSharedPrice" />
|
||||||
:prices="prices"
|
|
||||||
:use-same-price="useSamePrice"
|
|
||||||
@toggle-use-same-price="toggleUseSamePrice"
|
|
||||||
@set-shared-price="setSharedPrice"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<RawMaterialVariantSection
|
<RawMaterialVariantSection v-for="(price, index) in prices" :key="price.client_id" :form="form"
|
||||||
v-for="(price, index) in prices"
|
:price="price" :index="index" :total-prices="prices.length" :use-same-price="useSamePrice"
|
||||||
:key="price.client_id"
|
|
||||||
:form="form"
|
|
||||||
:price="price"
|
|
||||||
:index="index"
|
|
||||||
:total-prices="prices.length"
|
|
||||||
:use-same-price="useSamePrice"
|
|
||||||
:price-errors="(clientId, field) => priceErrors(form, clientId, field)"
|
:price-errors="(clientId, field) => priceErrors(form, clientId, field)"
|
||||||
@remove="removePrice(price.client_id)"
|
@remove="removePrice(price.client_id)" @apply-price-to-all="applyPriceToAllVariants(price.client_id)"
|
||||||
@apply-price-to-all="applyPriceToAllVariants(price.client_id)"
|
|
||||||
@update:variant="setPriceField(price.client_id, 'variant', $event)"
|
@update:variant="setPriceField(price.client_id, 'variant', $event)"
|
||||||
@update:stock="setPriceField(price.client_id, 'stock', $event)"
|
@update:stock="setPriceField(price.client_id, 'stock', $event)"
|
||||||
@update:price="setPriceValue(price.client_id, $event)"
|
@update:price="setPriceValue(price.client_id, $event)" />
|
||||||
/>
|
|
||||||
|
|
||||||
<FieldError :errors="formErrors(form, 'prices')" />
|
<FieldError :errors="formErrors(form, 'prices')" />
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { router } from '@inertiajs/vue3';
|
import { router } from '@inertiajs/vue3';
|
||||||
import { Save } from '@lucide/vue';
|
import { Save } from '@lucide/vue';
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import MediaDropzone from '@/components/media/MediaDropzone.vue';
|
import MediaDropzone from '@/components/media/MediaDropzone.vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user