feat: add confirmation dialogs for deleting variants in ProductForm and RawMaterialForm components to enhance user experience and prevent accidental deletions
This commit is contained in:
parent
897d9c62b7
commit
4753949338
@ -3,6 +3,7 @@ import { useForm } from '@inertiajs/vue3';
|
|||||||
import { Plus, Save } from '@lucide/vue';
|
import { Plus, Save } from '@lucide/vue';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { useCan } from '@/composables/useCan';
|
import { useCan } from '@/composables/useCan';
|
||||||
@ -12,6 +13,7 @@ import type { CategoryOption, ProductFormInitialData, ProductVariantFormItem } f
|
|||||||
import ProductInfoSection from './ProductInfoSection.vue';
|
import ProductInfoSection from './ProductInfoSection.vue';
|
||||||
import ProductVariantSection from './ProductVariantSection.vue';
|
import ProductVariantSection from './ProductVariantSection.vue';
|
||||||
|
|
||||||
|
|
||||||
const { hasRole } = useCan();
|
const { hasRole } = useCan();
|
||||||
const showPrices = !hasRole('admin-bahan-baku');
|
const showPrices = !hasRole('admin-bahan-baku');
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ function createClientId(): string {
|
|||||||
return `variant-${crypto.randomUUID()}`;
|
return `variant-${crypto.randomUUID()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isUploading = computed(() =>
|
const isUploading = computed(() =>
|
||||||
variants.value.some((v) => v.media.pendingUploads > 0)
|
variants.value.some((v) => v.media.pendingUploads > 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -122,8 +124,8 @@ function copyPrices(variantPrices: Record<string, string>) {
|
|||||||
|
|
||||||
function pastePrices(clientId: string) {
|
function pastePrices(clientId: string) {
|
||||||
if (!copiedPrices.value) {
|
if (!copiedPrices.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setVariantField(clientId, 'prices', { ...copiedPrices.value });
|
setVariantField(clientId, 'prices', { ...copiedPrices.value });
|
||||||
}
|
}
|
||||||
@ -134,6 +136,23 @@ function applyToAllPrices(variantPrices: Record<string, string>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showDeleteConfirm = ref(false);
|
||||||
|
const variantToDelete = ref<string | null>(null);
|
||||||
|
|
||||||
|
function confirmRemoveVariant(clientId: string) {
|
||||||
|
variantToDelete.value = clientId;
|
||||||
|
showDeleteConfirm.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemoveVariant() {
|
||||||
|
if (variantToDelete.value) {
|
||||||
|
removeVariant(variantToDelete.value);
|
||||||
|
variantToDelete.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
showDeleteConfirm.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
name: props.initialData?.name ?? '',
|
name: props.initialData?.name ?? '',
|
||||||
description: props.initialData?.description ?? '',
|
description: props.initialData?.description ?? '',
|
||||||
@ -205,27 +224,16 @@ function submit() {
|
|||||||
<CardTitle>Informasi Produk</CardTitle>
|
<CardTitle>Informasi Produk</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ProductInfoSection
|
<ProductInfoSection :form="form" :categories="categories" :category-error="categoryError"
|
||||||
:form="form"
|
@update:name="form.name = $event" @update:description="form.description = $event"
|
||||||
:categories="categories"
|
@toggle-category="toggleCategory" />
|
||||||
:category-error="categoryError"
|
|
||||||
@update:name="form.name = $event"
|
|
||||||
@update:description="form.description = $event"
|
|
||||||
@toggle-category="toggleCategory"
|
|
||||||
/>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<ProductVariantSection
|
<ProductVariantSection v-for="(variant, index) in variants" :key="variant.client_id" :form="form"
|
||||||
v-for="(variant, index) in variants"
|
:variant="variant" :index="index" :can-remove="variants.length > 1" :has-copied-prices="!!copiedPrices"
|
||||||
:key="variant.client_id"
|
|
||||||
:form="form"
|
|
||||||
:variant="variant"
|
|
||||||
:index="index"
|
|
||||||
:can-remove="variants.length > 1"
|
|
||||||
:has-copied-prices="!!copiedPrices"
|
|
||||||
:variant-errors="(clientId, field) => variantErrors(form, clientId, field)"
|
:variant-errors="(clientId, field) => variantErrors(form, clientId, field)"
|
||||||
@remove="removeVariant(variant.client_id)"
|
@remove="confirmRemoveVariant(variant.client_id)"
|
||||||
@update:name="setVariantField(variant.client_id, 'name', $event)"
|
@update:name="setVariantField(variant.client_id, 'name', $event)"
|
||||||
@update:stock="setVariantField(variant.client_id, 'stock', $event)"
|
@update:stock="setVariantField(variant.client_id, 'stock', $event)"
|
||||||
@update:retail-stock="setVariantField(variant.client_id, 'retail_stock', $event)"
|
@update:retail-stock="setVariantField(variant.client_id, 'retail_stock', $event)"
|
||||||
@ -233,8 +241,7 @@ function submit() {
|
|||||||
@update:media="setVariantField(variant.client_id, 'media', $event)"
|
@update:media="setVariantField(variant.client_id, 'media', $event)"
|
||||||
@copy-prices="copyPrices(variant.prices as Record<string, string>)"
|
@copy-prices="copyPrices(variant.prices as Record<string, string>)"
|
||||||
@paste-prices="pastePrices(variant.client_id)"
|
@paste-prices="pastePrices(variant.client_id)"
|
||||||
@apply-to-all-prices="applyToAllPrices(variant.prices as Record<string, string>)"
|
@apply-to-all-prices="applyToAllPrices(variant.prices as Record<string, string>)" />
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between gap-2">
|
<div class="flex items-center justify-between gap-2">
|
||||||
<Button type="button" variant="outline" @click="addVariant">
|
<Button type="button" variant="outline" @click="addVariant">
|
||||||
@ -249,4 +256,8 @@ function submit() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<ConfirmDialog v-model:open="showDeleteConfirm" title="Hapus Varian?"
|
||||||
|
description="Apakah Anda yakin ingin menghapus varian ini? Tindakan ini tidak dapat dibatalkan."
|
||||||
|
confirm-label="Hapus" cancel-label="Batal" destructive @confirm="handleRemoveVariant" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useForm } from '@inertiajs/vue3';
|
|||||||
import { Plus, Save } from '@lucide/vue';
|
import { Plus, Save } from '@lucide/vue';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { FieldError } from '@/components/ui/field';
|
import { FieldError } from '@/components/ui/field';
|
||||||
import { useVariantList } from '@/composables/useVariantList';
|
import { useVariantList } from '@/composables/useVariantList';
|
||||||
@ -89,6 +90,22 @@ const {
|
|||||||
|
|
||||||
const useSamePrice = ref(prices.value.length <= 1 || allPricesHaveSameValue());
|
const useSamePrice = ref(prices.value.length <= 1 || allPricesHaveSameValue());
|
||||||
|
|
||||||
|
const showDeleteConfirm = ref(false);
|
||||||
|
const priceToDelete = ref<string | null>(null);
|
||||||
|
|
||||||
|
function confirmRemovePrice(clientId: string) {
|
||||||
|
priceToDelete.value = clientId;
|
||||||
|
showDeleteConfirm.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemovePrice() {
|
||||||
|
if (priceToDelete.value) {
|
||||||
|
removePrice(priceToDelete.value);
|
||||||
|
priceToDelete.value = null;
|
||||||
|
}
|
||||||
|
showDeleteConfirm.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
name: props.initialData?.name ?? '',
|
name: props.initialData?.name ?? '',
|
||||||
unit: props.initialData?.unit ?? '',
|
unit: props.initialData?.unit ?? '',
|
||||||
@ -196,7 +213,7 @@ function submit() {
|
|||||||
<RawMaterialVariantSection v-for="(price, index) in prices" :key="price.client_id" :form="form"
|
<RawMaterialVariantSection v-for="(price, index) in prices" :key="price.client_id" :form="form"
|
||||||
:price="price" :index="index" :total-prices="prices.length" :use-same-price="useSamePrice"
|
: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)" @apply-price-to-all="applyPriceToAllVariants(price.client_id)"
|
@remove="confirmRemovePrice(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)" />
|
||||||
@ -216,4 +233,14 @@ function submit() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
v-model:open="showDeleteConfirm"
|
||||||
|
title="Hapus Varian?"
|
||||||
|
description="Apakah Anda yakin ingin menghapus varian ini? Tindakan ini tidak dapat dibatalkan."
|
||||||
|
confirm-label="Hapus"
|
||||||
|
cancel-label="Batal"
|
||||||
|
destructive
|
||||||
|
@confirm="handleRemovePrice"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user