This commit is contained in:
@@ -4,10 +4,12 @@ import { RouterLink } from 'vue-router';
|
||||
|
||||
import { useAuth } from '@/composables/useAuth.js';
|
||||
import { createAdminInventory, createAdminProduct, listAdminCategories, listAdminConditions, listAdminInventory, listAdminProducts } from '@/services/admin-catalog-service.js';
|
||||
import { createAdminListing, listAdminListings, markListingPending, publishAdminListing } from '@/services/admin-listing-service.js';
|
||||
|
||||
const { principal } = useAuth();
|
||||
const products = ref([]);
|
||||
const inventory = ref([]);
|
||||
const listings = ref([]);
|
||||
const categories = ref([]);
|
||||
const conditions = ref([]);
|
||||
const isLoading = ref(true);
|
||||
@@ -17,6 +19,8 @@ const productName = ref('');
|
||||
const categoryId = ref('');
|
||||
const inventoryProductId = ref('');
|
||||
const conditionId = ref('');
|
||||
const listingInventoryId = ref('');
|
||||
const askingPrice = ref('');
|
||||
|
||||
function csrfToken() {
|
||||
return document.cookie.split('; ').find((value) => value.startsWith('pokemon_inventory_csrf='))?.split('=')[1] ?? '';
|
||||
@@ -25,7 +29,7 @@ function csrfToken() {
|
||||
async function load() {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
[products.value, inventory.value, categories.value, conditions.value] = await Promise.all([listAdminProducts(), listAdminInventory(), listAdminCategories(), listAdminConditions()]);
|
||||
[products.value, inventory.value, categories.value, conditions.value, listings.value] = await Promise.all([listAdminProducts(), listAdminInventory(), listAdminCategories(), listAdminConditions(), listAdminListings()]);
|
||||
} catch (requestError) { error.value = requestError; }
|
||||
finally { isLoading.value = false; }
|
||||
}
|
||||
@@ -49,6 +53,27 @@ async function createInventory() {
|
||||
finally { isSaving.value = false; }
|
||||
}
|
||||
|
||||
async function createListing() {
|
||||
const item = inventory.value.find((candidate) => candidate.id === listingInventoryId.value);
|
||||
const product = products.value.find((candidate) => candidate.id === item?.productId);
|
||||
isSaving.value = true;
|
||||
try {
|
||||
const listing = await createAdminListing({ inventoryItemId: item.id, productName: product.name, categoryId: product.categoryId, conditionId: item.conditionId, askingPriceMinor: Number(askingPrice.value) }, csrfToken());
|
||||
listings.value.push(listing);
|
||||
askingPrice.value = '';
|
||||
} catch (requestError) { error.value = requestError; }
|
||||
finally { isSaving.value = false; }
|
||||
}
|
||||
|
||||
async function transitionListing(action, id) {
|
||||
isSaving.value = true;
|
||||
try {
|
||||
const listing = await action(id, csrfToken());
|
||||
listings.value = listings.value.map((candidate) => candidate.id === listing.id ? listing : candidate);
|
||||
} catch (requestError) { error.value = requestError; }
|
||||
finally { isSaving.value = false; }
|
||||
}
|
||||
|
||||
onMounted(load);
|
||||
</script>
|
||||
|
||||
@@ -86,6 +111,17 @@ onMounted(load);
|
||||
</select>
|
||||
<button class="button button--primary" type="submit" :disabled="isSaving">Create copy</button>
|
||||
</form>
|
||||
<form class="showcase-panel" @submit.prevent="createListing">
|
||||
<h2>Create listing draft</h2>
|
||||
<label class="fixture-label" for="listing-inventory">Inventory copy</label>
|
||||
<select id="listing-inventory" v-model="listingInventoryId" class="fixture-input" required>
|
||||
<option value="" disabled>Select a physical copy</option>
|
||||
<option v-for="item in inventory" :key="item.id" :value="item.id">{{ item.id }} · {{ item.status }}</option>
|
||||
</select>
|
||||
<label class="fixture-label" for="listing-price">Asking price (cents)</label>
|
||||
<input id="listing-price" v-model="askingPrice" class="fixture-input" type="number" min="1" required />
|
||||
<button class="button button--primary" type="submit" :disabled="isSaving">Create listing</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<section class="admin-list" aria-labelledby="products-title">
|
||||
@@ -98,5 +134,10 @@ onMounted(load);
|
||||
<p v-if="!inventory.length && !isLoading" class="state state--empty">No physical copies yet.</p>
|
||||
<ul v-else><li v-for="item in inventory" :key="item.id"><span>{{ item.id }}</span> · {{ item.status }} <RouterLink :to="{ name: 'admin-image-manager', params: { id: item.id } }">Manage images</RouterLink></li></ul>
|
||||
</section>
|
||||
<section class="admin-list" aria-labelledby="listings-title">
|
||||
<h2 id="listings-title">Listings</h2>
|
||||
<p v-if="!listings.length && !isLoading" class="state state--empty">No listings yet.</p>
|
||||
<ul v-else><li v-for="listing in listings" :key="listing.id"><span>{{ listing.productName }}</span> · {{ listing.status }} · ${{ (listing.askingPriceMinor / 100).toFixed(2) }} <button v-if="listing.status === 'DRAFT'" class="button button--secondary" type="button" @click="transitionListing(publishAdminListing, listing.id)">Publish</button><button v-if="listing.status === 'DRAFT'" class="button button--secondary" type="button" @click="transitionListing(markListingPending, listing.id)">Mark pending</button></li></ul>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user