@isoftdata/svelte-ecommerce 1.0.0-beta.0 → 1.0.0-beta.2

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.
@@ -1,66 +1,54 @@
1
- <script lang="ts">
2
- import type { i18n } from 'i18next'
3
-
4
- import { getContext } from 'svelte'
5
-
6
- import Table, { Td } from '@isoftdata/svelte-table'
7
- import Checkbox from '@isoftdata/svelte-checkbox'
8
- import { translate as defaultTranslate } from '@isoftdata/utility-string'
9
-
10
- const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
11
-
12
- import type { PolicyRowWithChecked } from './utils.js'
13
-
14
- interface Props {
15
- title: string
16
- policies: PolicyRowWithChecked[]
17
- selectedPolicyIds: string[]
18
- onSelectionChange: (selectedIds: string[]) => void
19
- }
20
-
21
- let { title, policies, selectedPolicyIds, onSelectionChange }: Props = $props()
22
-
23
- function handleCheckboxChange(policy: PolicyRowWithChecked, checked: boolean) {
24
- let updatedIds: string[]
25
-
26
- if (checked) {
27
- // Add policy to the list if not already present
28
- if (!selectedPolicyIds.includes(policy.policyId)) {
29
- updatedIds = [...selectedPolicyIds, policy.policyId]
30
- } else {
31
- updatedIds = selectedPolicyIds
32
- }
33
- } else {
34
- // Remove policy from the list
35
- updatedIds = selectedPolicyIds.filter(id => id !== policy.policyId)
36
- }
37
-
38
- onSelectionChange(updatedIds)
39
- }
40
- </script>
41
-
42
- <div class="mb-4">
43
- <Table
44
- responsive
45
- {title}
46
- stickyHeader
47
- rows={policies}
48
- parentClass="overflow-y-auto mh-500"
49
- columns={[
50
- { property: 'checked', name: translate('configuration.ecommerce.selected', 'Selected'), width: '100px' },
51
- { property: 'name', name: translate('configuration.ecommerce.policy', 'Policy'), defaultSortColumn: true },
52
- ]}
53
- >
54
- {#snippet children({ row })}
55
- <tr>
56
- <Td property="checked">
57
- <Checkbox
58
- checked={row.checked}
59
- onchange={e => handleCheckboxChange(row, e.currentTarget.checked)}
60
- />
61
- </Td>
62
- <td>{row.name}</td>
63
- </tr>
64
- {/snippet}
65
- </Table>
66
- </div>
1
+ <script lang="ts">
2
+ import type { i18n } from 'i18next'
3
+
4
+ import { getContext } from 'svelte'
5
+
6
+ import Table, { Td } from '@isoftdata/svelte-table'
7
+ import Checkbox from '@isoftdata/svelte-checkbox'
8
+ import { translate as defaultTranslate } from '@isoftdata/utility-string'
9
+
10
+ const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
11
+
12
+ import type { PolicyRowWithChecked } from './utils.js'
13
+
14
+ interface Props {
15
+ title: string
16
+ policies: Array<PolicyRowWithChecked>
17
+ selectedPolicyIds: Array<string>
18
+ onSelectionChange: (selectedIds: Array<string>) => void
19
+ }
20
+
21
+ let { title, policies, selectedPolicyIds, onSelectionChange }: Props = $props()
22
+
23
+ function handleCheckboxChange(policy: PolicyRowWithChecked, checked: boolean) {
24
+ const updatedIds = new Set<string>(selectedPolicyIds)
25
+ checked ? updatedIds.add(policy.policyId) : updatedIds.delete(policy.policyId)
26
+ onSelectionChange(Array.from(updatedIds))
27
+ }
28
+ </script>
29
+
30
+ <div class="mb-4">
31
+ <Table
32
+ responsive
33
+ {title}
34
+ stickyHeader
35
+ rows={policies}
36
+ parentClass="overflow-y-auto mh-500"
37
+ columns={[
38
+ { property: 'checked', name: translate('configuration.ecommerce.selected', 'Selected'), width: '100px' },
39
+ { property: 'name', name: translate('configuration.ecommerce.policy', 'Policy'), defaultSortColumn: true },
40
+ ]}
41
+ >
42
+ {#snippet children({ row })}
43
+ <tr>
44
+ <Td property="checked">
45
+ <Checkbox
46
+ checked={row.checked}
47
+ onchange={e => handleCheckboxChange(row, e.currentTarget.checked)}
48
+ />
49
+ </Td>
50
+ <td>{row.name}</td>
51
+ </tr>
52
+ {/snippet}
53
+ </Table>
54
+ </div>
@@ -1,9 +1,9 @@
1
1
  import type { PolicyRowWithChecked } from './utils.js';
2
2
  interface Props {
3
3
  title: string;
4
- policies: PolicyRowWithChecked[];
5
- selectedPolicyIds: string[];
6
- onSelectionChange: (selectedIds: string[]) => void;
4
+ policies: Array<PolicyRowWithChecked>;
5
+ selectedPolicyIds: Array<string>;
6
+ onSelectionChange: (selectedIds: Array<string>) => void;
7
7
  }
8
8
  declare const PolicyList: import("svelte").Component<Props, {}, "">;
9
9
  type PolicyList = ReturnType<typeof PolicyList>;
@@ -3,9 +3,9 @@ export type LengthUnit = 'INCH' | 'FEET' | 'CENTIMETER' | 'METER';
3
3
  export type WeightUnit = 'POUND' | 'KILOGRAM' | 'OUNCE' | 'GRAM';
4
4
  export type TimeUnit = 'YEAR' | 'MONTH' | 'DAY' | 'HOUR' | 'CALENDAR_DAY' | 'BUSINESS_DAY';
5
5
  export interface EbayStaticData {
6
- lengthUnits: LengthUnit[];
7
- weightUnits: WeightUnit[];
8
- timeUnits: TimeUnit[];
9
- packageTypes: PackageType[];
6
+ lengthUnits: Array<LengthUnit>;
7
+ weightUnits: Array<WeightUnit>;
8
+ timeUnits: Array<TimeUnit>;
9
+ packageTypes: Array<PackageType>;
10
10
  }
11
11
  export declare const ebayStaticData: EbayStaticData;
@@ -2,8 +2,8 @@ import type { PackageType } from './types.js';
2
2
  export type LengthUnit = 'in' | 'cm' | 'm' | 'ft';
3
3
  export type WeightUnit = 'g' | 'lb' | 'kg' | 'oz';
4
4
  export interface HtpStaticData {
5
- lengthUnits: LengthUnit[];
6
- weightUnits: WeightUnit[];
7
- packageTypes: PackageType[];
5
+ lengthUnits: Array<LengthUnit>;
6
+ weightUnits: Array<WeightUnit>;
7
+ packageTypes: Array<PackageType>;
8
8
  }
9
9
  export declare const htpStaticData: HtpStaticData;
package/dist/data/htp.js CHANGED
@@ -18,5 +18,5 @@ export const htpStaticData = {
18
18
  name: 'Pallet',
19
19
  partnerValue: 'Pallet',
20
20
  },
21
- ]
21
+ ],
22
22
  };
