react-shopwave-connect 0.4.1 → 0.4.3
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/README.md +17 -5
- package/dist/core/index.cjs +119 -48
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +80 -9
- package/dist/core/index.d.ts +80 -9
- package/dist/core/index.js +116 -49
- package/dist/core/index.js.map +1 -1
- package/dist/hooks/index.cjs +129 -44
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +21 -1
- package/dist/hooks/index.d.ts +21 -1
- package/dist/hooks/index.js +128 -45
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +148 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -9
- package/dist/index.d.ts +100 -9
- package/dist/index.js +143 -49
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +83 -2
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +63 -7
- package/dist/next/index.d.ts +63 -7
- package/dist/next/index.js +83 -3
- package/dist/next/index.js.map +1 -1
- package/dist/server/index.cjs +80 -2
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +60 -7
- package/dist/server/index.d.ts +60 -7
- package/dist/server/index.js +80 -3
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -340,6 +340,26 @@ declare function fetchProductsMap(productIds: number[] | null | undefined, optio
|
|
|
340
340
|
[id: number]: Product;
|
|
341
341
|
}>;
|
|
342
342
|
//#endregion
|
|
343
|
+
//#region src/core/productTags.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* Turns a tag list from the API into clean strings: trims each tag, drops
|
|
346
|
+
* blanks and anything that isn't text, and removes exact duplicates (first one
|
|
347
|
+
* wins). The API's own order is kept. A map is accepted too (its values are
|
|
348
|
+
* used), in case the API ever answers keyed by id.
|
|
349
|
+
*/
|
|
350
|
+
declare function normalizeTagList(value: unknown): string[];
|
|
351
|
+
/**
|
|
352
|
+
* Every distinct tag used on the merchant's products (`GET /product/tags`),
|
|
353
|
+
* for a tag field's suggestions. Returns `[]` when there are none.
|
|
354
|
+
*/
|
|
355
|
+
declare function fetchProductTags(options?: RequestOptions): Promise<string[]>;
|
|
356
|
+
/**
|
|
357
|
+
* Every distinct tag used on the merchant's price instances
|
|
358
|
+
* (`GET /product/instance/tags`): the channel names (Eat In, Takeout, …).
|
|
359
|
+
* Returns `[]` when there are none.
|
|
360
|
+
*/
|
|
361
|
+
declare function fetchProductInstanceTags(options?: RequestOptions): Promise<string[]>;
|
|
362
|
+
//#endregion
|
|
343
363
|
//#region src/core/promotion.d.ts
|
|
344
364
|
/** Promotion rule identifiers as stored by the Shopwave API. */
|
|
345
365
|
declare enum PromotionRuleSet {
|
|
@@ -537,8 +557,9 @@ declare function submitEntity<R = any>({
|
|
|
537
557
|
//#region src/core/entities.d.ts
|
|
538
558
|
/**
|
|
539
559
|
* How each Shopwave entity is addressed, shared by the client functions below
|
|
540
|
-
* and the server route handlers in `react-shopwave-connect/
|
|
541
|
-
*
|
|
560
|
+
* and the server route handlers in `react-shopwave-connect/server` (wrapped with
|
|
561
|
+
* the session by `react-shopwave-connect/next`), so the two halves of the
|
|
562
|
+
* contract can't drift apart.
|
|
542
563
|
*/
|
|
543
564
|
interface EntityDefinition {
|
|
544
565
|
/** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
|
|
@@ -556,13 +577,25 @@ interface EntityDefinition {
|
|
|
556
577
|
/**
|
|
557
578
|
* How a delete is done upstream:
|
|
558
579
|
* - `"delete"`: `DELETE {apiUrl}/<upstream>` with the `idHeader` (205, empty body)
|
|
559
|
-
* - `"retire"`: the API has no DELETE; the record is retired by
|
|
560
|
-
* `
|
|
580
|
+
* - `"retire"`: the API has no DELETE; the record is retired by setting
|
|
581
|
+
* `retireField` to now (employees: `exitDate`, promotions: `endDate`)
|
|
561
582
|
* - `"none"`: can't be deleted
|
|
562
583
|
*/
|
|
563
584
|
deleteMode: "delete" | "retire" | "none";
|
|
564
585
|
/** Date field set to "now" when `deleteMode` is `"retire"`. */
|
|
565
586
|
retireField?: string;
|
|
587
|
+
/**
|
|
588
|
+
* Retire by reading the record and POSTing all of it back with the date(s)
|
|
589
|
+
* changed, instead of a partial `{ id, [retireField]: <now> }`. Needed where
|
|
590
|
+
* the API rejects a partial save (promotions: error 899, live 14 Oct 2026).
|
|
591
|
+
*/
|
|
592
|
+
retireWithRecord?: boolean;
|
|
593
|
+
/**
|
|
594
|
+
* Start-date field of a record retired with `retireWithRecord`. If the record
|
|
595
|
+
* hasn't started yet (start after now), the start moves to now as well, so
|
|
596
|
+
* start = end and the record is expired without ever running.
|
|
597
|
+
*/
|
|
598
|
+
retireStartField?: string;
|
|
566
599
|
}
|
|
567
600
|
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer";
|
|
568
601
|
/** Entities that can be created/updated through the API. */
|
|
@@ -574,7 +607,10 @@ type DeletableEntityKind = Exclude<EntityKind, "consumer">;
|
|
|
574
607
|
* (https://developer.merchantstack.com/api-reference.html) and checked against
|
|
575
608
|
* the live API where noted:
|
|
576
609
|
* - category/product/store: GET filtered by `<x>Ids`, POST upsert, DELETE with `<x>Id` → 205.
|
|
577
|
-
* - promotion: no DELETE;
|
|
610
|
+
* - promotion: no DELETE; promotions are never deleted, only expired. Expiring
|
|
611
|
+
* reads the promotion and saves the whole record back with `endDate` = now (and
|
|
612
|
+
* `startDate` = now too if it hadn't started); the live API rejects a partial
|
|
613
|
+
* `{ id, endDate }` save with error 899. Dates are UTC `YYYY-MM-DD HH:mm:ss`.
|
|
578
614
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
579
615
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
580
616
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
@@ -618,7 +654,8 @@ declare function saveEntity<K extends WritableEntityKind>(kind: K, item: EntityI
|
|
|
618
654
|
/**
|
|
619
655
|
* Deletes one entity (a soft delete: it stays readable with `deleted: true`).
|
|
620
656
|
* Employees and promotions can't be deleted in Shopwave; for them the route
|
|
621
|
-
* sets `exitDate` / `endDate` to now instead (see `SHOPWAVE_ENTITIES`)
|
|
657
|
+
* sets `exitDate` / `endDate` to now instead (see `SHOPWAVE_ENTITIES`), and a
|
|
658
|
+
* promotion is saved back whole (see {@link deletePromotion}).
|
|
622
659
|
*
|
|
623
660
|
* Shopwave answers 205 with an empty body — also for ids that don't exist — so
|
|
624
661
|
* a resolved promise means "the API accepted the request", not "a record was
|
|
@@ -650,7 +687,12 @@ declare const saveStore: (store: EntityInput<Store>, options?: RequestOptions) =
|
|
|
650
687
|
declare const deleteStore: (id: EntityId, options?: RequestOptions) => Promise<void>;
|
|
651
688
|
declare const fetchStore: (id: EntityId, params?: FetchByIdParams, options?: RequestOptions) => Promise<Store | null>;
|
|
652
689
|
declare const savePromotion: (promotion: EntityInput<Promotion>, options?: RequestOptions) => Promise<Saved<Promotion>>;
|
|
653
|
-
/**
|
|
690
|
+
/**
|
|
691
|
+
* Expires a promotion (Shopwave never deletes promotions). The route reads the
|
|
692
|
+
* promotion and saves it back with `endDate` set to now; a promotion that hasn't
|
|
693
|
+
* started yet gets `startDate` = `endDate` = now. Rejects if the promotion doesn't
|
|
694
|
+
* exist or the save fails.
|
|
695
|
+
*/
|
|
654
696
|
declare const deletePromotion: (id: EntityId, options?: RequestOptions) => Promise<void>;
|
|
655
697
|
declare const fetchPromotion: (id: EntityId, params?: FetchByIdParams, options?: RequestOptions) => Promise<Promotion | null>;
|
|
656
698
|
/**
|
|
@@ -769,7 +811,7 @@ declare function buildConsumerMap(consumers: Consumer[] | null | undefined): {
|
|
|
769
811
|
*
|
|
770
812
|
* Like `SHOPWAVE_ENTITIES`, this table is shared by the client functions
|
|
771
813
|
* (`fetchMerchant`, `fetchUser`, `uploadImage`, …) and the server route
|
|
772
|
-
* handlers in `react-shopwave-connect/
|
|
814
|
+
* handlers in `react-shopwave-connect/server`, so the two halves of the contract
|
|
773
815
|
* can't drift apart. These aren't in `SHOPWAVE_ENTITIES` because they aren't
|
|
774
816
|
* keyed collections: `GET /merchant` answers `{ merchant: {…} }`, not a map by id.
|
|
775
817
|
*/
|
|
@@ -816,6 +858,35 @@ declare const SHOPWAVE_UPLOAD: Readonly<{
|
|
|
816
858
|
kindField: "kind";
|
|
817
859
|
}>;
|
|
818
860
|
declare function isUploadKind(value: unknown): value is UploadKind;
|
|
861
|
+
/**
|
|
862
|
+
* Read-only lists that aren't records: the merchant's distinct tags.
|
|
863
|
+
*
|
|
864
|
+
* Like `SHOPWAVE_RESOURCES`, shared by the client functions
|
|
865
|
+
* (`fetchProductTags`, `fetchProductInstanceTags`) and the server route
|
|
866
|
+
* handlers (`shopwave.lookup(kind)`), so the two halves can't drift apart.
|
|
867
|
+
*
|
|
868
|
+
* - productTags: `GET /product/tags` → `{ tags: string[] }`, every distinct tag
|
|
869
|
+
* on the merchant's products. No parameters. The API reference says
|
|
870
|
+
* "internal SKU tags are excluded", but the live API includes system tags
|
|
871
|
+
* written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
|
|
872
|
+
* test merchant 5644, 29 Oct 2026). Apps that offer the list as suggestions
|
|
873
|
+
* filter those themselves. Tags of deleted products drop out of the list.
|
|
874
|
+
* - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
|
|
875
|
+
* the same for price instances (channels such as "Eat In", "Takeout").
|
|
876
|
+
*
|
|
877
|
+
* The app route for instance tags is `products/instance-tags`, one segment
|
|
878
|
+
* under `products`, so it sits beside `products/[id]` without nesting deeper.
|
|
879
|
+
*/
|
|
880
|
+
interface LookupDefinition {
|
|
881
|
+
/** App route: `/api/<route>`. */
|
|
882
|
+
route: string;
|
|
883
|
+
/** Key of the list in the response (`{ tags: [...] }`). */
|
|
884
|
+
key: string;
|
|
885
|
+
/** Shopwave API path. */
|
|
886
|
+
upstream: string;
|
|
887
|
+
}
|
|
888
|
+
type LookupKind = "productTags" | "productInstanceTags";
|
|
889
|
+
declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
|
|
819
890
|
//#endregion
|
|
820
891
|
//#region src/core/imageFit.d.ts
|
|
821
892
|
/**
|
|
@@ -1213,6 +1284,26 @@ declare function useEmployee(params?: FetchEmployeesParams, options?: RequestOpt
|
|
|
1213
1284
|
*/
|
|
1214
1285
|
declare function useProduct(params?: FetchProductsParams, options?: RequestOptions): QueryState<Product[]>;
|
|
1215
1286
|
//#endregion
|
|
1287
|
+
//#region src/hooks/useProductTags.d.ts
|
|
1288
|
+
type LookupOptions = RequestOptions & {
|
|
1289
|
+
/** Fetch only when true (e.g. once a tag field is first opened). Defaults to true. */
|
|
1290
|
+
enabled?: boolean;
|
|
1291
|
+
};
|
|
1292
|
+
/**
|
|
1293
|
+
* The merchant's distinct product tags, for a tag field's suggestions.
|
|
1294
|
+
* `data` is `string[]` once loaded.
|
|
1295
|
+
*
|
|
1296
|
+
* @example
|
|
1297
|
+
* const [opened, setOpened] = useState(false);
|
|
1298
|
+
* const { data: tags, loading } = useProductTags({ enabled: opened });
|
|
1299
|
+
*/
|
|
1300
|
+
declare function useProductTags(options?: LookupOptions): QueryState<string[]>;
|
|
1301
|
+
/**
|
|
1302
|
+
* The merchant's distinct price-instance (channel) tags: Eat In, Takeout, …
|
|
1303
|
+
* `data` is `string[]` once loaded.
|
|
1304
|
+
*/
|
|
1305
|
+
declare function useProductInstanceTags(options?: LookupOptions): QueryState<string[]>;
|
|
1306
|
+
//#endregion
|
|
1216
1307
|
//#region src/hooks/usePromotion.d.ts
|
|
1217
1308
|
/**
|
|
1218
1309
|
* Auto-fetches promotions on mount and whenever the params change.
|
|
@@ -1366,5 +1457,5 @@ interface UseBasketReportReturn {
|
|
|
1366
1457
|
*/
|
|
1367
1458
|
declare function useBasketReport(options?: RequestOptions): UseBasketReportReturn;
|
|
1368
1459
|
//#endregion
|
|
1369
|
-
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, MutationState, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, QueryState, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, UseBasketReportReturn, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, useBasketReport, useCategory, useConsumer, useDelete, useEmployee, useLogout, useMerchant, useProduct, usePromotion, useReport, useSession, useStore, useSubmit, useUpdateMerchant, useUploadImage, useUploadMerchantImage, useUser, validateMerchant, withToken };
|
|
1460
|
+
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, MutationState, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, QueryState, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, UseBasketReportReturn, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, useBasketReport, useCategory, useConsumer, useDelete, useEmployee, useLogout, useMerchant, useProduct, useProductInstanceTags, useProductTags, usePromotion, useReport, useSession, useStore, useSubmit, useUpdateMerchant, useUploadImage, useUploadMerchantImage, useUser, validateMerchant, withToken };
|
|
1370
1461
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -340,6 +340,26 @@ declare function fetchProductsMap(productIds: number[] | null | undefined, optio
|
|
|
340
340
|
[id: number]: Product;
|
|
341
341
|
}>;
|
|
342
342
|
//#endregion
|
|
343
|
+
//#region src/core/productTags.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* Turns a tag list from the API into clean strings: trims each tag, drops
|
|
346
|
+
* blanks and anything that isn't text, and removes exact duplicates (first one
|
|
347
|
+
* wins). The API's own order is kept. A map is accepted too (its values are
|
|
348
|
+
* used), in case the API ever answers keyed by id.
|
|
349
|
+
*/
|
|
350
|
+
declare function normalizeTagList(value: unknown): string[];
|
|
351
|
+
/**
|
|
352
|
+
* Every distinct tag used on the merchant's products (`GET /product/tags`),
|
|
353
|
+
* for a tag field's suggestions. Returns `[]` when there are none.
|
|
354
|
+
*/
|
|
355
|
+
declare function fetchProductTags(options?: RequestOptions): Promise<string[]>;
|
|
356
|
+
/**
|
|
357
|
+
* Every distinct tag used on the merchant's price instances
|
|
358
|
+
* (`GET /product/instance/tags`): the channel names (Eat In, Takeout, …).
|
|
359
|
+
* Returns `[]` when there are none.
|
|
360
|
+
*/
|
|
361
|
+
declare function fetchProductInstanceTags(options?: RequestOptions): Promise<string[]>;
|
|
362
|
+
//#endregion
|
|
343
363
|
//#region src/core/promotion.d.ts
|
|
344
364
|
/** Promotion rule identifiers as stored by the Shopwave API. */
|
|
345
365
|
declare enum PromotionRuleSet {
|
|
@@ -537,8 +557,9 @@ declare function submitEntity<R = any>({
|
|
|
537
557
|
//#region src/core/entities.d.ts
|
|
538
558
|
/**
|
|
539
559
|
* How each Shopwave entity is addressed, shared by the client functions below
|
|
540
|
-
* and the server route handlers in `react-shopwave-connect/
|
|
541
|
-
*
|
|
560
|
+
* and the server route handlers in `react-shopwave-connect/server` (wrapped with
|
|
561
|
+
* the session by `react-shopwave-connect/next`), so the two halves of the
|
|
562
|
+
* contract can't drift apart.
|
|
542
563
|
*/
|
|
543
564
|
interface EntityDefinition {
|
|
544
565
|
/** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
|
|
@@ -556,13 +577,25 @@ interface EntityDefinition {
|
|
|
556
577
|
/**
|
|
557
578
|
* How a delete is done upstream:
|
|
558
579
|
* - `"delete"`: `DELETE {apiUrl}/<upstream>` with the `idHeader` (205, empty body)
|
|
559
|
-
* - `"retire"`: the API has no DELETE; the record is retired by
|
|
560
|
-
* `
|
|
580
|
+
* - `"retire"`: the API has no DELETE; the record is retired by setting
|
|
581
|
+
* `retireField` to now (employees: `exitDate`, promotions: `endDate`)
|
|
561
582
|
* - `"none"`: can't be deleted
|
|
562
583
|
*/
|
|
563
584
|
deleteMode: "delete" | "retire" | "none";
|
|
564
585
|
/** Date field set to "now" when `deleteMode` is `"retire"`. */
|
|
565
586
|
retireField?: string;
|
|
587
|
+
/**
|
|
588
|
+
* Retire by reading the record and POSTing all of it back with the date(s)
|
|
589
|
+
* changed, instead of a partial `{ id, [retireField]: <now> }`. Needed where
|
|
590
|
+
* the API rejects a partial save (promotions: error 899, live 14 Oct 2026).
|
|
591
|
+
*/
|
|
592
|
+
retireWithRecord?: boolean;
|
|
593
|
+
/**
|
|
594
|
+
* Start-date field of a record retired with `retireWithRecord`. If the record
|
|
595
|
+
* hasn't started yet (start after now), the start moves to now as well, so
|
|
596
|
+
* start = end and the record is expired without ever running.
|
|
597
|
+
*/
|
|
598
|
+
retireStartField?: string;
|
|
566
599
|
}
|
|
567
600
|
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer";
|
|
568
601
|
/** Entities that can be created/updated through the API. */
|
|
@@ -574,7 +607,10 @@ type DeletableEntityKind = Exclude<EntityKind, "consumer">;
|
|
|
574
607
|
* (https://developer.merchantstack.com/api-reference.html) and checked against
|
|
575
608
|
* the live API where noted:
|
|
576
609
|
* - category/product/store: GET filtered by `<x>Ids`, POST upsert, DELETE with `<x>Id` → 205.
|
|
577
|
-
* - promotion: no DELETE;
|
|
610
|
+
* - promotion: no DELETE; promotions are never deleted, only expired. Expiring
|
|
611
|
+
* reads the promotion and saves the whole record back with `endDate` = now (and
|
|
612
|
+
* `startDate` = now too if it hadn't started); the live API rejects a partial
|
|
613
|
+
* `{ id, endDate }` save with error 899. Dates are UTC `YYYY-MM-DD HH:mm:ss`.
|
|
578
614
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
579
615
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
580
616
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
@@ -618,7 +654,8 @@ declare function saveEntity<K extends WritableEntityKind>(kind: K, item: EntityI
|
|
|
618
654
|
/**
|
|
619
655
|
* Deletes one entity (a soft delete: it stays readable with `deleted: true`).
|
|
620
656
|
* Employees and promotions can't be deleted in Shopwave; for them the route
|
|
621
|
-
* sets `exitDate` / `endDate` to now instead (see `SHOPWAVE_ENTITIES`)
|
|
657
|
+
* sets `exitDate` / `endDate` to now instead (see `SHOPWAVE_ENTITIES`), and a
|
|
658
|
+
* promotion is saved back whole (see {@link deletePromotion}).
|
|
622
659
|
*
|
|
623
660
|
* Shopwave answers 205 with an empty body — also for ids that don't exist — so
|
|
624
661
|
* a resolved promise means "the API accepted the request", not "a record was
|
|
@@ -650,7 +687,12 @@ declare const saveStore: (store: EntityInput<Store>, options?: RequestOptions) =
|
|
|
650
687
|
declare const deleteStore: (id: EntityId, options?: RequestOptions) => Promise<void>;
|
|
651
688
|
declare const fetchStore: (id: EntityId, params?: FetchByIdParams, options?: RequestOptions) => Promise<Store | null>;
|
|
652
689
|
declare const savePromotion: (promotion: EntityInput<Promotion>, options?: RequestOptions) => Promise<Saved<Promotion>>;
|
|
653
|
-
/**
|
|
690
|
+
/**
|
|
691
|
+
* Expires a promotion (Shopwave never deletes promotions). The route reads the
|
|
692
|
+
* promotion and saves it back with `endDate` set to now; a promotion that hasn't
|
|
693
|
+
* started yet gets `startDate` = `endDate` = now. Rejects if the promotion doesn't
|
|
694
|
+
* exist or the save fails.
|
|
695
|
+
*/
|
|
654
696
|
declare const deletePromotion: (id: EntityId, options?: RequestOptions) => Promise<void>;
|
|
655
697
|
declare const fetchPromotion: (id: EntityId, params?: FetchByIdParams, options?: RequestOptions) => Promise<Promotion | null>;
|
|
656
698
|
/**
|
|
@@ -769,7 +811,7 @@ declare function buildConsumerMap(consumers: Consumer[] | null | undefined): {
|
|
|
769
811
|
*
|
|
770
812
|
* Like `SHOPWAVE_ENTITIES`, this table is shared by the client functions
|
|
771
813
|
* (`fetchMerchant`, `fetchUser`, `uploadImage`, …) and the server route
|
|
772
|
-
* handlers in `react-shopwave-connect/
|
|
814
|
+
* handlers in `react-shopwave-connect/server`, so the two halves of the contract
|
|
773
815
|
* can't drift apart. These aren't in `SHOPWAVE_ENTITIES` because they aren't
|
|
774
816
|
* keyed collections: `GET /merchant` answers `{ merchant: {…} }`, not a map by id.
|
|
775
817
|
*/
|
|
@@ -816,6 +858,35 @@ declare const SHOPWAVE_UPLOAD: Readonly<{
|
|
|
816
858
|
kindField: "kind";
|
|
817
859
|
}>;
|
|
818
860
|
declare function isUploadKind(value: unknown): value is UploadKind;
|
|
861
|
+
/**
|
|
862
|
+
* Read-only lists that aren't records: the merchant's distinct tags.
|
|
863
|
+
*
|
|
864
|
+
* Like `SHOPWAVE_RESOURCES`, shared by the client functions
|
|
865
|
+
* (`fetchProductTags`, `fetchProductInstanceTags`) and the server route
|
|
866
|
+
* handlers (`shopwave.lookup(kind)`), so the two halves can't drift apart.
|
|
867
|
+
*
|
|
868
|
+
* - productTags: `GET /product/tags` → `{ tags: string[] }`, every distinct tag
|
|
869
|
+
* on the merchant's products. No parameters. The API reference says
|
|
870
|
+
* "internal SKU tags are excluded", but the live API includes system tags
|
|
871
|
+
* written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
|
|
872
|
+
* test merchant 5644, 29 Oct 2026). Apps that offer the list as suggestions
|
|
873
|
+
* filter those themselves. Tags of deleted products drop out of the list.
|
|
874
|
+
* - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
|
|
875
|
+
* the same for price instances (channels such as "Eat In", "Takeout").
|
|
876
|
+
*
|
|
877
|
+
* The app route for instance tags is `products/instance-tags`, one segment
|
|
878
|
+
* under `products`, so it sits beside `products/[id]` without nesting deeper.
|
|
879
|
+
*/
|
|
880
|
+
interface LookupDefinition {
|
|
881
|
+
/** App route: `/api/<route>`. */
|
|
882
|
+
route: string;
|
|
883
|
+
/** Key of the list in the response (`{ tags: [...] }`). */
|
|
884
|
+
key: string;
|
|
885
|
+
/** Shopwave API path. */
|
|
886
|
+
upstream: string;
|
|
887
|
+
}
|
|
888
|
+
type LookupKind = "productTags" | "productInstanceTags";
|
|
889
|
+
declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
|
|
819
890
|
//#endregion
|
|
820
891
|
//#region src/core/imageFit.d.ts
|
|
821
892
|
/**
|
|
@@ -1213,6 +1284,26 @@ declare function useEmployee(params?: FetchEmployeesParams, options?: RequestOpt
|
|
|
1213
1284
|
*/
|
|
1214
1285
|
declare function useProduct(params?: FetchProductsParams, options?: RequestOptions): QueryState<Product[]>;
|
|
1215
1286
|
//#endregion
|
|
1287
|
+
//#region src/hooks/useProductTags.d.ts
|
|
1288
|
+
type LookupOptions = RequestOptions & {
|
|
1289
|
+
/** Fetch only when true (e.g. once a tag field is first opened). Defaults to true. */
|
|
1290
|
+
enabled?: boolean;
|
|
1291
|
+
};
|
|
1292
|
+
/**
|
|
1293
|
+
* The merchant's distinct product tags, for a tag field's suggestions.
|
|
1294
|
+
* `data` is `string[]` once loaded.
|
|
1295
|
+
*
|
|
1296
|
+
* @example
|
|
1297
|
+
* const [opened, setOpened] = useState(false);
|
|
1298
|
+
* const { data: tags, loading } = useProductTags({ enabled: opened });
|
|
1299
|
+
*/
|
|
1300
|
+
declare function useProductTags(options?: LookupOptions): QueryState<string[]>;
|
|
1301
|
+
/**
|
|
1302
|
+
* The merchant's distinct price-instance (channel) tags: Eat In, Takeout, …
|
|
1303
|
+
* `data` is `string[]` once loaded.
|
|
1304
|
+
*/
|
|
1305
|
+
declare function useProductInstanceTags(options?: LookupOptions): QueryState<string[]>;
|
|
1306
|
+
//#endregion
|
|
1216
1307
|
//#region src/hooks/usePromotion.d.ts
|
|
1217
1308
|
/**
|
|
1218
1309
|
* Auto-fetches promotions on mount and whenever the params change.
|
|
@@ -1366,5 +1457,5 @@ interface UseBasketReportReturn {
|
|
|
1366
1457
|
*/
|
|
1367
1458
|
declare function useBasketReport(options?: RequestOptions): UseBasketReportReturn;
|
|
1368
1459
|
//#endregion
|
|
1369
|
-
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, MutationState, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, QueryState, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, UseBasketReportReturn, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, useBasketReport, useCategory, useConsumer, useDelete, useEmployee, useLogout, useMerchant, useProduct, usePromotion, useReport, useSession, useStore, useSubmit, useUpdateMerchant, useUploadImage, useUploadMerchantImage, useUser, validateMerchant, withToken };
|
|
1460
|
+
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, MutationState, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, QueryState, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, UseBasketReportReturn, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, useBasketReport, useCategory, useConsumer, useDelete, useEmployee, useLogout, useMerchant, useProduct, useProductInstanceTags, useProductTags, usePromotion, useReport, useSession, useStore, useSubmit, useUpdateMerchant, useUploadImage, useUploadMerchantImage, useUser, validateMerchant, withToken };
|
|
1370
1461
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -351,6 +351,106 @@ async function fetchProductsMap(productIds, options = {}, batchSize = 200) {
|
|
|
351
351
|
return result;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region src/core/resources.ts
|
|
356
|
+
/**
|
|
357
|
+
* - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
|
|
358
|
+
* updates it (without an `id` the API would create a second merchant, so the
|
|
359
|
+
* route requires one).
|
|
360
|
+
* - user: `GET /user` (read-only here; the API's `POST /user` invites users and
|
|
361
|
+
* needs the admin scope).
|
|
362
|
+
*/
|
|
363
|
+
const SHOPWAVE_RESOURCES = Object.freeze({
|
|
364
|
+
merchant: {
|
|
365
|
+
route: "merchant",
|
|
366
|
+
key: "merchant",
|
|
367
|
+
upstream: "merchant",
|
|
368
|
+
writable: true
|
|
369
|
+
},
|
|
370
|
+
user: {
|
|
371
|
+
route: "user",
|
|
372
|
+
key: "user",
|
|
373
|
+
upstream: "user",
|
|
374
|
+
writable: false
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
/** `UploadKind` → the API's `contentType` value. */
|
|
378
|
+
const UPLOAD_KINDS = Object.freeze({
|
|
379
|
+
merchant: "merchant",
|
|
380
|
+
merchantFeature: "merchantFeature",
|
|
381
|
+
product: "product",
|
|
382
|
+
user: "user",
|
|
383
|
+
applicationLogo: "applicaionLogo",
|
|
384
|
+
applicationImages: "applicaionImages"
|
|
385
|
+
});
|
|
386
|
+
/** How uploads are addressed (app route and Shopwave uploader). */
|
|
387
|
+
const SHOPWAVE_UPLOAD = Object.freeze({
|
|
388
|
+
route: "upload",
|
|
389
|
+
upstream: "uploader",
|
|
390
|
+
kindHeader: "contentType",
|
|
391
|
+
fileField: "file",
|
|
392
|
+
kindField: "kind"
|
|
393
|
+
});
|
|
394
|
+
function isUploadKind(value) {
|
|
395
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
|
|
396
|
+
}
|
|
397
|
+
const SHOPWAVE_LOOKUPS = Object.freeze({
|
|
398
|
+
productTags: {
|
|
399
|
+
route: "products/tags",
|
|
400
|
+
key: "tags",
|
|
401
|
+
upstream: "product/tags"
|
|
402
|
+
},
|
|
403
|
+
productInstanceTags: {
|
|
404
|
+
route: "products/instance-tags",
|
|
405
|
+
key: "tags",
|
|
406
|
+
upstream: "product/instance/tags"
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
//#endregion
|
|
411
|
+
//#region src/core/productTags.ts
|
|
412
|
+
/**
|
|
413
|
+
* Turns a tag list from the API into clean strings: trims each tag, drops
|
|
414
|
+
* blanks and anything that isn't text, and removes exact duplicates (first one
|
|
415
|
+
* wins). The API's own order is kept. A map is accepted too (its values are
|
|
416
|
+
* used), in case the API ever answers keyed by id.
|
|
417
|
+
*/
|
|
418
|
+
function normalizeTagList(value) {
|
|
419
|
+
const list = Array.isArray(value) ? value : value && typeof value === "object" ? Object.values(value) : [];
|
|
420
|
+
const seen = /* @__PURE__ */ new Set();
|
|
421
|
+
const out = [];
|
|
422
|
+
for (const item of list) {
|
|
423
|
+
if (typeof item !== "string" && typeof item !== "number") continue;
|
|
424
|
+
const tag = String(item).trim();
|
|
425
|
+
if (!tag || seen.has(tag)) continue;
|
|
426
|
+
seen.add(tag);
|
|
427
|
+
out.push(tag);
|
|
428
|
+
}
|
|
429
|
+
return out;
|
|
430
|
+
}
|
|
431
|
+
async function fetchLookup(kind, options) {
|
|
432
|
+
const def = SHOPWAVE_LOOKUPS[kind];
|
|
433
|
+
if (!def) throw new Error(`Unknown Shopwave lookup "${kind}"`);
|
|
434
|
+
const json = await apiGet(`/api/${def.route}`, {}, options);
|
|
435
|
+
assertNoApiErrors(json, 200);
|
|
436
|
+
return normalizeTagList(json?.[def.key]);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Every distinct tag used on the merchant's products (`GET /product/tags`),
|
|
440
|
+
* for a tag field's suggestions. Returns `[]` when there are none.
|
|
441
|
+
*/
|
|
442
|
+
function fetchProductTags(options = {}) {
|
|
443
|
+
return fetchLookup("productTags", options);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Every distinct tag used on the merchant's price instances
|
|
447
|
+
* (`GET /product/instance/tags`): the channel names (Eat In, Takeout, …).
|
|
448
|
+
* Returns `[]` when there are none.
|
|
449
|
+
*/
|
|
450
|
+
function fetchProductInstanceTags(options = {}) {
|
|
451
|
+
return fetchLookup("productInstanceTags", options);
|
|
452
|
+
}
|
|
453
|
+
|
|
354
454
|
//#endregion
|
|
355
455
|
//#region src/core/promotion.ts
|
|
356
456
|
/** Promotion rule identifiers as stored by the Shopwave API. */
|
|
@@ -485,7 +585,10 @@ async function submitEntity({ endpoint, method = "POST", payload }, options = {}
|
|
|
485
585
|
* (https://developer.merchantstack.com/api-reference.html) and checked against
|
|
486
586
|
* the live API where noted:
|
|
487
587
|
* - category/product/store: GET filtered by `<x>Ids`, POST upsert, DELETE with `<x>Id` → 205.
|
|
488
|
-
* - promotion: no DELETE;
|
|
588
|
+
* - promotion: no DELETE; promotions are never deleted, only expired. Expiring
|
|
589
|
+
* reads the promotion and saves the whole record back with `endDate` = now (and
|
|
590
|
+
* `startDate` = now too if it hadn't started); the live API rejects a partial
|
|
591
|
+
* `{ id, endDate }` save with error 899. Dates are UTC `YYYY-MM-DD HH:mm:ss`.
|
|
489
592
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
490
593
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
491
594
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
@@ -526,7 +629,9 @@ const SHOPWAVE_ENTITIES = Object.freeze({
|
|
|
526
629
|
idHeader: "promotionId",
|
|
527
630
|
writable: true,
|
|
528
631
|
deleteMode: "retire",
|
|
529
|
-
retireField: "endDate"
|
|
632
|
+
retireField: "endDate",
|
|
633
|
+
retireWithRecord: true,
|
|
634
|
+
retireStartField: "startDate"
|
|
530
635
|
},
|
|
531
636
|
employee: {
|
|
532
637
|
route: "employees",
|
|
@@ -601,7 +706,8 @@ async function saveEntity(kind, item, options = {}) {
|
|
|
601
706
|
/**
|
|
602
707
|
* Deletes one entity (a soft delete: it stays readable with `deleted: true`).
|
|
603
708
|
* Employees and promotions can't be deleted in Shopwave; for them the route
|
|
604
|
-
* sets `exitDate` / `endDate` to now instead (see `SHOPWAVE_ENTITIES`)
|
|
709
|
+
* sets `exitDate` / `endDate` to now instead (see `SHOPWAVE_ENTITIES`), and a
|
|
710
|
+
* promotion is saved back whole (see {@link deletePromotion}).
|
|
605
711
|
*
|
|
606
712
|
* Shopwave answers 205 with an empty body — also for ids that don't exist — so
|
|
607
713
|
* a resolved promise means "the API accepted the request", not "a record was
|
|
@@ -642,7 +748,12 @@ const saveStore = (store, options) => saveEntity("store", store, options);
|
|
|
642
748
|
const deleteStore = (id, options) => deleteEntityById("store", id, options);
|
|
643
749
|
const fetchStore = (id, params, options) => fetchEntityById("store", id, params, options);
|
|
644
750
|
const savePromotion = (promotion, options) => saveEntity("promotion", promotion, options);
|
|
645
|
-
/**
|
|
751
|
+
/**
|
|
752
|
+
* Expires a promotion (Shopwave never deletes promotions). The route reads the
|
|
753
|
+
* promotion and saves it back with `endDate` set to now; a promotion that hasn't
|
|
754
|
+
* started yet gets `startDate` = `endDate` = now. Rejects if the promotion doesn't
|
|
755
|
+
* exist or the save fails.
|
|
756
|
+
*/
|
|
646
757
|
const deletePromotion = (id, options) => deleteEntityById("promotion", id, options);
|
|
647
758
|
const fetchPromotion = (id, params, options) => fetchEntityById("promotion", id, params, options);
|
|
648
759
|
/**
|
|
@@ -801,50 +912,6 @@ function buildConsumerMap(consumers) {
|
|
|
801
912
|
return map;
|
|
802
913
|
}
|
|
803
914
|
|
|
804
|
-
//#endregion
|
|
805
|
-
//#region src/core/resources.ts
|
|
806
|
-
/**
|
|
807
|
-
* - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
|
|
808
|
-
* updates it (without an `id` the API would create a second merchant, so the
|
|
809
|
-
* route requires one).
|
|
810
|
-
* - user: `GET /user` (read-only here; the API's `POST /user` invites users and
|
|
811
|
-
* needs the admin scope).
|
|
812
|
-
*/
|
|
813
|
-
const SHOPWAVE_RESOURCES = Object.freeze({
|
|
814
|
-
merchant: {
|
|
815
|
-
route: "merchant",
|
|
816
|
-
key: "merchant",
|
|
817
|
-
upstream: "merchant",
|
|
818
|
-
writable: true
|
|
819
|
-
},
|
|
820
|
-
user: {
|
|
821
|
-
route: "user",
|
|
822
|
-
key: "user",
|
|
823
|
-
upstream: "user",
|
|
824
|
-
writable: false
|
|
825
|
-
}
|
|
826
|
-
});
|
|
827
|
-
/** `UploadKind` → the API's `contentType` value. */
|
|
828
|
-
const UPLOAD_KINDS = Object.freeze({
|
|
829
|
-
merchant: "merchant",
|
|
830
|
-
merchantFeature: "merchantFeature",
|
|
831
|
-
product: "product",
|
|
832
|
-
user: "user",
|
|
833
|
-
applicationLogo: "applicaionLogo",
|
|
834
|
-
applicationImages: "applicaionImages"
|
|
835
|
-
});
|
|
836
|
-
/** How uploads are addressed (app route and Shopwave uploader). */
|
|
837
|
-
const SHOPWAVE_UPLOAD = Object.freeze({
|
|
838
|
-
route: "upload",
|
|
839
|
-
upstream: "uploader",
|
|
840
|
-
kindHeader: "contentType",
|
|
841
|
-
fileField: "file",
|
|
842
|
-
kindField: "kind"
|
|
843
|
-
});
|
|
844
|
-
function isUploadKind(value) {
|
|
845
|
-
return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
915
|
//#endregion
|
|
849
916
|
//#region src/core/imageFit.ts
|
|
850
917
|
/**
|
|
@@ -1511,6 +1578,33 @@ function useProduct(params = {}, options) {
|
|
|
1511
1578
|
]);
|
|
1512
1579
|
}
|
|
1513
1580
|
|
|
1581
|
+
//#endregion
|
|
1582
|
+
//#region src/hooks/useProductTags.ts
|
|
1583
|
+
/**
|
|
1584
|
+
* The merchant's distinct product tags, for a tag field's suggestions.
|
|
1585
|
+
* `data` is `string[]` once loaded.
|
|
1586
|
+
*
|
|
1587
|
+
* @example
|
|
1588
|
+
* const [opened, setOpened] = useState(false);
|
|
1589
|
+
* const { data: tags, loading } = useProductTags({ enabled: opened });
|
|
1590
|
+
*/
|
|
1591
|
+
function useProductTags(options) {
|
|
1592
|
+
return useQuery((signal) => fetchProductTags({
|
|
1593
|
+
...options,
|
|
1594
|
+
signal
|
|
1595
|
+
}), [options?.baseUrl, options?.token], options?.enabled ?? true);
|
|
1596
|
+
}
|
|
1597
|
+
/**
|
|
1598
|
+
* The merchant's distinct price-instance (channel) tags: Eat In, Takeout, …
|
|
1599
|
+
* `data` is `string[]` once loaded.
|
|
1600
|
+
*/
|
|
1601
|
+
function useProductInstanceTags(options) {
|
|
1602
|
+
return useQuery((signal) => fetchProductInstanceTags({
|
|
1603
|
+
...options,
|
|
1604
|
+
signal
|
|
1605
|
+
}), [options?.baseUrl, options?.token], options?.enabled ?? true);
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1514
1608
|
//#endregion
|
|
1515
1609
|
//#region src/hooks/usePromotion.ts
|
|
1516
1610
|
/**
|
|
@@ -1821,5 +1915,5 @@ function useBasketReport(options) {
|
|
|
1821
1915
|
}
|
|
1822
1916
|
|
|
1823
1917
|
//#endregion
|
|
1824
|
-
export { DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, PromotionRuleSet, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, ShopwaveApiError, UPLOAD_KINDS, apiDelete, apiGet, apiRequest, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, useBasketReport, useCategory, useConsumer, useDelete, useEmployee, useLogout, useMerchant, useProduct, usePromotion, useReport, useSession, useStore, useSubmit, useUpdateMerchant, useUploadImage, useUploadMerchantImage, useUser, validateMerchant, withToken };
|
|
1918
|
+
export { DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, PromotionRuleSet, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, ShopwaveApiError, UPLOAD_KINDS, apiDelete, apiGet, apiRequest, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, useBasketReport, useCategory, useConsumer, useDelete, useEmployee, useLogout, useMerchant, useProduct, useProductInstanceTags, useProductTags, usePromotion, useReport, useSession, useStore, useSubmit, useUpdateMerchant, useUploadImage, useUploadMerchantImage, useUser, validateMerchant, withToken };
|
|
1825
1919
|
//# sourceMappingURL=index.js.map
|