This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
.inventory-images-step {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--space-4);
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
border: var(--border-thin) solid var(--color-border);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: var(--space-4);
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inventory-images-step__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inventory-images-step__intro {
|
||||||
|
margin: var(--space-2) 0 0;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inventory-images-step__count {
|
||||||
|
align-self: start;
|
||||||
|
color: var(--color-warning-text);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
font-weight: var(--weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inventory-images-step__list {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--space-2);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inventory-images-step__list li {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-3);
|
||||||
|
padding: var(--space-3) 0;
|
||||||
|
border-top: var(--border-thin) solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inventory-images-step__list a {
|
||||||
|
color: var(--color-interactive-text);
|
||||||
|
font-weight: var(--weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.inventory-images-step__header,
|
||||||
|
.inventory-images-step__list li {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import InventoryImagesStep from './InventoryImagesStep.vue';
|
||||||
|
|
||||||
|
export default { title: 'Molecules/InventoryImagesStep', component: InventoryImagesStep };
|
||||||
|
|
||||||
|
export const MissingImages = {
|
||||||
|
args: {
|
||||||
|
missingImages: 2,
|
||||||
|
inventory: [
|
||||||
|
{ id: 'copy-1', status: 'ACTIVE' },
|
||||||
|
{ id: 'copy-2', status: 'ACTIVE' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Empty = { args: { missingImages: 0, inventory: [] } };
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
inventory: { type: Array, required: true },
|
||||||
|
missingImages: { type: Number, default: 0 },
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section id="workflow-images" class="inventory-images-step" aria-labelledby="inventory-images-step-title">
|
||||||
|
<div class="inventory-images-step__header">
|
||||||
|
<div>
|
||||||
|
<p class="catalog-kicker">Step 4</p>
|
||||||
|
<h2 id="inventory-images-step-title">Add Images</h2>
|
||||||
|
<p class="inventory-images-step__intro">Add clear photos to each physical copy before publishing its listing.</p>
|
||||||
|
</div>
|
||||||
|
<span class="inventory-images-step__count">{{ missingImages }} missing</span>
|
||||||
|
</div>
|
||||||
|
<p v-if="!inventory.length" class="state state--empty">Create a physical copy before adding images.</p>
|
||||||
|
<ul v-else class="inventory-images-step__list">
|
||||||
|
<li v-for="item in inventory" :key="item.id">
|
||||||
|
<span>{{ item.id }} · {{ item.status }}</span>
|
||||||
|
<a :href="`/admin/inventory/${item.id}/images`">Manage images</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use './InventoryImagesStep.scss';
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { RouterLink } from "vue-router";
|
|
||||||
|
|
||||||
import { useAuth } from "@/composables/useAuth.js";
|
import { useAuth } from "@/composables/useAuth.js";
|
||||||
import AdminListingStatus from "@/components/molecules/AdminListingStatus.vue";
|
import AdminListingStatus from "@/components/molecules/AdminListingStatus.vue";
|
||||||
@@ -8,6 +7,7 @@ import InventoryWorkflowStepper from "@/components/molecules/InventoryWorkflowSt
|
|||||||
import ProductIdentityStep from "@/components/molecules/ProductIdentityStep.vue";
|
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 {
|
import {
|
||||||
createAdminInventory,
|
createAdminInventory,
|
||||||
createAdminProduct,
|
createAdminProduct,
|
||||||
@@ -988,7 +988,6 @@ onMounted(load);
|
|||||||
class="admin-list"
|
class="admin-list"
|
||||||
aria-labelledby="inventory-title"
|
aria-labelledby="inventory-title"
|
||||||
>
|
>
|
||||||
<span id="workflow-images" aria-hidden="true"></span>
|
|
||||||
<h2 id="inventory-title">Physical inventory</h2>
|
<h2 id="inventory-title">Physical inventory</h2>
|
||||||
<div class="admin-list__actions">
|
<div class="admin-list__actions">
|
||||||
<button
|
<button
|
||||||
@@ -1051,12 +1050,12 @@ onMounted(load);
|
|||||||
</label>
|
</label>
|
||||||
<span v-else>{{ item.id }}</span>
|
<span v-else>{{ item.id }}</span>
|
||||||
· {{ item.status }}
|
· {{ item.status }}
|
||||||
<RouterLink
|
|
||||||
:to="{ name: 'admin-image-manager', params: { id: item.id } }"
|
|
||||||
>Manage images</RouterLink
|
|
||||||
>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<InventoryImagesStep
|
||||||
|
:inventory="inventory"
|
||||||
|
:missing-images="dashboard?.counts.missingImages ?? 0"
|
||||||
|
/>
|
||||||
<ul v-if="hasValuations" aria-label="Market valuations">
|
<ul v-if="hasValuations" aria-label="Market valuations">
|
||||||
<li
|
<li
|
||||||
v-for="(valuation, inventoryItemId) in valuations"
|
v-for="(valuation, inventoryItemId) in valuations"
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ Remaining roadmap areas are approved external provider credentials/adapters, bro
|
|||||||
- Product identification is now an extracted `ProductIdentityStep` molecule with empty/filled Storybook states, while preserving the existing create-product API workflow.
|
- Product identification is now an extracted `ProductIdentityStep` molecule with empty/filled Storybook states, while preserving the existing create-product API workflow.
|
||||||
- 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.
|
||||||
- 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