store/resources/js/components/modal/StockRetailTransferModal.vue

178 lines
6.1 KiB
Vue

<script setup lang="ts">
import { ArrowLeftRight, Save } from '@lucide/vue';
import { reactive, ref, watch } from 'vue';
import { toast } from 'vue-sonner';
import { NumberInput } from '@/components/form/number-input';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import {
Field,
FieldError,
FieldGroup,
FieldLabel,
FieldSet,
} from '@/components/ui/field';
import { Textarea } from '@/components/ui/textarea';
import { apiFetch } from '@/lib/api';
import { transfer } from '@/routes/admin/manage/stock-retail';
const open = defineModel<boolean>('open', { default: false });
const props = defineProps<{
variantId: number;
variantName: string;
productName: string;
stockBagus: number;
stockRetail: number;
}>();
const emit = defineEmits<{
submitted: [];
}>();
const processing = ref(false);
const errors = reactive<Record<string, string>>({});
const form = reactive({
quantity: '',
notes: '',
});
function resetForm() {
form.quantity = '';
form.notes = '';
Object.keys(errors).forEach((key) => delete errors[key]);
}
watch(open, (isOpen) => {
if (isOpen) {
resetForm();
}
});
async function submit() {
Object.keys(errors).forEach((key) => delete errors[key]);
processing.value = true;
try {
await apiFetch(transfer.url(), {
method: 'POST',
body: JSON.stringify({
product_variant_id: props.variantId,
quantity: Number(form.quantity),
notes: form.notes || null,
}),
});
emit('submitted');
open.value = false;
toast.success('Pengajuan transfer stok ecer berhasil dikirim. Menunggu verifikasi owner.');
} catch (error) {
const message =
error instanceof Error ? error.message : 'Gagal menyimpan data.';
if (message.includes('jumlah') || message.includes('Jumlah')) {
errors.quantity = message;
} else if (message.includes('Stok')) {
errors.quantity = message;
} else if (message.includes('pengajuan') || message.includes('menunggu')) {
errors.quantity = message;
} else {
toast.error(message);
}
} finally {
processing.value = false;
}
}
function formatNumber(value: number): string {
return value.toLocaleString('id-ID');
}
</script>
<template>
<Dialog v-model:open="open">
<DialogContent class="sm:max-w-md">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<ArrowLeftRight class="size-5" />
Transfer Stok Ecer
</DialogTitle>
</DialogHeader>
<div class="space-y-4">
<div class="rounded-lg border p-3 space-y-1.5">
<p class="text-sm font-medium">{{ productName }}</p>
<p class="text-xs text-muted-foreground">Varian: {{ variantName }}</p>
<div class="flex justify-between text-xs pt-1">
<span class="text-muted-foreground">Stok Bagus</span>
<span class="font-medium tabular-nums">{{ formatNumber(stockBagus) }}</span>
</div>
<div class="flex justify-between text-xs">
<span class="text-muted-foreground">Stok Ecer</span>
<span class="font-medium tabular-nums text-blue-600">{{ formatNumber(stockRetail) }}</span>
</div>
</div>
<p class="text-xs text-amber-600 bg-amber-50 border border-amber-200 rounded-md px-3 py-2">
Transfer stok memerlukan persetujuan owner. Stok akan berubah setelah disetujui.
</p>
<form @submit.prevent="submit">
<FieldGroup>
<FieldSet class="grid gap-4">
<Field>
<FieldLabel for="retail-quantity" required>Jumlah Transfer</FieldLabel>
<NumberInput
id="retail-quantity"
v-model="form.quantity"
:max="stockBagus"
placeholder="Masukkan jumlah"
/>
<p class="text-xs text-muted-foreground mt-1">
Maksimal: {{ formatNumber(stockBagus) }} pcs
</p>
<FieldError
v-if="errors.quantity"
:errors="[errors.quantity]"
/>
</Field>
<Field>
<FieldLabel for="retail-notes">Catatan</FieldLabel>
<Textarea
id="retail-notes"
v-model="form.notes"
rows="2"
placeholder="Contoh: Transfer untuk kebutuhan kasir"
/>
</Field>
</FieldSet>
</FieldGroup>
<DialogFooter class="mt-6">
<Button
type="button"
variant="outline"
:disabled="processing"
@click="open = false"
>
Batal
</Button>
<Button type="submit" :disabled="processing || !form.quantity || Number(form.quantity) < 1">
<Save class="size-4" />
{{ processing ? 'Mengirim...' : 'Ajukan Transfer' }}
</Button>
</DialogFooter>
</form>
</div>
</DialogContent>
</Dialog>
</template>