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

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
@@ -160,8 +163,8 @@ export const buildEbayListing = (buildEbayListingInput) => {
160
163
  if (validationErrors.length) {
161
164
  listingDetails.listingStatus = 'error';
162
165
  const errObj = {
163
- type: "validation",
164
- messages: validationErrors
166
+ type: 'validation',
167
+ messages: validationErrors,
165
168
  };
166
169
  listingDetails.message = [errObj];
167
170
  listingDetails.active = false;
@@ -204,7 +207,7 @@ const getFirstValidTemplateValue = (existingValue, partTypeTemplate, storeTempla
204
207
  const result = convertAndApplyTemplate({
205
208
  inventory: inventoryRow,
206
209
  inventoryTypeName,
207
- template
210
+ template,
208
211
  });
209
212
  if (result && result.trim() !== '') {
210
213
  return result;
@@ -246,7 +249,7 @@ export function processImageUrls(partFileList) {
246
249
  'image/png',
247
250
  'image/tiff',
248
251
  'image/tif',
249
- 'image/webp'
252
+ 'image/webp',
250
253
  ];
251
254
  // Create a new array that will only contain valid files
252
255
  const updatedImageUrlArray = [];
@@ -264,12 +267,11 @@ export function processImageUrls(partFileList) {
264
267
  fileId: file.fileId,
265
268
  fileName: file.name,
266
269
  rank: file.rank ?? 0,
267
- mimeType: file.mimeType
270
+ mimeType: file.mimeType,
268
271
  });
269
272
  }
270
273
  // 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
274
  updatedImageUrlArray.sort((a, b) => a.rank - b.rank);
272
- // Stringify it so we return it in same format it was received
273
275
  return updatedImageUrlArray.length > 0 ? updatedImageUrlArray : null;
274
276
  }
275
277
  // TODO: pretty much identical to the next method, could probably have just combined and returned two things
@@ -286,14 +288,9 @@ function findMatchingPartTypeConfig(inventoryRow, inventoryTypeListingDetails) {
286
288
  if (categoryMatch) {
287
289
  return categoryMatch;
288
290
  }
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;
291
+ return inventoryTypeListingDetails.find(config => config.categoryName === '');
295
292
  }
296
- // Needed a separate method to check what I think are all of the ways we'd need to check
293
+ // Needed a separate method to check what I think are all of the ways we'd need to check
297
294
  // part type
298
295
  function shouldSkipListingDueToInactiveConfiguration(inventoryRow, inventoryTypeListingDetails) {
299
296
  // 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';