This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
.pricing-review-step {
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pricing-review-step__intro {
|
||||||
|
margin: var(--space-2) 0 0;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import PricingReviewStep from './PricingReviewStep.vue';
|
||||||
|
|
||||||
|
export default { title: 'Molecules/PricingReviewStep', component: PricingReviewStep };
|
||||||
|
|
||||||
|
const inventory = [{ id: 'copy-1' }, { id: 'copy-2' }];
|
||||||
|
|
||||||
|
export const Empty = {
|
||||||
|
args: {
|
||||||
|
inventoryItemId: '', provider: 'fixture-provider', sourceIdentifier: '', observedPrice: '',
|
||||||
|
overridePrice: '', overrideReason: '', inventory, refreshStatus: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Refreshing = {
|
||||||
|
args: {
|
||||||
|
inventoryItemId: 'copy-1', provider: 'fixture-provider', sourceIdentifier: 'fixture-copy-1', observedPrice: '2500',
|
||||||
|
overridePrice: '', overrideReason: '', inventory, refreshStatus: 'PROCESSING', isSaving: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
inventoryItemId: { type: String, required: true },
|
||||||
|
provider: { type: String, required: true },
|
||||||
|
sourceIdentifier: { type: String, required: true },
|
||||||
|
observedPrice: { type: String, required: true },
|
||||||
|
overridePrice: { type: String, required: true },
|
||||||
|
overrideReason: { type: String, required: true },
|
||||||
|
inventory: { type: Array, required: true },
|
||||||
|
refreshStatus: { type: String, default: '' },
|
||||||
|
isSaving: { type: Boolean, default: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
defineEmits([
|
||||||
|
'update:inventoryItemId',
|
||||||
|
'update:provider',
|
||||||
|
'update:sourceIdentifier',
|
||||||
|
'update:observedPrice',
|
||||||
|
'update:overridePrice',
|
||||||
|
'update:overrideReason',
|
||||||
|
'calculate',
|
||||||
|
'refresh',
|
||||||
|
'override',
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="workflow-pricing" class="showcase-panel pricing-review-step" @submit.prevent="$emit('calculate')">
|
||||||
|
<div>
|
||||||
|
<p class="catalog-kicker">Step 5</p>
|
||||||
|
<h2>Check Pricing</h2>
|
||||||
|
<p class="pricing-review-step__intro">Record a source, refresh market data, or add a reasoned private override before listing.</p>
|
||||||
|
</div>
|
||||||
|
<label class="fixture-label" for="pricing-inventory">Inventory copy</label>
|
||||||
|
<select id="pricing-inventory" :value="inventoryItemId" class="fixture-input" required @change="$emit('update:inventoryItemId', $event.target.value)">
|
||||||
|
<option value="" disabled>Select a copy</option>
|
||||||
|
<option v-for="item in inventory" :key="item.id" :value="item.id">{{ item.id }}</option>
|
||||||
|
</select>
|
||||||
|
<label class="fixture-label" for="pricing-provider">Provider</label>
|
||||||
|
<input id="pricing-provider" :value="provider" class="fixture-input" required @input="$emit('update:provider', $event.target.value)" />
|
||||||
|
<label class="fixture-label" for="pricing-source">Source identifier</label>
|
||||||
|
<input id="pricing-source" :value="sourceIdentifier" class="fixture-input" required @input="$emit('update:sourceIdentifier', $event.target.value)" />
|
||||||
|
<label class="fixture-label" for="pricing-price">Observed price (cents)</label>
|
||||||
|
<input id="pricing-price" :value="observedPrice" class="fixture-input" type="number" min="1" required @input="$emit('update:observedPrice', $event.target.value)" />
|
||||||
|
<button class="button button--primary" type="submit" :disabled="isSaving">Add observation and calculate</button>
|
||||||
|
<button class="button button--secondary" type="button" :disabled="isSaving" @click="$emit('refresh')">Refresh from provider<span v-if="refreshStatus"> ({{ refreshStatus }})</span></button>
|
||||||
|
<label class="fixture-label" for="override-price">Manual value (cents)</label>
|
||||||
|
<input id="override-price" :value="overridePrice" class="fixture-input" type="number" min="0" @input="$emit('update:overridePrice', $event.target.value)" />
|
||||||
|
<label class="fixture-label" for="override-reason">Override reason</label>
|
||||||
|
<input id="override-reason" :value="overrideReason" class="fixture-input" minlength="3" @input="$emit('update:overrideReason', $event.target.value)" />
|
||||||
|
<button class="button button--secondary" type="button" :disabled="isSaving" @click="$emit('override')">Save manual value</button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use './PricingReviewStep.scss';
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,7 @@ import ProductIdentityStep from "@/components/molecules/ProductIdentityStep.vue"
|
|||||||
import ProviderMappingStep from "@/components/molecules/ProviderMappingStep.vue";
|
import ProviderMappingStep from "@/components/molecules/ProviderMappingStep.vue";
|
||||||
import InventoryCopyStep from "@/components/molecules/InventoryCopyStep.vue";
|
import InventoryCopyStep from "@/components/molecules/InventoryCopyStep.vue";
|
||||||
import InventoryImagesStep from "@/components/molecules/InventoryImagesStep.vue";
|
import InventoryImagesStep from "@/components/molecules/InventoryImagesStep.vue";
|
||||||
|
import PricingReviewStep from "@/components/molecules/PricingReviewStep.vue";
|
||||||
import {
|
import {
|
||||||
createAdminInventory,
|
createAdminInventory,
|
||||||
createAdminProduct,
|
createAdminProduct,
|
||||||
@@ -870,94 +871,26 @@ onMounted(load);
|
|||||||
Record acquisition
|
Record acquisition
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<form id="workflow-pricing" class="showcase-panel" @submit.prevent="calculatePricing">
|
<PricingReviewStep
|
||||||
<h2 id="pricing-title">Calculate market value</h2>
|
:inventory-item-id="pricingInventoryId"
|
||||||
<label class="fixture-label" for="pricing-inventory"
|
:provider="pricingProvider"
|
||||||
>Inventory copy</label
|
:source-identifier="pricingSource"
|
||||||
>
|
:observed-price="pricingPrice"
|
||||||
<select
|
:override-price="overridePrice"
|
||||||
id="pricing-inventory"
|
:override-reason="overrideReason"
|
||||||
v-model="pricingInventoryId"
|
:inventory="inventory"
|
||||||
class="fixture-input"
|
:refresh-status="refreshStatus"
|
||||||
required
|
:is-saving="isSaving"
|
||||||
>
|
@update:inventory-item-id="pricingInventoryId = $event"
|
||||||
<option value="" disabled>Select a copy</option>
|
@update:provider="pricingProvider = $event"
|
||||||
<option v-for="item in inventory" :key="item.id" :value="item.id">
|
@update:source-identifier="pricingSource = $event"
|
||||||
{{ item.id }}
|
@update:observed-price="pricingPrice = $event"
|
||||||
</option>
|
@update:override-price="overridePrice = $event"
|
||||||
</select>
|
@update:override-reason="overrideReason = $event"
|
||||||
<label class="fixture-label" for="pricing-provider">Provider</label>
|
@calculate="calculatePricing"
|
||||||
<input
|
@refresh="refreshPricing"
|
||||||
id="pricing-provider"
|
@override="overridePricing"
|
||||||
v-model="pricingProvider"
|
/>
|
||||||
class="fixture-input"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="fixture-label" for="pricing-source"
|
|
||||||
>Source identifier</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="pricing-source"
|
|
||||||
v-model="pricingSource"
|
|
||||||
class="fixture-input"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="fixture-label" for="pricing-price"
|
|
||||||
>Observed price (cents)</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="pricing-price"
|
|
||||||
v-model="pricingPrice"
|
|
||||||
class="fixture-input"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="button button--primary"
|
|
||||||
type="submit"
|
|
||||||
:disabled="isSaving"
|
|
||||||
>
|
|
||||||
Add observation and calculate
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="button button--secondary"
|
|
||||||
type="button"
|
|
||||||
:disabled="isSaving"
|
|
||||||
@click="refreshPricing"
|
|
||||||
>
|
|
||||||
Refresh from provider<span v-if="refreshStatus">
|
|
||||||
({{ refreshStatus }})</span
|
|
||||||
>
|
|
||||||
</button>
|
|
||||||
<label class="fixture-label" for="override-price"
|
|
||||||
>Manual value (cents)</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="override-price"
|
|
||||||
v-model="overridePrice"
|
|
||||||
class="fixture-input"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
/>
|
|
||||||
<label class="fixture-label" for="override-reason"
|
|
||||||
>Override reason</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="override-reason"
|
|
||||||
v-model="overrideReason"
|
|
||||||
class="fixture-input"
|
|
||||||
minlength="3"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="button button--secondary"
|
|
||||||
type="button"
|
|
||||||
:disabled="isSaving"
|
|
||||||
@click="overridePricing"
|
|
||||||
>
|
|
||||||
Save manual value
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="admin-list" aria-labelledby="products-title">
|
<section class="admin-list" aria-labelledby="products-title">
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ Remaining roadmap areas are approved external provider credentials/adapters, bro
|
|||||||
- Source mapping is now an extracted `ProviderMappingStep` molecule with Product/Provider/PRODUCT-vs-SEARCH mapping states, while preserving existing mapping loading and save behavior.
|
- Source mapping is now an extracted `ProviderMappingStep` molecule with Product/Provider/PRODUCT-vs-SEARCH mapping states, while preserving existing mapping loading and save behavior.
|
||||||
- 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.
|
- 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.
|
- 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.
|
||||||
- Public catalog sorting now supports latest manual/calculated market value low-to-high and high-to-low, with null values placed last.
|
- 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.
|
- 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