@develemit/commerce-admin 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/README.md +84 -8
- package/dist/client/admin-client.d.ts +3 -2
- package/dist/client/errors.d.ts +5 -0
- package/dist/client/index.js +1 -1
- package/dist/{client-CSjuKdIE.js → client-DCL5DSHP.js} +55 -49
- package/dist/client-DCL5DSHP.js.map +1 -0
- package/dist/components/admin-layout/admin-layout.d.ts +5 -6
- package/dist/components/admin-layout/nav-icons.d.ts +9 -0
- package/dist/components/admin-layout/nav-items.d.ts +36 -0
- package/dist/components/admin-layout/use-more-sheet.d.ts +5 -0
- package/dist/components/empty-state/empty-state.d.ts +10 -0
- package/dist/components/notice/notice.d.ts +5 -1
- package/dist/components/page-header/admin-page-header.d.ts +8 -0
- package/dist/components/setup-checklist/setup-checklist.d.ts +15 -0
- package/dist/components/switch/switch.d.ts +7 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +3248 -1109
- package/dist/index.js.map +1 -1
- package/dist/lib/admin-labels.d.ts +2 -0
- package/dist/lib/discount-labels.d.ts +1 -0
- package/dist/lib/fill-alts.d.ts +3 -0
- package/dist/lib/order-labels.d.ts +1 -0
- package/dist/lib/product-draft.d.ts +11 -0
- package/dist/lib/product-flow-labels.d.ts +54 -0
- package/dist/lib/product-labels.d.ts +53 -0
- package/dist/lib/product-missing.d.ts +4 -0
- package/dist/lib/product-sheet-actions.d.ts +13 -0
- package/dist/lib/shipping-labels.d.ts +2 -0
- package/dist/lib/stock-labels.d.ts +41 -0
- package/dist/lib/use-batch-upload.d.ts +38 -0
- package/dist/lib/use-focus-trap.d.ts +2 -0
- package/dist/lib/use-image-upload.d.ts +3 -2
- package/dist/lib/use-product-autosave.d.ts +95 -0
- package/dist/lib/use-product-pages.d.ts +2 -2
- package/dist/styles.css +1300 -55
- package/dist/views/products/add-several/admin-add-several.d.ts +5 -0
- package/dist/views/products/add-several/photo-picker.d.ts +7 -0
- package/dist/views/products/admin-product-editor.d.ts +3 -1
- package/dist/views/products/admin-product-list.d.ts +13 -1
- package/dist/views/products/finish-drafts/admin-finish-drafts.d.ts +7 -0
- package/dist/views/products/finish-drafts/piece-card.d.ts +10 -0
- package/dist/views/products/finish-drafts/piece-fields.d.ts +7 -0
- package/dist/views/products/finish-drafts/piece-summary.d.ts +10 -0
- package/dist/views/products/finish-drafts/use-publish-pieces.d.ts +52 -0
- package/dist/views/products/product-card.d.ts +6 -0
- package/dist/views/products/product-flow/admin-product-flow.d.ts +15 -0
- package/dist/views/products/product-flow/basics-section.d.ts +6 -0
- package/dist/views/products/product-flow/flow-actions.d.ts +10 -0
- package/dist/views/products/product-flow/flow-frame.d.ts +28 -0
- package/dist/views/products/product-flow/flow-images.d.ts +7 -0
- package/dist/views/products/product-flow/flow-section-props.d.ts +5 -0
- package/dist/views/products/product-flow/flow-success.d.ts +8 -0
- package/dist/views/products/product-flow/flow-test-helpers.d.ts +12 -0
- package/dist/views/products/product-flow/photos-section.d.ts +9 -0
- package/dist/views/products/product-flow/preview-section.d.ts +10 -0
- package/dist/views/products/product-flow/story-section.d.ts +8 -0
- package/dist/views/products/product-flow/use-product-flow.d.ts +138 -0
- package/dist/views/products/product-sheet/admin-product-sheet.d.ts +8 -0
- package/dist/views/products/product-sheet/sheet-carousel.d.ts +4 -0
- package/dist/views/products/product-sheet/sheet-edit-link.d.ts +14 -0
- package/dist/views/products/product-sheet/use-product-change.d.ts +16 -0
- package/dist/views/products/product-toolbar.d.ts +10 -0
- package/dist/views/products/product-welcome.d.ts +8 -0
- package/dist/views/shipping/admin-shipping-rates.d.ts +6 -1
- package/package.json +11 -3
- package/dist/client-CSjuKdIE.js.map +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
3
|
+
import { ProductFlowStep } from '../../lib/product-flow-labels';
|
|
3
4
|
export interface AdminProductEditorProps {
|
|
4
5
|
productId?: string;
|
|
5
6
|
onSaved?: (product: AdminProduct) => void;
|
|
6
7
|
imagesSlot?: ReactNode;
|
|
7
8
|
categories?: string[];
|
|
9
|
+
initialStep?: ProductFlowStep;
|
|
8
10
|
}
|
|
9
|
-
export declare function AdminProductEditor({ productId, onSaved, imagesSlot, categories, }: AdminProductEditorProps): import('react').JSX.Element;
|
|
11
|
+
export declare function AdminProductEditor({ productId, onSaved, imagesSlot, categories, initialStep, }: AdminProductEditorProps): import('react').JSX.Element;
|
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
3
|
+
import { SetupStep } from '../../components/setup-checklist/setup-checklist';
|
|
4
|
+
import { EditProduct } from './product-sheet/sheet-edit-link';
|
|
5
|
+
export interface AdminProductListProps {
|
|
6
|
+
welcome?: ReactNode;
|
|
7
|
+
setup?: SetupStep[];
|
|
8
|
+
onAddMany?: () => void;
|
|
9
|
+
onFinishDrafts?: () => void;
|
|
10
|
+
onOpenProduct?: (product: AdminProduct) => void;
|
|
11
|
+
onEditProduct?: EditProduct;
|
|
12
|
+
}
|
|
13
|
+
export declare function AdminProductList({ welcome, setup, onAddMany, onFinishDrafts, onOpenProduct, onEditProduct, }?: AdminProductListProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PublishOutcome } from './use-publish-pieces';
|
|
2
|
+
export interface AdminFinishDraftsProps {
|
|
3
|
+
productIds?: string[];
|
|
4
|
+
categories?: string[];
|
|
5
|
+
onDone: (result: PublishOutcome) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function AdminFinishDrafts({ productIds, categories, onDone, }: AdminFinishDraftsProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
export interface PieceCardProps {
|
|
3
|
+
product: AdminProduct;
|
|
4
|
+
index: number;
|
|
5
|
+
total: number;
|
|
6
|
+
categories?: string[];
|
|
7
|
+
onAdvance: (product: AdminProduct) => void;
|
|
8
|
+
onBack?: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function PieceCard({ product, index, total, categories, onAdvance, onBack, }: PieceCardProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ProductForm } from '../../../lib/product-form';
|
|
2
|
+
export interface PieceFieldsProps {
|
|
3
|
+
form: ProductForm;
|
|
4
|
+
update: <K extends 'name' | 'price' | 'category'>(field: K, value: string) => void;
|
|
5
|
+
categories?: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function PieceFields({ form, update, categories }: PieceFieldsProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
export interface PieceSummaryProps {
|
|
3
|
+
pieces: AdminProduct[];
|
|
4
|
+
pending: boolean;
|
|
5
|
+
failure: unknown;
|
|
6
|
+
onPublish: (ready: AdminProduct[], rest: AdminProduct[]) => void;
|
|
7
|
+
onKeepDrafts: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function isReady(piece: AdminProduct): boolean;
|
|
10
|
+
export declare function PieceSummary({ pieces, pending, failure, onPublish, onKeepDrafts, }: PieceSummaryProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
export interface PublishOutcome {
|
|
3
|
+
published: AdminProduct[];
|
|
4
|
+
drafts: AdminProduct[];
|
|
5
|
+
}
|
|
6
|
+
export declare function usePublishPieces(): {
|
|
7
|
+
publish: (ready: AdminProduct[], rest: AdminProduct[]) => Promise<{
|
|
8
|
+
published: {
|
|
9
|
+
id: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
materials: string | null;
|
|
14
|
+
dimensions: string | null;
|
|
15
|
+
priceCents: number | null;
|
|
16
|
+
currency: string;
|
|
17
|
+
category: string | null;
|
|
18
|
+
quantity: number;
|
|
19
|
+
status: "draft" | "active" | "archived";
|
|
20
|
+
featured: boolean;
|
|
21
|
+
images: {
|
|
22
|
+
id: string;
|
|
23
|
+
url: string;
|
|
24
|
+
alt: string;
|
|
25
|
+
position: number;
|
|
26
|
+
}[];
|
|
27
|
+
}[];
|
|
28
|
+
drafts: {
|
|
29
|
+
id: string;
|
|
30
|
+
slug: string;
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
materials: string | null;
|
|
34
|
+
dimensions: string | null;
|
|
35
|
+
priceCents: number | null;
|
|
36
|
+
currency: string;
|
|
37
|
+
category: string | null;
|
|
38
|
+
quantity: number;
|
|
39
|
+
status: "draft" | "active" | "archived";
|
|
40
|
+
featured: boolean;
|
|
41
|
+
images: {
|
|
42
|
+
id: string;
|
|
43
|
+
url: string;
|
|
44
|
+
alt: string;
|
|
45
|
+
position: number;
|
|
46
|
+
}[];
|
|
47
|
+
}[];
|
|
48
|
+
}>;
|
|
49
|
+
pending: boolean;
|
|
50
|
+
failure: unknown;
|
|
51
|
+
outcome: PublishOutcome | null;
|
|
52
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
3
|
+
import { ProductFlowStep } from '../../../lib/product-flow-labels';
|
|
4
|
+
export type { ProductFlowStep } from '../../../lib/product-flow-labels';
|
|
5
|
+
export interface AdminProductFlowProps {
|
|
6
|
+
productId?: string;
|
|
7
|
+
initialStep?: ProductFlowStep;
|
|
8
|
+
onDone?: (product: AdminProduct) => void;
|
|
9
|
+
onClose?: (product: AdminProduct | null) => void;
|
|
10
|
+
categories?: string[];
|
|
11
|
+
materialSuggestions?: string[];
|
|
12
|
+
isFirstProduct?: boolean;
|
|
13
|
+
imagesSlot?: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare function AdminProductFlow(props: AdminProductFlowProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FlowSectionProps } from './flow-section-props';
|
|
2
|
+
export interface BasicsSectionProps extends FlowSectionProps {
|
|
3
|
+
categories?: string[];
|
|
4
|
+
currency: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function BasicsSection({ form, update, categories, currency, }: BasicsSectionProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ProductFlowStep } from '../../../lib/product-flow-labels';
|
|
2
|
+
import { ProductFlowState } from './use-product-flow';
|
|
3
|
+
export declare function nextStep(step: ProductFlowStep): ProductFlowStep;
|
|
4
|
+
export declare function previousStep(step: ProductFlowStep): ProductFlowStep | null;
|
|
5
|
+
export declare function FinishActions({ flow }: {
|
|
6
|
+
flow: ProductFlowState;
|
|
7
|
+
}): import('react').JSX.Element;
|
|
8
|
+
export declare function StepActions({ flow }: {
|
|
9
|
+
flow: ProductFlowState;
|
|
10
|
+
}): import('react').JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ProductFlowStep } from '../../../lib/product-flow-labels';
|
|
3
|
+
import { AutosaveState } from '../../../lib/use-product-autosave';
|
|
4
|
+
export interface FlowHeadProps {
|
|
5
|
+
title: string;
|
|
6
|
+
onBack: () => void;
|
|
7
|
+
canGoBack: boolean;
|
|
8
|
+
close: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function FlowHead({ title, onBack, canGoBack, close }: FlowHeadProps): import('react').JSX.Element;
|
|
11
|
+
export interface StepBarProps {
|
|
12
|
+
step: ProductFlowStep;
|
|
13
|
+
allOpen: boolean;
|
|
14
|
+
onStep: (step: ProductFlowStep) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function StepBar({ step, allOpen, onStep }: StepBarProps): import('react').JSX.Element;
|
|
17
|
+
export interface SaveNoteProps {
|
|
18
|
+
state: AutosaveState;
|
|
19
|
+
isNew: boolean;
|
|
20
|
+
onRetry: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function SaveNote({ state, isNew, onRetry }: SaveNoteProps): import('react').JSX.Element | null;
|
|
23
|
+
export interface FlowSectionFrameProps {
|
|
24
|
+
step: ProductFlowStep;
|
|
25
|
+
active: boolean;
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export declare function FlowSectionFrame({ step, active, children, }: FlowSectionFrameProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
import { FlowSuccess } from './use-product-flow';
|
|
3
|
+
export interface FlowSuccessViewProps {
|
|
4
|
+
success: FlowSuccess;
|
|
5
|
+
onAddAnother: () => void;
|
|
6
|
+
onDone?: (product: AdminProduct) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function FlowSuccessView({ success, onAddAnother, onDone, }: FlowSuccessViewProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
export declare function draft(overrides?: Partial<AdminProduct>): AdminProduct;
|
|
3
|
+
export declare function image(id: string, position: number, alt?: string): {
|
|
4
|
+
id: string;
|
|
5
|
+
url: string;
|
|
6
|
+
alt: string;
|
|
7
|
+
position: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function type(label: string, value: string): void;
|
|
10
|
+
export declare function click(name: string | RegExp): void;
|
|
11
|
+
export declare function pickFiles(files: File[]): void;
|
|
12
|
+
export declare const png: (name?: string) => File;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
3
|
+
export interface PhotosSectionProps {
|
|
4
|
+
product: AdminProduct | null;
|
|
5
|
+
ensureProduct: () => Promise<AdminProduct>;
|
|
6
|
+
setProduct: (next: AdminProduct) => void;
|
|
7
|
+
imagesSlot?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare function PhotosSection({ product, ensureProduct, setProduct, imagesSlot, }: PhotosSectionProps): string | number | bigint | true | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import('react').JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AdminProduct, ProductIncompleteField } from '@develemit/commerce-contracts';
|
|
3
|
+
import { FlowSectionProps } from './flow-section-props';
|
|
4
|
+
export interface PreviewSectionProps extends FlowSectionProps {
|
|
5
|
+
product: AdminProduct | null;
|
|
6
|
+
currency: string;
|
|
7
|
+
missing: ProductIncompleteField[] | null;
|
|
8
|
+
actions: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function PreviewSection({ form, update, product, currency, missing, actions, }: PreviewSectionProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
import { FlowSectionProps } from './flow-section-props';
|
|
3
|
+
export interface StorySectionProps extends FlowSectionProps {
|
|
4
|
+
product: AdminProduct | null;
|
|
5
|
+
setProduct: (next: AdminProduct) => void;
|
|
6
|
+
materialSuggestions?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function StorySection({ form, update, product, setProduct, materialSuggestions, }: StorySectionProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
import { ProductForm } from '../../../lib/product-form';
|
|
3
|
+
import { ProductFlowStep } from '../../../lib/product-flow-labels';
|
|
4
|
+
export interface FlowOptions {
|
|
5
|
+
initial: AdminProduct | null;
|
|
6
|
+
initialStep?: ProductFlowStep;
|
|
7
|
+
isFirstProduct?: boolean;
|
|
8
|
+
onDone?: (product: AdminProduct) => void;
|
|
9
|
+
onClose?: (product: AdminProduct | null) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface FlowSuccess {
|
|
12
|
+
product: AdminProduct;
|
|
13
|
+
first: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function useProductFlow({ initial, initialStep, isFirstProduct, onDone, onClose, }: FlowOptions): {
|
|
16
|
+
form: ProductForm;
|
|
17
|
+
update: <K extends keyof ProductForm>(field: K, value: ProductForm[K]) => void;
|
|
18
|
+
step: ProductFlowStep;
|
|
19
|
+
goTo: import('react').Dispatch<import('react').SetStateAction<ProductFlowStep>>;
|
|
20
|
+
product: {
|
|
21
|
+
id: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
materials: string | null;
|
|
26
|
+
dimensions: string | null;
|
|
27
|
+
priceCents: number | null;
|
|
28
|
+
currency: string;
|
|
29
|
+
category: string | null;
|
|
30
|
+
quantity: number;
|
|
31
|
+
status: "draft" | "active" | "archived";
|
|
32
|
+
featured: boolean;
|
|
33
|
+
images: {
|
|
34
|
+
id: string;
|
|
35
|
+
url: string;
|
|
36
|
+
alt: string;
|
|
37
|
+
position: number;
|
|
38
|
+
}[];
|
|
39
|
+
} | null;
|
|
40
|
+
isNew: boolean;
|
|
41
|
+
autosave: {
|
|
42
|
+
product: {
|
|
43
|
+
id: string;
|
|
44
|
+
slug: string;
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
materials: string | null;
|
|
48
|
+
dimensions: string | null;
|
|
49
|
+
priceCents: number | null;
|
|
50
|
+
currency: string;
|
|
51
|
+
category: string | null;
|
|
52
|
+
quantity: number;
|
|
53
|
+
status: "draft" | "active" | "archived";
|
|
54
|
+
featured: boolean;
|
|
55
|
+
images: {
|
|
56
|
+
id: string;
|
|
57
|
+
url: string;
|
|
58
|
+
alt: string;
|
|
59
|
+
position: number;
|
|
60
|
+
}[];
|
|
61
|
+
} | null;
|
|
62
|
+
setProduct: (next: AdminProduct) => void;
|
|
63
|
+
state: import('../../../lib/use-product-autosave').AutosaveState;
|
|
64
|
+
error: unknown;
|
|
65
|
+
flush: () => Promise<{
|
|
66
|
+
id: string;
|
|
67
|
+
slug: string;
|
|
68
|
+
name: string;
|
|
69
|
+
description: string;
|
|
70
|
+
materials: string | null;
|
|
71
|
+
dimensions: string | null;
|
|
72
|
+
priceCents: number | null;
|
|
73
|
+
currency: string;
|
|
74
|
+
category: string | null;
|
|
75
|
+
quantity: number;
|
|
76
|
+
status: "draft" | "active" | "archived";
|
|
77
|
+
featured: boolean;
|
|
78
|
+
images: {
|
|
79
|
+
id: string;
|
|
80
|
+
url: string;
|
|
81
|
+
alt: string;
|
|
82
|
+
position: number;
|
|
83
|
+
}[];
|
|
84
|
+
} | null>;
|
|
85
|
+
ensureProduct: () => Promise<{
|
|
86
|
+
id: string;
|
|
87
|
+
slug: string;
|
|
88
|
+
name: string;
|
|
89
|
+
description: string;
|
|
90
|
+
materials: string | null;
|
|
91
|
+
dimensions: string | null;
|
|
92
|
+
priceCents: number | null;
|
|
93
|
+
currency: string;
|
|
94
|
+
category: string | null;
|
|
95
|
+
quantity: number;
|
|
96
|
+
status: "draft" | "active" | "archived";
|
|
97
|
+
featured: boolean;
|
|
98
|
+
images: {
|
|
99
|
+
id: string;
|
|
100
|
+
url: string;
|
|
101
|
+
alt: string;
|
|
102
|
+
position: number;
|
|
103
|
+
}[];
|
|
104
|
+
}>;
|
|
105
|
+
retry: () => Promise<{
|
|
106
|
+
id: string;
|
|
107
|
+
slug: string;
|
|
108
|
+
name: string;
|
|
109
|
+
description: string;
|
|
110
|
+
materials: string | null;
|
|
111
|
+
dimensions: string | null;
|
|
112
|
+
priceCents: number | null;
|
|
113
|
+
currency: string;
|
|
114
|
+
category: string | null;
|
|
115
|
+
quantity: number;
|
|
116
|
+
status: "draft" | "active" | "archived";
|
|
117
|
+
featured: boolean;
|
|
118
|
+
images: {
|
|
119
|
+
id: string;
|
|
120
|
+
url: string;
|
|
121
|
+
alt: string;
|
|
122
|
+
position: number;
|
|
123
|
+
}[];
|
|
124
|
+
} | null>;
|
|
125
|
+
};
|
|
126
|
+
missing: ("name" | "priceCents" | "category" | "images")[] | null;
|
|
127
|
+
failure: unknown;
|
|
128
|
+
pending: boolean;
|
|
129
|
+
success: FlowSuccess | null;
|
|
130
|
+
notice: string | null;
|
|
131
|
+
dismissNotice: () => void;
|
|
132
|
+
closing: boolean;
|
|
133
|
+
finishClosing: () => void;
|
|
134
|
+
saveDraft: () => Promise<void>;
|
|
135
|
+
publish: () => Promise<void>;
|
|
136
|
+
close: () => Promise<void>;
|
|
137
|
+
};
|
|
138
|
+
export type ProductFlowState = ReturnType<typeof useProductFlow>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EditProduct } from './sheet-edit-link';
|
|
2
|
+
export interface AdminProductSheetProps {
|
|
3
|
+
productId: string;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onEdit?: EditProduct;
|
|
6
|
+
onChanged?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function AdminProductSheet({ productId, onClose, onEdit, onChanged, }: AdminProductSheetProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
3
|
+
import { ProductFlowStep } from '../../../lib/product-flow-labels';
|
|
4
|
+
export type EditProduct = (product: AdminProduct, step?: ProductFlowStep) => void;
|
|
5
|
+
export declare function hrefWithStep(href: string, step: ProductFlowStep): string;
|
|
6
|
+
export declare function finishStep(product: AdminProduct): ProductFlowStep;
|
|
7
|
+
export interface SheetEditLinkProps {
|
|
8
|
+
product: AdminProduct;
|
|
9
|
+
step: ProductFlowStep;
|
|
10
|
+
onEdit?: EditProduct;
|
|
11
|
+
className: string;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export declare function SheetEditLink({ product, step, onEdit, className, children, }: SheetEditLinkProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import('react').JSX.Element | null | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AdminProduct } from '@develemit/commerce-contracts';
|
|
2
|
+
import { ProductChange } from '../../../lib/product-sheet-actions';
|
|
3
|
+
export interface SheetNotice {
|
|
4
|
+
text: string;
|
|
5
|
+
undo?: ProductChange['undo'];
|
|
6
|
+
}
|
|
7
|
+
export declare function useProductChange(product: AdminProduct, setProduct: (next: AdminProduct) => void, onChanged: () => void): {
|
|
8
|
+
apply: (change: ProductChange, text: string) => Promise<void>;
|
|
9
|
+
undo: () => Promise<void>;
|
|
10
|
+
notice: SheetNotice | null;
|
|
11
|
+
dismiss: () => void;
|
|
12
|
+
announce: (text: string) => void;
|
|
13
|
+
pending: boolean;
|
|
14
|
+
missing: ("name" | "priceCents" | "category" | "images")[] | null;
|
|
15
|
+
error: unknown;
|
|
16
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AdminProductCounts } from '@develemit/commerce-contracts';
|
|
2
|
+
import { ProductFilter } from '../../lib/product-labels';
|
|
3
|
+
export interface ProductToolbarProps {
|
|
4
|
+
filter: ProductFilter;
|
|
5
|
+
onFilter: (filter: ProductFilter) => void;
|
|
6
|
+
search: string;
|
|
7
|
+
onSearch: (value: string) => void;
|
|
8
|
+
counts: AdminProductCounts | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function ProductToolbar({ filter, onFilter, search, onSearch, counts, }: ProductToolbarProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SetupStep } from '../../components/setup-checklist/setup-checklist';
|
|
3
|
+
export interface ProductWelcomeProps {
|
|
4
|
+
art?: ReactNode;
|
|
5
|
+
steps?: SetupStep[];
|
|
6
|
+
onAddMany?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function ProductWelcome({ art, steps, onAddMany }: ProductWelcomeProps): import('react').JSX.Element;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
export interface SuggestedRate {
|
|
2
|
+
label: string;
|
|
3
|
+
amountCents: number;
|
|
4
|
+
}
|
|
1
5
|
export interface AdminShippingRatesProps {
|
|
6
|
+
suggestedRates?: SuggestedRate[];
|
|
2
7
|
onDirtyChange?: (dirty: boolean) => void;
|
|
3
8
|
}
|
|
4
|
-
export declare function AdminShippingRates({ onDirtyChange }: AdminShippingRatesProps): import('react').JSX.Element;
|
|
9
|
+
export declare function AdminShippingRates({ onDirtyChange, suggestedRates, }: AdminShippingRatesProps): import('react').JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@develemit/commerce-admin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "React admin UI for products, orders, discounts and shipping rates, backed by the commerce-server admin API.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/develemit/develemit-commerce.git",
|
|
8
|
+
"directory": "packages/commerce-admin"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/develemit/develemit-commerce/blob/main/docs/getting-started.md",
|
|
4
11
|
"type": "module",
|
|
5
12
|
"main": "./dist/index.js",
|
|
6
13
|
"module": "./dist/index.js",
|
|
@@ -21,7 +28,8 @@
|
|
|
21
28
|
},
|
|
22
29
|
"files": [
|
|
23
30
|
"dist",
|
|
24
|
-
"!**/*.tsbuildinfo"
|
|
31
|
+
"!**/*.tsbuildinfo",
|
|
32
|
+
"CHANGELOG.md"
|
|
25
33
|
],
|
|
26
34
|
"nx": {
|
|
27
35
|
"name": "commerce-admin",
|
|
@@ -39,7 +47,7 @@
|
|
|
39
47
|
"access": "public"
|
|
40
48
|
},
|
|
41
49
|
"dependencies": {
|
|
42
|
-
"@develemit/commerce-contracts": "0.
|
|
50
|
+
"@develemit/commerce-contracts": "0.7.0"
|
|
43
51
|
},
|
|
44
52
|
"devDependencies": {
|
|
45
53
|
"@testing-library/user-event": "^14.6.8"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-CSjuKdIE.js","names":["AdminApiError","message","status","code","url","AdminUnauthorizedError","AdminNotFoundError","AdminInvalidInputError","issues","InvalidOrderStateError","orderStatus","InsufficientStockError","productIds","RefundExceedsBalanceError","balanceCents","RefundGatewayError","RefundOutcomeUnknownError","InvalidImageError","ImageTooLargeError","DiscountCodeTakenError","DiscountInUseError","MaxRedemptionsBelowUsageError","readBody","body","res","mapError","createTransport","fetchImpl","args","getHeaders","root","baseUrl","path","merged","name","value","headers","form","error","schema","enc","queryString","params","key","query","qs","createAdminClient","options","product","adminProductSchema","discount","discountSchema","rates","shippingRateSchema","request","adminProductPageSchema","id","input","patch","alt","file","imageId","adminDiscountPageSchema","adminOrderPageSchema","adminOrderDetailSchema","refund","err"],"sources":["../src/client/errors.ts","../src/client/map-error.ts","../src/client/transport.ts","../src/client/admin-client.ts"],"sourcesContent":["export class AdminApiError extends Error {\n idempotencyKey?: string;\n\n constructor(\n readonly status: number,\n readonly url: string,\n readonly code?: string,\n message?: string,\n ) {\n super(\n message ??\n `Admin API request failed (${status}${code ? ` ${code}` : ''}): ${url}`,\n );\n this.name = 'AdminApiError';\n }\n}\n\nexport class AdminUnauthorizedError extends AdminApiError {\n constructor(url: string) {\n super(401, url, 'UNAUTHORIZED', `Not authorized: ${url}`);\n this.name = 'AdminUnauthorizedError';\n }\n}\n\nexport class AdminNotFoundError extends AdminApiError {\n constructor(url: string, code?: string, message?: string) {\n super(404, url, code, message ?? `Not found: ${url}`);\n this.name = 'AdminNotFoundError';\n }\n}\n\nexport class AdminInvalidInputError extends AdminApiError {\n constructor(\n url: string,\n readonly issues: unknown[],\n ) {\n super(400, url, 'INVALID_INPUT', `Invalid input: ${url}`);\n this.name = 'AdminInvalidInputError';\n }\n}\n\nexport class InvalidOrderStateError extends AdminApiError {\n constructor(\n url: string,\n readonly orderStatus: string,\n message?: string,\n ) {\n super(409, url, 'INVALID_ORDER_STATE', message);\n this.name = 'InvalidOrderStateError';\n }\n}\n\nexport class InsufficientStockError extends AdminApiError {\n constructor(\n url: string,\n readonly productIds: string[],\n message?: string,\n ) {\n super(409, url, 'INSUFFICIENT_STOCK', message);\n this.name = 'InsufficientStockError';\n }\n}\n\nexport class RefundExceedsBalanceError extends AdminApiError {\n constructor(\n url: string,\n readonly balanceCents: number | undefined,\n message?: string,\n ) {\n super(400, url, 'REFUND_EXCEEDS_BALANCE', message);\n this.name = 'RefundExceedsBalanceError';\n }\n}\n\nexport class RefundGatewayError extends AdminApiError {\n constructor(url: string, message?: string) {\n super(502, url, 'REFUND_GATEWAY_ERROR', message);\n this.name = 'RefundGatewayError';\n }\n}\n\nexport class RefundOutcomeUnknownError extends AdminApiError {\n constructor(url: string, message?: string) {\n super(502, url, 'REFUND_OUTCOME_UNKNOWN', message);\n this.name = 'RefundOutcomeUnknownError';\n }\n}\n\nexport class InvalidImageError extends AdminApiError {\n constructor(url: string, code: string, message?: string) {\n super(400, url, code, message);\n this.name = 'InvalidImageError';\n }\n}\n\nexport class ImageTooLargeError extends AdminApiError {\n constructor(url: string) {\n super(413, url, 'IMAGE_TOO_LARGE', `Image is too large: ${url}`);\n this.name = 'ImageTooLargeError';\n }\n}\n\nexport class DiscountCodeTakenError extends AdminApiError {\n constructor(url: string, message?: string) {\n super(409, url, 'DISCOUNT_CODE_TAKEN', message);\n this.name = 'DiscountCodeTakenError';\n }\n}\n\nexport class DiscountInUseError extends AdminApiError {\n constructor(url: string, message?: string) {\n super(409, url, 'DISCOUNT_IN_USE', message);\n this.name = 'DiscountInUseError';\n }\n}\n\nexport class MaxRedemptionsBelowUsageError extends AdminApiError {\n constructor(url: string, message?: string) {\n super(400, url, 'MAX_REDEMPTIONS_BELOW_USAGE', message);\n this.name = 'MaxRedemptionsBelowUsageError';\n }\n}\n","import {\n AdminApiError,\n AdminInvalidInputError,\n AdminNotFoundError,\n AdminUnauthorizedError,\n DiscountCodeTakenError,\n DiscountInUseError,\n ImageTooLargeError,\n InsufficientStockError,\n InvalidImageError,\n InvalidOrderStateError,\n MaxRedemptionsBelowUsageError,\n RefundExceedsBalanceError,\n RefundGatewayError,\n RefundOutcomeUnknownError,\n} from './errors';\n\ninterface ErrorBody {\n error?: string;\n message?: string;\n issues?: unknown[];\n status?: string;\n productIds?: string[];\n balanceCents?: number;\n}\n\nasync function readBody(res: Response): Promise<ErrorBody> {\n try {\n const body: unknown = await res.json();\n return body && typeof body === 'object' ? (body as ErrorBody) : {};\n } catch {\n return {};\n }\n}\n\nexport async function mapError(\n url: string,\n res: Response,\n): Promise<AdminApiError> {\n const body = await readBody(res);\n const { error: code, message } = body;\n if (res.status === 401) return new AdminUnauthorizedError(url);\n if (res.status === 404) return new AdminNotFoundError(url, code, message);\n if (res.status === 413) return new ImageTooLargeError(url);\n if (code === 'INVALID_INPUT') {\n return new AdminInvalidInputError(url, body.issues ?? []);\n }\n if (code === 'INVALID_ORDER_STATE') {\n return new InvalidOrderStateError(url, body.status ?? '', message);\n }\n if (code === 'INSUFFICIENT_STOCK') {\n return new InsufficientStockError(url, body.productIds ?? [], message);\n }\n if (code === 'REFUND_EXCEEDS_BALANCE') {\n return new RefundExceedsBalanceError(url, body.balanceCents, message);\n }\n if (code === 'REFUND_GATEWAY_ERROR')\n return new RefundGatewayError(url, message);\n if (code === 'REFUND_OUTCOME_UNKNOWN') {\n return new RefundOutcomeUnknownError(url, message);\n }\n if (code === 'DISCOUNT_CODE_TAKEN') {\n return new DiscountCodeTakenError(url, message);\n }\n if (code === 'MAX_REDEMPTIONS_BELOW_USAGE') {\n return new MaxRedemptionsBelowUsageError(url, message);\n }\n if (code === 'DISCOUNT_IN_USE') return new DiscountInUseError(url, message);\n if (code === 'INVALID_IMAGE' || code === 'INVALID_IMAGE_ORDER') {\n return new InvalidImageError(url, code, message);\n }\n return new AdminApiError(res.status, url, code, message);\n}\n","import { AdminUnauthorizedError } from './errors';\nimport { mapError } from './map-error';\n\nexport interface AdminClientOptions {\n baseUrl: string;\n fetch?: typeof fetch;\n headers?: () => HeadersInit | Promise<HeadersInit>;\n onUnauthorized?: (error: AdminUnauthorizedError) => void;\n}\n\ntype Schema<T> = { parse(data: unknown): T };\n\nexport interface RequestOptions {\n method?: string;\n body?: unknown;\n form?: FormData;\n headers?: Record<string, string>;\n}\n\nexport interface Transport {\n request<T>(\n path: string,\n schema: Schema<T>,\n options?: RequestOptions,\n ): Promise<T>;\n}\n\nexport function createTransport({\n baseUrl,\n fetch: fetchImpl = (...args) => globalThis.fetch(...args),\n headers: getHeaders,\n onUnauthorized,\n}: AdminClientOptions): Transport {\n const root = baseUrl.replace(/\\/+$/, '');\n\n return {\n async request(path, schema, { method = 'GET', body, form, headers } = {}) {\n const url = `${root}${path}`;\n const merged = new Headers(getHeaders ? await getHeaders() : undefined);\n merged.set('accept', 'application/json');\n if (body !== undefined) merged.set('content-type', 'application/json');\n for (const [name, value] of Object.entries(headers ?? {})) {\n merged.set(name, value);\n }\n const res = await fetchImpl(url, {\n method,\n headers: merged,\n body: form ?? (body === undefined ? undefined : JSON.stringify(body)),\n });\n if (!res.ok) {\n const error = await mapError(url, res);\n if (error instanceof AdminUnauthorizedError) {\n try {\n onUnauthorized?.(error);\n } catch {\n // A host callback failure must not replace the 401 the caller expects.\n }\n }\n throw error;\n }\n return schema.parse(await res.json());\n },\n };\n}\n","import {\n adminDiscountPageSchema,\n adminOrderDetailSchema,\n adminOrderPageSchema,\n adminProductPageSchema,\n adminProductSchema,\n discountSchema,\n shippingRateSchema,\n type AdminDiscountListQuery,\n type AdminDiscountPage,\n type AdminOrderDetail,\n type AdminOrderListQuery,\n type AdminOrderPage,\n type AdminProduct,\n type AdminProductListQuery,\n type AdminProductPage,\n type AdminProductInput,\n type AdminProductPatch,\n type Discount,\n type DiscountInput,\n type DiscountPatch,\n type RefundOrderInput,\n type ProductImagePatch,\n type ShippingRate,\n type ShippingRateInput,\n type ShipOrderInput,\n} from '@develemit/commerce-contracts';\nimport { createTransport, type AdminClientOptions } from './transport';\n\nexport type AdminOrderQuery = Partial<\n Pick<AdminOrderListQuery, 'status' | 'q' | 'hasPendingRefund' | 'cursor'>\n> & { limit?: number };\n\nexport type AdminProductQuery = Pick<\n AdminProductListQuery,\n 'status' | 'stock' | 'q' | 'cursor' | 'limit'\n>;\n\nexport type AdminDiscountQuery = Partial<\n Pick<AdminDiscountListQuery, 'status' | 'q' | 'cursor' | 'limit'>\n>;\n\nexport interface RefundOptions {\n idempotencyKey?: string;\n}\n\nexport interface AdminClient {\n listProducts(query?: AdminProductQuery): Promise<AdminProductPage>;\n getProduct(id: string): Promise<AdminProduct>;\n createProduct(input: AdminProductInput): Promise<AdminProduct>;\n updateProduct(id: string, patch: AdminProductPatch): Promise<AdminProduct>;\n uploadProductImage(\n id: string,\n file: Blob,\n alt?: string,\n ): Promise<AdminProduct>;\n reorderProductImages(id: string, imageIds: string[]): Promise<AdminProduct>;\n updateProductImage(\n id: string,\n imageId: string,\n patch: ProductImagePatch,\n ): Promise<AdminProduct>;\n deleteProductImage(id: string, imageId: string): Promise<AdminProduct>;\n listDiscounts(query?: AdminDiscountQuery): Promise<AdminDiscountPage>;\n getDiscount(id: string): Promise<Discount>;\n createDiscount(input: DiscountInput): Promise<Discount>;\n updateDiscount(id: string, patch: DiscountPatch): Promise<Discount>;\n listShippingRates(): Promise<ShippingRate[]>;\n replaceShippingRates(rates: ShippingRateInput[]): Promise<ShippingRate[]>;\n listOrders(query?: AdminOrderQuery): Promise<AdminOrderPage>;\n getOrder(id: string): Promise<AdminOrderDetail>;\n shipOrder(id: string, input?: ShipOrderInput): Promise<AdminOrderDetail>;\n resolveOrder(id: string): Promise<AdminOrderDetail>;\n /**\n * Retrying the same intent must reuse the same key. When none is passed one\n * is generated, and it is set on any thrown error as `idempotencyKey` so the\n * caller can pass it back on retry.\n */\n refundOrder(\n id: string,\n input?: RefundOrderInput,\n options?: RefundOptions,\n ): Promise<AdminOrderDetail>;\n}\n\nconst enc = encodeURIComponent;\n\nfunction queryString(query: object): string {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) params.set(key, String(value));\n }\n const qs = params.toString();\n return qs ? `?${qs}` : '';\n}\n\nexport function createAdminClient(options: AdminClientOptions): AdminClient {\n const { request } = createTransport(options);\n const product = adminProductSchema;\n const discount = discountSchema;\n const rates = shippingRateSchema.array();\n\n return {\n listProducts: (query = {}) =>\n request(`/admin/products${queryString(query)}`, adminProductPageSchema),\n getProduct: (id) => request(`/admin/products/${enc(id)}`, product),\n createProduct: (input) =>\n request('/admin/products', product, { method: 'POST', body: input }),\n updateProduct: (id, patch) =>\n request(`/admin/products/${enc(id)}`, product, {\n method: 'PATCH',\n body: patch,\n }),\n uploadProductImage(id, file, alt) {\n const form = new FormData();\n if (alt !== undefined) form.append('alt', alt);\n form.append('file', file);\n return request(`/admin/products/${enc(id)}/images`, product, {\n method: 'POST',\n form,\n });\n },\n reorderProductImages: (id, imageIds) =>\n request(`/admin/products/${enc(id)}/images/order`, product, {\n method: 'PATCH',\n body: { imageIds },\n }),\n updateProductImage: (id, imageId, patch) =>\n request(`/admin/products/${enc(id)}/images/${enc(imageId)}`, product, {\n method: 'PATCH',\n body: patch,\n }),\n deleteProductImage: (id, imageId) =>\n request(`/admin/products/${enc(id)}/images/${enc(imageId)}`, product, {\n method: 'DELETE',\n }),\n listDiscounts: (query = {}) =>\n request(`/admin/discounts${queryString(query)}`, adminDiscountPageSchema),\n getDiscount: (id) => request(`/admin/discounts/${enc(id)}`, discount),\n createDiscount: (input) =>\n request('/admin/discounts', discount, { method: 'POST', body: input }),\n updateDiscount: (id, patch) =>\n request(`/admin/discounts/${enc(id)}`, discount, {\n method: 'PATCH',\n body: patch,\n }),\n listShippingRates: () => request('/admin/shipping-rates', rates),\n replaceShippingRates: (input) =>\n request('/admin/shipping-rates', rates, { method: 'PUT', body: input }),\n listOrders: (query = {}) =>\n request(`/admin/orders${queryString(query)}`, adminOrderPageSchema),\n getOrder: (id) =>\n request(`/admin/orders/${enc(id)}`, adminOrderDetailSchema),\n shipOrder: (id, input = {}) =>\n request(`/admin/orders/${enc(id)}/ship`, adminOrderDetailSchema, {\n method: 'POST',\n body: input,\n }),\n resolveOrder: (id) =>\n request(`/admin/orders/${enc(id)}/resolve`, adminOrderDetailSchema, {\n method: 'POST',\n }),\n async refundOrder(id, input = { restock: false }, refund = {}) {\n const key = refund.idempotencyKey ?? crypto.randomUUID();\n try {\n return await request(\n `/admin/orders/${enc(id)}/refunds`,\n adminOrderDetailSchema,\n {\n method: 'POST',\n body: input,\n headers: { 'idempotency-key': key },\n },\n );\n } catch (err) {\n if (err instanceof Error) {\n (err as Error & { idempotencyKey?: string }).idempotencyKey = key;\n }\n throw err;\n }\n },\n };\n}\n"],"mappings":"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"}
|