@@ -1,6 +1,6 @@
1
1
  import { convertAndApplyTemplate, validateInventoryListingDetails } from './index.js';
2
- import klona from 'klona';
3
- const newInventoryListingDetailTemplate = {
2
+ import { klona } from 'klona';
3
+ const newInventoryListingDetailTemplate = Object.freeze({
4
4
  active: false,
5
5
  convertedListingDetails: null,
6
6
  duration: 'GTC',
@@ -27,7 +27,7 @@ const newInventoryListingDetailTemplate = {
27
27
  merchantLocationKey: '',
28
28
  oemNumber: '',
29
29
  paymentPolicy: [],
30
- returnPolicy: []
30
+ returnPolicy: [],
31
31
  },
32
32
  price: null,
33
33
  quantity: null,
@@ -40,14 +40,14 @@ const newInventoryListingDetailTemplate = {
40
40
  storeId: 0,
41
41
  upc: '',
42
42
  weight: null,
43
- weightUnit: null
44
- };
43
+ weightUnit: null,
44
+ });
45
45
  /**
46
46
  * Shared method for creating an inventorylistingdetail row
47
47
  * Includes minimum validation and may return undefined if certain configuration settings determine the inventory item doesn't get a listing created
48
48
  */
49
49
  export const buildEbayListing = (buildEbayListingInput) => {
50
- const { categoryMapping, conditionMapping, ecommercePartnerConfiguration, existingListing, inventoryRow, inventoryTypeListingDefaults, inventoryType, partFileList } = buildEbayListingInput;
50
+ const { categoryMapping, conditionMapping, ecommercePartnerConfiguration, existingListing, inventoryRow, inventoryTypeListingDefaults, inventoryType, partFileList, } = buildEbayListingInput;
51
51
  if (!ecommercePartnerConfiguration) {
52
52
  // No partner config, no listing
53
53
  return;
@@ -63,19 +63,19 @@ export const buildEbayListing = (buildEbayListingInput) => {
63
63
  if (existingListing && existingListing.listingStatus === 'cancelled') {
64
64
  return;
65
65
  }
66
- // Is the ecommerce config set to active?
66
+ // Is the ecommerce config set to active?
67
67
  if (ecommercePartnerConfiguration && !ecommercePartnerConfiguration.active) {
68
68
  // Ecommerce config set to inactive
69
69
  return;
70
70
  }
71
- // Is store mapped and active?
71
+ // Is store mapped and active?
72
72
  const matchingStoreConfig = ecommercePartnerConfiguration?.defaults?.store?.find(store => store.storeId === inventoryRow.storeId);
73
73
  if (!matchingStoreConfig) {
74
- // No store/location configured, do not create listing row
74
+ // No store/location configured, do not create listing row
75
75
  return;
76
76
  }
77
77
  if (matchingStoreConfig && !matchingStoreConfig.active) {
78
- // Store configured to inactive, do not create listing row
78
+ // Store configured to inactive, do not create listing row
79
79
  return;
80
80
  }
81
81
  // Check if part type + category configuration is inactive
@@ -101,7 +101,7 @@ export const buildEbayListing = (buildEbayListingInput) => {
101
101
  merchantLocationKey: '',
102
102
  oemNumber: '',
103
103
  paymentPolicy: [],
104
- returnPolicy: []
104
+ returnPolicy: [],
105
105
  };
106
106
  }
107
107
  }
@@ -110,7 +110,10 @@ export const buildEbayListing = (buildEbayListingInput) => {
110
110
  }
111
111
  // Static
112
112
  listingDetails.ecommercePartnerId = ecommercePartnerId;
113
- listingDetails.partnerSpecificDetails.merchantLocationKey ?? listingDetails.partnerSpecificDetails.merchantLocationKey ?? matchingStoreConfig?.merchantLocationKey ?? null;
113
+ listingDetails.partnerSpecificDetails.merchantLocationKey ??
114
+ listingDetails.partnerSpecificDetails.merchantLocationKey ??
115
+ matchingStoreConfig?.merchantLocationKey ??
116
+ null;
114
117
  // Mapped
115
118
  listingDetails.ecommerceCategoryId = listingDetails.ecommerceCategoryId
116
119
  ? listingDetails.ecommerceCategoryId
@@ -118,6 +121,7 @@ export const buildEbayListing = (buildEbayListingInput) => {
118
121
  // Use latest from inventory
119
122
  // TODO: I'll need to check some of these, they may not allow changes on the config screen and inventory.* is the only truth avail
120
123
  listingDetails.quantity = inventoryRow.quantity;
124
+ listingDetails.inventoryId = inventoryRow.inventoryId;
121
125
  listingDetails.storeId = listingDetails.storeId || inventoryRow.storeId;
122
126
  listingDetails.sku = listingDetails.sku || inventoryRow.tagNumber;
123
127
  listingDetails.price = listingDetails.price || inventoryRow.retailPrice || null;
@@ -160,8 +164,8 @@ export const buildEbayListing = (buildEbayListingInput) => {
160
164
  if (validationErrors.length) {
161
165
  listingDetails.listingStatus = 'error';
162
166
  const errObj = {
163
- type: "validation",
164
- messages: validationErrors
167
+ type: 'validation',
168
+ messages: validationErrors,
165
169
  };
166
170
  listingDetails.message = [errObj];
167
171
  listingDetails.active = false;
@@ -204,7 +208,7 @@ const getFirstValidTemplateValue = (existingValue, partTypeTemplate, storeTempla
204
208
  const result = convertAndApplyTemplate({
205
209
  inventory: inventoryRow,
206
210
  inventoryTypeName,
207
- template
211
+ template,
208
212
  });
209
213
  if (result && result.trim() !== '') {
210
214
  return result;
@@ -246,7 +250,7 @@ export function processImageUrls(partFileList) {
246
250
  'image/png',
247
251
  'image/tiff',
248
252
  'image/tif',
249
- 'image/webp'
253
+ 'image/webp',
250
254
  ];
251
255
  // Create a new array that will only contain valid files
252
256
  const updatedImageUrlArray = [];
@@ -264,12 +268,11 @@ export function processImageUrls(partFileList) {
264
268
  fileId: file.fileId,
265
269
  fileName: file.name,
266
270
  rank: file.rank ?? 0,
267
- mimeType: file.mimeType
271
+ mimeType: file.mimeType,
268
272
  });
269
273
  }
270
274
  // Sort by rank to maintain order, presumably the "top" image in the list of images given to eBay for a listing is shown first
271
275
  updatedImageUrlArray.sort((a, b) => a.rank - b.rank);
272
- // Stringify it so we return it in same format it was received
273
276
  return updatedImageUrlArray.length > 0 ? updatedImageUrlArray : null;
274
277
  }
275
278
  // TODO: pretty much identical to the next method, could probably have just combined and returned two things
@@ -286,14 +289,9 @@ function findMatchingPartTypeConfig(inventoryRow, inventoryTypeListingDetails) {
286
289
  if (categoryMatch) {
287
290
  return categoryMatch;
288
291
  }
289
- // TODO: this one's iffy, double-check if types match reality, also make sure we can't have more than one
290
- const allCategoryMatch = inventoryTypeListingDetails.find(config => config.categoryName === '');
291
- if (allCategoryMatch) {
292
- return allCategoryMatch;
293
- }
294
- return;
292
+ return inventoryTypeListingDetails.find(config => config.categoryName === '');
295
293
  }
296
- // Needed a separate method to check what I think are all of the ways we'd need to check
294
+ // Needed a separate method to check what I think are all of the ways we'd need to check
297
295
  // part type
298
296
  function shouldSkipListingDueToInactiveConfiguration(inventoryRow, inventoryTypeListingDetails) {
299
297
  // Early return if no configurations to check
@@ -1,11 +1,11 @@
1
- import type { InventoryRow, InventoryDetailsForTemplate } from "../utils.js";
1
+ import type { InventoryRow, InventoryDetailsForTemplate } from '../utils.js';
2
2
  /**
3
3
  *
4
4
  * @param template Configured in ecommerce settings
5
5
  * @returns a string with template values replaced by inventory values
6
6
  * Convert product inventory row to a shared type for the token replacement
7
7
  */
8
- export declare function convertAndApplyTemplate({ inventory, inventoryTypeName, template }: {
8
+ export declare function convertAndApplyTemplate({ inventory, inventoryTypeName, template, }: {
9
9
  inventory: InventoryRow;
10
10
  inventoryTypeName: string | null | undefined;
11
11
  template: string | null | undefined;
@@ -4,41 +4,41 @@
4
4
  * @returns a string with template values replaced by inventory values
5
5
  * Convert product inventory row to a shared type for the token replacement
6
6
  */
7
- export function convertAndApplyTemplate({ inventory, inventoryTypeName, template }) {
7
+ export function convertAndApplyTemplate({ inventory, inventoryTypeName, template, }) {
8
8
  if (!template)
9
9
  return null;
10
10
  // Map the inventory object to the InventoryDetails type expected by replaceInventoryTokens
11
11
  const mappedInventoryDetails = {
12
12
  inventoryId: inventory.inventoryId,
13
- vehicleMake: inventory.make || undefined,
14
- vehicleModel: inventory.model || undefined,
15
- year: inventory.year || undefined,
16
- description: inventory.description || undefined,
17
- price: inventory.retailPrice || undefined,
18
- manufacturer: inventory.partManufacturer || undefined,
19
- model: inventory.partModel || undefined,
20
- partType: inventoryTypeName || undefined,
21
- category: inventory.category || undefined,
22
- store: inventory.storeId?.toString() || undefined,
23
- tagNumber: inventory.tagNumber || undefined,
24
- condition: inventory.condition || undefined,
25
- flexLabel1: inventory.label1 || undefined,
26
- flexLabel2: inventory.label2 || undefined,
27
- flexLabel3: inventory.label3 || undefined,
28
- flexLabel4: inventory.label4 || undefined,
29
- flexValue1: inventory.data1 || undefined,
30
- flexValue2: inventory.data2 || undefined,
31
- flexValue3: inventory.data3 || undefined,
32
- flexValue4: inventory.data4 || undefined,
33
- oemNumber: inventory.oemNumber || undefined,
34
- side: inventory.side || undefined,
35
- serialNumber: inventory.serialNumber || undefined,
36
- weight: inventory.weight || undefined,
37
- upc: inventory.upc || undefined,
38
- notes: inventory.notes || undefined,
39
- quantity: inventory.quantity || undefined,
40
- partManufacturer: inventory.partManufacturer || undefined,
41
- partModel: inventory.partModel || undefined,
13
+ vehicleMake: inventory.make,
14
+ vehicleModel: inventory.model,
15
+ year: inventory.year,
16
+ description: inventory.description,
17
+ price: inventory.retailPrice,
18
+ manufacturer: inventory.partManufacturer,
19
+ model: inventory.partModel,
20
+ partType: inventoryTypeName,
21
+ category: inventory.category,
22
+ store: inventory.storeId?.toString(),
23
+ tagNumber: inventory.tagNumber,
24
+ condition: inventory.condition,
25
+ flexLabel1: inventory.label1,
26
+ flexLabel2: inventory.label2,
27
+ flexLabel3: inventory.label3,
28
+ flexLabel4: inventory.label4,
29
+ flexValue1: inventory.data1,
30
+ flexValue2: inventory.data2,
31
+ flexValue3: inventory.data3,
32
+ flexValue4: inventory.data4,
33
+ oemNumber: inventory.oemNumber,
34
+ side: inventory.side,
35
+ serialNumber: inventory.serialNumber,
36
+ weight: inventory.weight,
37
+ upc: inventory.upc,
38
+ notes: inventory.notes,
39
+ quantity: inventory.quantity,
40
+ partManufacturer: inventory.partManufacturer,
41
+ partModel: inventory.partModel,
42
42
  };
43
43
  // Replace tokens in the template and set the listingDescription
44
44
  return replaceInventoryTokens(template, mappedInventoryDetails);
@@ -64,8 +64,6 @@ export function convertAndApplyTemplate({ inventory, inventoryTypeName, template
64
64
  export function replaceInventoryTokens(template, inventoryDetails) {
65
65
  if (!template)
66
66
  return '';
67
- if (!inventoryDetails)
68
- return template;
69
67
  // Define token mappings (token name -> inventory property)
70
68
  const generalTokens = {
71
69
  '{?InventoryID}': 'inventoryId',
@@ -91,24 +89,24 @@ export function replaceInventoryTokens(template, inventoryDetails) {
91
89
  '{?FlexValue3}': 'flexValue3',
92
90
  '{?FlexValue4}': 'flexValue4',
93
91
  '{?OEMNumber}': 'oemNumber',
94
- '{?Side}': 'side'
92
+ '{?Side}': 'side',
95
93
  // Add more mappings as needed
96
94
  };
97
95
  // Pro-specific token mappings
98
96
  const proTokens = {
99
- '{?PartNum}': 'inventoryId'
97
+ '{?PartNum}': 'inventoryId',
100
98
  };
101
99
  // Enterprise-specific token mappings, need to confirm these
102
100
  const enterpriseTokenMappings = {
103
101
  '{?PartNumber}': 'inventoryId', // not sure on this one, supposed to be vendor part number
104
102
  '{?PartManufacturer}': 'partManufacturer',
105
- '{?PartModel}': 'partModel'
103
+ '{?PartModel}': 'partModel',
106
104
  };
107
105
  // Combine all token mappings
108
106
  const tokenMappings = {
109
107
  ...generalTokens,
110
108
  ...proTokens,
111
- ...enterpriseTokenMappings
109
+ ...enterpriseTokenMappings,
112
110
  };
113
111
  // Replace each token with its corresponding value
114
112
  let result = template;
@@ -116,7 +114,7 @@ export function replaceInventoryTokens(template, inventoryDetails) {
116
114
  // Create a global regex pattern to replace all occurrences
117
115
  const tokenPattern = new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
118
116
  // Check if the property exists in inventoryDetails
119
- if (inventoryDetails[property]) {
117
+ if (property in inventoryDetails) {
120
118
  result = result.replace(tokenPattern, String(inventoryDetails[property]));
121
119
  }
122
120
  else {
@@ -1,5 +1,5 @@
1
1
  // Pretty basic method to verify all required fields, the ebay-utility is more thorough on certain types
2
- // We could've just done required fields (and we may still), but this is a way to get a full list and to know when to set the active flag
2
+ // We could've just done required fields (and we may still), but this is a way to get a full list and to know when to set the active flag
3
3
  export function validateInventoryListingDetails(listingDetails) {
4
4
  const validationErrors = [];
5
5
  // Helper function for required integer fields
@@ -33,7 +33,7 @@ export function validateInventoryListingDetails(listingDetails) {
33
33
  if (value == null || value === undefined) {
34
34
  validationErrors.push(`${name} is required`);
35
35
  }
36
- else if (typeof value !== 'number' || isNaN(value)) {
36
+ else if (typeof value !== 'number' || Number.isNaN(value)) {
37
37
  validationErrors.push(`${name} must be a valid number`);
38
38
  }
39
39
  else if (!allowZero && value <= 0) {
@@ -69,9 +69,9 @@ export function validateInventoryListingDetails(listingDetails) {
69
69
  ]);
70
70
  validateRequiredNumbers([
71
71
  { key: 'price', name: 'Price' },
72
- { key: 'weight', name: 'Weight', allowZero: true }
72
+ { key: 'weight', name: 'Weight', allowZero: true },
73
73
  ]);
74
- // TODO: add public check and quantity check to ebay listing helper
74
+ // TODO: add public check and quantity check to ebay listing helper
75
75
  // price
76
76
  // quantity
77
77
  // weight
package/dist/index.d.ts CHANGED
@@ -8,4 +8,4 @@ export { default as EcommercePartTypeConfiguration } from './EcommercePartTypeCo
8
8
  export { buildEbayListing } from './helpers/index.js';
9
9
  export { ecommercePartnerStaticData } from './data/index.js';
10
10
  export type { PackageType } from './data/types.js';
11
- export type { BuildEbayListingInput, EbayCategory, EbayCategoryMap, EbayLocation, EbayPolicy, EcommerceCondition, EcommerceConditionMap, EcommercePartnerConfiguration, EcommercePartnerDefaults, EcommerceStoreConfig, EcommerceSharedDefaults, ExtendedEbayCategoryMap, ExtendedEcommerceConditionMap, ExtendedInventoryTypeListingDefaults, FileItem, ImageUrl, InventoryDetailsForTemplate, InventoryListingDetail, InventoryType, InventoryTypeCategory, InventoryTypeListingDefaults, InventoryRow, NewInventoryListingDetail, NewInventoryTypeListingDefaults, Store } from './utils.js';
11
+ export type * from './utils.js';