This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
.product-identity-step {
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-identity-step__intro {
|
||||||
|
margin: var(--space-2) 0 0;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import ProductIdentityStep from './ProductIdentityStep.vue';
|
||||||
|
|
||||||
|
export default { title: 'Molecules/ProductIdentityStep', component: ProductIdentityStep };
|
||||||
|
|
||||||
|
export const Empty = {
|
||||||
|
args: {
|
||||||
|
productName: '',
|
||||||
|
categoryId: '',
|
||||||
|
categories: [
|
||||||
|
{ id: 'cards', name: 'Trading cards' },
|
||||||
|
{ id: 'merchandise', name: 'Merchandise' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Filled = {
|
||||||
|
args: {
|
||||||
|
productName: 'Charizard ex #199/165',
|
||||||
|
categoryId: 'cards',
|
||||||
|
categories: [{ id: 'cards', name: 'Trading cards' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
productName: { type: String, required: true },
|
||||||
|
categoryId: { type: String, required: true },
|
||||||
|
categories: { type: Array, required: true },
|
||||||
|
isSaving: { type: Boolean, default: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
defineEmits(['update:productName', 'update:categoryId', 'submit']);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="workflow-product" class="showcase-panel product-identity-step" @submit.prevent="$emit('submit')">
|
||||||
|
<div>
|
||||||
|
<p class="catalog-kicker">Step 1</p>
|
||||||
|
<h2>Identify the Product</h2>
|
||||||
|
<p class="product-identity-step__intro">Create the shared product record before adding a physical copy.</p>
|
||||||
|
</div>
|
||||||
|
<label class="fixture-label" for="product-name">Name</label>
|
||||||
|
<input
|
||||||
|
id="product-name"
|
||||||
|
:value="productName"
|
||||||
|
class="fixture-input"
|
||||||
|
required
|
||||||
|
@input="$emit('update:productName', $event.target.value)"
|
||||||
|
/>
|
||||||
|
<label class="fixture-label" for="product-category">Category</label>
|
||||||
|
<select
|
||||||
|
id="product-category"
|
||||||
|
:value="categoryId"
|
||||||
|
class="fixture-input"
|
||||||
|
required
|
||||||
|
@change="$emit('update:categoryId', $event.target.value)"
|
||||||
|
>
|
||||||
|
<option value="" disabled>Select a category</option>
|
||||||
|
<option v-for="category in categories" :key="category.id" :value="category.id">
|
||||||
|
{{ category.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<button class="button button--primary" type="submit" :disabled="isSaving">
|
||||||
|
Create product
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use './ProductIdentityStep.scss';
|
||||||
|
</style>
|
||||||
@@ -5,6 +5,7 @@ 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";
|
||||||
import InventoryWorkflowStepper from "@/components/molecules/InventoryWorkflowStepper.vue";
|
import InventoryWorkflowStepper from "@/components/molecules/InventoryWorkflowStepper.vue";
|
||||||
|
import ProductIdentityStep from "@/components/molecules/ProductIdentityStep.vue";
|
||||||
import {
|
import {
|
||||||
createAdminInventory,
|
createAdminInventory,
|
||||||
createAdminProduct,
|
createAdminProduct,
|
||||||
@@ -675,39 +676,15 @@ onMounted(load);
|
|||||||
<InventoryWorkflowStepper :steps="workflowSteps" />
|
<InventoryWorkflowStepper :steps="workflowSteps" />
|
||||||
|
|
||||||
<div class="admin-workspace-grid">
|
<div class="admin-workspace-grid">
|
||||||
<form id="workflow-product" class="showcase-panel" @submit.prevent="createProduct">
|
<ProductIdentityStep
|
||||||
<h2>Add product</h2>
|
:product-name="productName"
|
||||||
<label class="fixture-label" for="product-name">Name</label>
|
:category-id="categoryId"
|
||||||
<input
|
:categories="categories"
|
||||||
id="product-name"
|
:is-saving="isSaving"
|
||||||
v-model="productName"
|
@update:product-name="productName = $event"
|
||||||
class="fixture-input"
|
@update:category-id="categoryId = $event"
|
||||||
required
|
@submit="createProduct"
|
||||||
/>
|
/>
|
||||||
<label class="fixture-label" for="product-category">Category</label>
|
|
||||||
<select
|
|
||||||
id="product-category"
|
|
||||||
v-model="categoryId"
|
|
||||||
class="fixture-input"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option value="" disabled>Select a category</option>
|
|
||||||
<option
|
|
||||||
v-for="category in categories"
|
|
||||||
:key="category.id"
|
|
||||||
:value="category.id"
|
|
||||||
>
|
|
||||||
{{ category.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<button
|
|
||||||
class="button button--primary"
|
|
||||||
type="submit"
|
|
||||||
:disabled="isSaving"
|
|
||||||
>
|
|
||||||
Create product
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<form id="workflow-mapping" class="showcase-panel" @submit.prevent="createProviderMapping">
|
<form id="workflow-mapping" class="showcase-panel" @submit.prevent="createProviderMapping">
|
||||||
<h2>Link provider mapping</h2>
|
<h2>Link provider mapping</h2>
|
||||||
<label class="fixture-label" for="mapping-product">Product</label>
|
<label class="fixture-label" for="mapping-product">Product</label>
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ Remaining roadmap areas are approved external provider credentials/adapters, bro
|
|||||||
- Public catalog filtering now supports URL-synchronized set, event, and tag text filters through a reusable atomic text-filter control and the shared search API.
|
- Public catalog filtering now supports URL-synchronized set, event, and tag text filters through a reusable atomic text-filter control and the shared search API.
|
||||||
- Public catalog filtering now supports explicit Available, Pending, Sold, and All status modes plus a 30-day Newly added toggle through the shared search API and atomic controls.
|
- Public catalog filtering now supports explicit Available, Pending, Sold, and All status modes plus a 30-day Newly added toggle through the shared search API and atomic controls.
|
||||||
- The admin workspace now includes a responsive guided inventory workflow stepper linking Product, Sources, Copy, Images, Pricing, and List stages, with progress derived from loaded admin state.
|
- The admin workspace now includes a responsive guided inventory workflow stepper linking Product, Sources, Copy, Images, Pricing, and List stages, with progress derived from loaded admin state.
|
||||||
|
- Product identification is now an extracted `ProductIdentityStep` molecule with empty/filled Storybook states, while preserving the existing create-product API workflow.
|
||||||
- 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