This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
.review-list-step {
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.review-list-step__intro {
|
||||
margin: var(--space-2) 0 0;
|
||||
color: var(--color-text-muted);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import ReviewListStep from './ReviewListStep.vue';
|
||||
|
||||
export default { title: 'Molecules/ReviewListStep', component: ReviewListStep };
|
||||
|
||||
const inventory = [
|
||||
{ id: 'copy-1', status: 'ACTIVE' },
|
||||
{ id: 'copy-2', status: 'ARCHIVED' },
|
||||
];
|
||||
|
||||
export const Ready = {
|
||||
args: { inventoryItemId: 'copy-1', askingPrice: '2499', inventory, isSaving: false },
|
||||
};
|
||||
|
||||
export const Empty = {
|
||||
args: { inventoryItemId: '', askingPrice: '', inventory, isSaving: false },
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
inventoryItemId: { type: String, required: true },
|
||||
askingPrice: { type: String, required: true },
|
||||
inventory: { type: Array, required: true },
|
||||
isSaving: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
defineEmits(['update:inventoryItemId', 'update:askingPrice', 'submit']);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="workflow-listing" class="showcase-panel review-list-step" @submit.prevent="$emit('submit')">
|
||||
<div>
|
||||
<p class="catalog-kicker">Step 6</p>
|
||||
<h2>Review and List</h2>
|
||||
<p class="review-list-step__intro">Confirm the physical copy and asking price. Images, condition, and product identity are checked before publishing.</p>
|
||||
</div>
|
||||
<label class="fixture-label" for="listing-inventory">Inventory copy</label>
|
||||
<select
|
||||
id="listing-inventory"
|
||||
:value="inventoryItemId"
|
||||
class="fixture-input"
|
||||
required
|
||||
@change="$emit('update:inventoryItemId', $event.target.value)"
|
||||
>
|
||||
<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"
|
||||
:value="askingPrice"
|
||||
class="fixture-input"
|
||||
type="number"
|
||||
min="1"
|
||||
required
|
||||
@input="$emit('update:askingPrice', $event.target.value)"
|
||||
/>
|
||||
<button class="button button--primary" type="submit" :disabled="isSaving">
|
||||
Create listing draft
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use './ReviewListStep.scss';
|
||||
</style>
|
||||
@@ -9,6 +9,7 @@ import ProviderMappingStep from "@/components/molecules/ProviderMappingStep.vue"
|
||||
import InventoryCopyStep from "@/components/molecules/InventoryCopyStep.vue";
|
||||
import InventoryImagesStep from "@/components/molecules/InventoryImagesStep.vue";
|
||||
import PricingReviewStep from "@/components/molecules/PricingReviewStep.vue";
|
||||
import ReviewListStep from "@/components/molecules/ReviewListStep.vue";
|
||||
import {
|
||||
createAdminInventory,
|
||||
createAdminProduct,
|
||||
@@ -714,41 +715,15 @@ onMounted(load);
|
||||
@update:condition-id="conditionId = $event"
|
||||
@submit="createInventory"
|
||||
/>
|
||||
<form id="workflow-listing" 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
|
||||
<ReviewListStep
|
||||
:inventory-item-id="listingInventoryId"
|
||||
:asking-price="askingPrice"
|
||||
:inventory="inventory"
|
||||
:is-saving="isSaving"
|
||||
@update:inventory-item-id="listingInventoryId = $event"
|
||||
@update:asking-price="askingPrice = $event"
|
||||
@submit="createListing"
|
||||
/>
|
||||
<button
|
||||
class="button button--primary"
|
||||
type="submit"
|
||||
:disabled="isSaving"
|
||||
>
|
||||
Create listing
|
||||
</button>
|
||||
</form>
|
||||
<form class="showcase-panel" @submit.prevent="recordSale">
|
||||
<h2>Record sale</h2>
|
||||
<label class="fixture-label" for="sale-inventory">Inventory copy</label>
|
||||
|
||||
@@ -172,6 +172,8 @@ Remaining roadmap areas are approved external provider credentials/adapters, bro
|
||||
- Physical inventory creation is now an extracted `InventoryCopyStep` molecule with Product and condition selection states, while preserving the existing seller-scoped create-copy API workflow.
|
||||
- Image management is now surfaced as an extracted `InventoryImagesStep` molecule with missing-image status and direct links to the existing upload/processing manager route.
|
||||
- Pricing is now an extracted `PricingReviewStep` molecule covering observations, provider refresh, and reasoned manual overrides while preserving existing pricing API behavior.
|
||||
- Review and listing is now an extracted `ReviewListStep` molecule covering physical-copy selection and asking-price confirmation while preserving existing draft creation and publication lifecycle behavior.
|
||||
- The guided inventory workflow now has extracted Product, Source Mapping, Physical Copy, Images, Pricing, and Review/List frontend stages, each with colocated Storybook coverage.
|
||||
- Public catalog sorting now supports latest manual/calculated market value low-to-high and high-to-low, with null values placed last.
|
||||
- Public catalog filters now collapse behind an accessible mobile disclosure, show an active-filter count, and provide a reset action while preserving URL synchronization.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user