feat: surface listing publication blockers
Quality / test (push) Canceled after 0s

This commit is contained in:
2026-09-08 23:20:31 -04:00
parent 370e4721ed
commit ea145191df
3 changed files with 20 additions and 5 deletions
@@ -40,7 +40,14 @@ export function createListingService({ listingRepository, inventoryImageReposito
},
async list({ sellerId }) {
return listingRepository.listBySellerId(sellerId);
const listings = await listingRepository.listBySellerId(sellerId);
if (!inventoryImageRepository) return listings;
return Promise.all(listings.map(async (listing) => ({
...listing,
imageCount: await inventoryImageRepository.countByInventoryItemId(listing.inventoryItemId),
inventoryStatus: listing.inventoryStatus ?? 'ACTIVE',
})));
},
};
}
@@ -1,11 +1,17 @@
<script setup>
defineProps({
import { computed } from 'vue';
const props = defineProps({
listing: { type: Object, required: true },
blockers: { type: Array, default: () => [] },
isSaving: { type: Boolean, default: false },
errorMessage: { type: String, default: '' },
});
defineEmits(['publish', 'pending']);
const computedBlockers = computed(() => props.blockers.length ? props.blockers : [
...(props.listing.status === 'DRAFT' && props.listing.imageCount < 1 ? ['Add at least one image before publishing.'] : []),
...(props.listing.inventoryStatus === 'SOLD' || props.listing.inventoryStatus === 'ARCHIVED' ? ['Sold or archived inventory cannot be published.'] : []),
]);
</script>
<template>
@@ -16,12 +22,12 @@ defineEmits(['publish', 'pending']);
<span class="fixture-label">${{ (listing.askingPriceMinor / 100).toFixed(2) }}</span>
</div>
<span class="status" :class="`status--${listing.status.toLowerCase()}`">{{ listing.status }}</span>
<ul v-if="blockers.length" class="admin-listing-status__blockers" aria-label="Publication blockers">
<li v-for="blocker in blockers" :key="blocker">{{ blocker }}</li>
<ul v-if="computedBlockers.length" class="admin-listing-status__blockers" aria-label="Publication blockers">
<li v-for="blocker in computedBlockers" :key="blocker">{{ blocker }}</li>
</ul>
<p v-if="errorMessage" class="state state--error" role="alert">{{ errorMessage }}</p>
<div class="admin-listing-status__actions">
<button v-if="listing.status === 'DRAFT'" class="button button--primary" type="button" :disabled="isSaving || blockers.length > 0" @click="$emit('publish')">{{ isSaving ? 'Publishing...' : 'Publish' }}</button>
<button v-if="listing.status === 'DRAFT'" class="button button--primary" type="button" :disabled="isSaving || computedBlockers.length > 0" @click="$emit('publish')">{{ isSaving ? 'Publishing...' : 'Publish' }}</button>
<button v-if="listing.status === 'DRAFT'" class="button button--secondary" type="button" :disabled="isSaving" @click="$emit('pending')">Mark pending</button>
</div>
</article>
+2
View File
@@ -12,6 +12,8 @@ export function toAdminListingDto(listing) {
askingPriceMinor: listing.askingPriceMinor,
status: listing.status,
notes: listing.notes ?? null,
imageCount: listing.imageCount ?? 0,
inventoryStatus: listing.inventoryStatus ?? null,
createdAt: toIsoString(listing.createdAt),
updatedAt: toIsoString(listing.updatedAt),
};