diff --git a/apps/web/src/assets/styles/global.scss b/apps/web/src/assets/styles/global.scss index 1b960b9..35d4b15 100644 --- a/apps/web/src/assets/styles/global.scss +++ b/apps/web/src/assets/styles/global.scss @@ -56,6 +56,7 @@ h1 { max-width: 760px; margin: var(--space-3) 0 var(--space-4); font-size: var(- .admin-list { margin-top: var(--space-8); } .admin-list h2 { margin-bottom: var(--space-3); font-size: var(--text-xl); } .admin-list ul { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; } +.admin-listing-stack { display: grid; gap: var(--space-3); } .admin-list li { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; border-bottom: var(--border-thin) solid var(--color-border); padding: var(--space-3) 0; } .admin-list li span { color: var(--color-text-muted); font-size: var(--text-sm); } .admin-list a { color: var(--color-interactive-text); font-weight: var(--weight-bold); } diff --git a/apps/web/src/components/molecules/AdminListingStatus.stories.js b/apps/web/src/components/molecules/AdminListingStatus.stories.js new file mode 100644 index 0000000..7b981a9 --- /dev/null +++ b/apps/web/src/components/molecules/AdminListingStatus.stories.js @@ -0,0 +1,19 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import AdminListingStatus from './AdminListingStatus.vue'; + +const listing = { id: 'listing-1', productName: 'Charizard ex #199/165', askingPriceMinor: 11500, status: 'DRAFT' }; + +export default { title: 'Molecules/AdminListingStatus', component: AdminListingStatus }; +export const DraftReady = { args: { listing, blockers: [] } }; +export const DraftBlockedByImages = { args: { listing, blockers: ['Add at least one completed image before publishing.'] } }; +export const Publishing = { args: { listing, blockers: [], isSaving: true } }; +export const PublishError = { args: { listing, blockers: [], errorMessage: 'Listing requirements are not met.' } }; +export const KeyboardPublish = { + args: { listing, blockers: [] }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole('button', { name: 'Publish' })); + await expect(canvas.getByRole('button', { name: 'Publish' })).toBeInTheDocument(); + }, +}; diff --git a/apps/web/src/components/molecules/AdminListingStatus.vue b/apps/web/src/components/molecules/AdminListingStatus.vue new file mode 100644 index 0000000..deceb00 --- /dev/null +++ b/apps/web/src/components/molecules/AdminListingStatus.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/apps/web/src/pages/AdminHomePage.vue b/apps/web/src/pages/AdminHomePage.vue index 010e68e..88c9b79 100644 --- a/apps/web/src/pages/AdminHomePage.vue +++ b/apps/web/src/pages/AdminHomePage.vue @@ -3,6 +3,7 @@ import { onMounted, ref } from 'vue'; import { RouterLink } from 'vue-router'; import { useAuth } from '@/composables/useAuth.js'; +import AdminListingStatus from '@/components/molecules/AdminListingStatus.vue'; import { createAdminInventory, createAdminProduct, listAdminCategories, listAdminConditions, listAdminInventory, listAdminProducts } from '@/services/admin-catalog-service.js'; import { createAdminListing, listAdminListings, markListingPending, publishAdminListing } from '@/services/admin-listing-service.js'; @@ -137,7 +138,7 @@ onMounted(load);

Listings

No listings yet.

- +