159 lines
5.3 KiB
Vue
159 lines
5.3 KiB
Vue
<template>
|
|
<section class="container-page py-10">
|
|
<div class="mb-8">
|
|
<h1 class="text-3xl font-extrabold">Jual Barang</h1>
|
|
<p class="mt-2 text-slate-600">Posting barang ke marketplace dengan beberapa foto asli dari perangkatmu.</p>
|
|
</div>
|
|
|
|
<div class="grid gap-8 lg:grid-cols-[1fr_360px]">
|
|
<form class="card grid gap-5 p-6" @submit.prevent="submitProduct">
|
|
<p v-if="errorMessage" class="rounded-xl bg-red-50 px-4 py-3 text-sm font-semibold text-red-700">
|
|
{{ errorMessage }}
|
|
</p>
|
|
|
|
<div>
|
|
<label class="label">Nama Barang</label>
|
|
<input v-model="form.title" class="input mt-2" placeholder="Contoh: Laptop ThinkPad T480" required />
|
|
</div>
|
|
|
|
<div class="grid gap-5 sm:grid-cols-2">
|
|
<div>
|
|
<label class="label">Kategori</label>
|
|
<select v-model="form.category" class="input mt-2" required>
|
|
<option v-for="cat in realCategories" :key="cat" :value="cat">{{ cat }}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="label">Harga</label>
|
|
<input v-model.number="form.price" type="number" class="input mt-2" placeholder="2500000" required />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-5 sm:grid-cols-2">
|
|
<div>
|
|
<label class="label">Kondisi</label>
|
|
<select v-model="form.condition" class="input mt-2">
|
|
<option>Bekas Normal</option>
|
|
<option>Bekas Mulus</option>
|
|
<option>Bekas Minus</option>
|
|
<option>Bekas Server Room</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="label">Lokasi</label>
|
|
<input v-model="form.location" class="input mt-2" placeholder="Yogyakarta" required />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-5 sm:grid-cols-2">
|
|
<div>
|
|
<label class="label">Nama Penjual</label>
|
|
<input v-model="form.seller" class="input mt-2" placeholder="Nama kamu" required />
|
|
</div>
|
|
<div>
|
|
<label class="label">Nomor WhatsApp</label>
|
|
<input v-model="form.whatsapp" class="input mt-2" placeholder="6281234567890" required />
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="label">Foto Barang</label>
|
|
<input type="file" accept="image/*" multiple class="input mt-2" required @change="handleImageChange" />
|
|
|
|
<div v-if="previewUrls.length" class="mt-4 grid grid-cols-2 gap-3 sm:grid-cols-3">
|
|
<div v-for="preview in previewUrls" :key="preview" class="overflow-hidden rounded-xl border border-slate-200">
|
|
<img :src="preview" alt="Preview foto barang" class="aspect-[4/3] w-full object-cover" />
|
|
</div>
|
|
</div>
|
|
|
|
<p class="mt-2 text-xs text-slate-500">Upload maksimal 6 foto. Foto pertama menjadi foto utama.</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="label">Deskripsi</label>
|
|
<textarea v-model="form.description" class="input mt-2 min-h-32" placeholder="Jelaskan kondisi barang..." required></textarea>
|
|
</div>
|
|
|
|
<button class="btn-primary w-full" :disabled="loading">
|
|
{{ loading ? "Memposting..." : "Posting Barang" }}
|
|
</button>
|
|
</form>
|
|
|
|
<div class="card h-fit p-6">
|
|
<h2 class="text-lg font-extrabold">Tips Isi Produk</h2>
|
|
<ul class="mt-4 grid gap-3 text-sm leading-6 text-slate-600">
|
|
<li>- Pakai judul yang jelas, misal "MikroTik RB941 Bekas Normal".</li>
|
|
<li>- Jelaskan minus barang kalau ada.</li>
|
|
<li>- Pakai nomor WhatsApp aktif.</li>
|
|
<li>- Upload beberapa foto dari sisi yang berbeda.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { reactive, computed, ref } from "vue"
|
|
import { useRouter } from "vue-router"
|
|
import { categories } from "../data/products"
|
|
import { createProduct, getCurrentUser } from "../utils"
|
|
|
|
const router = useRouter()
|
|
const realCategories = computed(() => categories.filter((cat) => cat !== "Semua"))
|
|
|
|
const form = reactive({
|
|
title: "",
|
|
category: "Laptop",
|
|
price: "",
|
|
condition: "Bekas Normal",
|
|
location: "",
|
|
seller: "",
|
|
whatsapp: "",
|
|
description: ""
|
|
})
|
|
const selectedImages = ref([])
|
|
const previewUrls = ref([])
|
|
const loading = ref(false)
|
|
const errorMessage = ref("")
|
|
|
|
const currentUser = getCurrentUser()
|
|
if (currentUser) {
|
|
form.seller = currentUser.name || ""
|
|
form.whatsapp = currentUser.whatsapp || ""
|
|
}
|
|
|
|
function handleImageChange(event) {
|
|
const files = Array.from(event.target.files || []).slice(0, 6)
|
|
selectedImages.value = files
|
|
previewUrls.value.forEach((url) => URL.revokeObjectURL(url))
|
|
previewUrls.value = files.map((file) => URL.createObjectURL(file))
|
|
}
|
|
|
|
async function submitProduct() {
|
|
if (!selectedImages.value.length) {
|
|
errorMessage.value = "Minimal 1 foto barang wajib diupload."
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
errorMessage.value = ""
|
|
|
|
const payload = new FormData()
|
|
Object.entries(form).forEach(([key, value]) => {
|
|
payload.append(key, value)
|
|
})
|
|
selectedImages.value.forEach((image) => {
|
|
payload.append("images", image)
|
|
})
|
|
|
|
try {
|
|
await createProduct(payload)
|
|
router.push("/dashboard")
|
|
} catch (error) {
|
|
errorMessage.value = error.message
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
</script>
|