@isoftdata/svelte-ecommerce 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/dist/EcommerceCategoryMapConfiguration.svelte +266 -0
- package/dist/EcommerceCategoryMapConfiguration.svelte.d.ts +14 -0
- package/dist/EcommerceConditionMapConfiguration.svelte +214 -0
- package/dist/EcommerceConditionMapConfiguration.svelte.d.ts +10 -0
- package/dist/EcommerceConfiguration.svelte +195 -0
- package/dist/EcommerceConfiguration.svelte.d.ts +22 -0
- package/dist/EcommerceDefaults.svelte +357 -0
- package/dist/EcommerceDefaults.svelte.d.ts +12 -0
- package/dist/EcommerceListingDetails.svelte +986 -0
- package/dist/EcommerceListingDetails.svelte.d.ts +18 -0
- package/dist/EcommercePartTypeConfig.svelte +305 -0
- package/dist/EcommercePartTypeConfig.svelte.d.ts +15 -0
- package/dist/EcommerceStoreConfiguration.svelte +263 -0
- package/dist/EcommerceStoreConfiguration.svelte.d.ts +13 -0
- package/dist/PolicyList.svelte +66 -0
- package/dist/PolicyList.svelte.d.ts +10 -0
- package/dist/data/ebay.d.ts +11 -0
- package/dist/data/ebay.js +31 -0
- package/dist/data/htp.d.ts +9 -0
- package/dist/data/htp.js +22 -0
- package/dist/data/index.d.ts +4 -0
- package/dist/data/index.js +6 -0
- package/dist/data/types.d.ts +4 -0
- package/dist/data/types.js +1 -0
- package/dist/helpers/index.d.ts +3 -0
- package/dist/helpers/index.js +3 -0
- package/dist/helpers/listing.d.ts +22 -0
- package/dist/helpers/listing.js +324 -0
- package/dist/helpers/template.d.ts +31 -0
- package/dist/helpers/template.js +131 -0
- package/dist/helpers/validation.d.ts +2 -0
- package/dist/helpers/validation.js +91 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/utils.d.ts +321 -0
- package/dist/utils.js +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# create-svelte
|
|
2
|
+
|
|
3
|
+
Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
|
4
|
+
|
|
5
|
+
Read more about creating a library [in the docs](https://svelte.dev/docs/kit/packaging).
|
|
6
|
+
|
|
7
|
+
## Creating a project
|
|
8
|
+
|
|
9
|
+
If you're seeing this, you've probably already done this step. Congrats!
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# create a new project in the current directory
|
|
13
|
+
npx sv create
|
|
14
|
+
|
|
15
|
+
# create a new project in my-app
|
|
16
|
+
npx sv create my-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Developing
|
|
20
|
+
|
|
21
|
+
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run dev
|
|
25
|
+
|
|
26
|
+
# or start the server and open the app in a new browser tab
|
|
27
|
+
npm run dev -- --open
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
|
|
31
|
+
|
|
32
|
+
## Building
|
|
33
|
+
|
|
34
|
+
To build your library:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm run package
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
To create a production version of your showcase app:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm run build
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can preview the production build with `npm run preview`.
|
|
47
|
+
|
|
48
|
+
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
|
49
|
+
|
|
50
|
+
## Publishing
|
|
51
|
+
|
|
52
|
+
Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
|
|
53
|
+
|
|
54
|
+
To publish your library to [npm](https://www.npmjs.com):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm publish
|
|
58
|
+
```
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { i18n } from 'i18next'
|
|
3
|
+
|
|
4
|
+
import { getContext } from 'svelte'
|
|
5
|
+
import Select from '@isoftdata/svelte-select'
|
|
6
|
+
import Table from '@isoftdata/svelte-table'
|
|
7
|
+
import Button from '@isoftdata/svelte-button'
|
|
8
|
+
import Modal from '@isoftdata/svelte-modal'
|
|
9
|
+
import type {
|
|
10
|
+
EbayCategory,
|
|
11
|
+
EbayCategoryMap,
|
|
12
|
+
ExtendedEbayCategoryMap,
|
|
13
|
+
InventoryType,
|
|
14
|
+
SelectedEbayCategoryMapRow,
|
|
15
|
+
} from './utils.js'
|
|
16
|
+
import klona from 'klona'
|
|
17
|
+
|
|
18
|
+
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
19
|
+
|
|
20
|
+
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
21
|
+
|
|
22
|
+
// Just ebay category map table columns
|
|
23
|
+
interface Props {
|
|
24
|
+
// Props
|
|
25
|
+
ebayCategoryList: EbayCategory[] // ebay categories for mapping
|
|
26
|
+
ebayCategoryMapList: ExtendedEbayCategoryMap[] // ebay category mappings for itrack categories
|
|
27
|
+
inventoryTypeList?: InventoryType[] // inventory types for mapping
|
|
28
|
+
selectedPartType?: number | null
|
|
29
|
+
categoryMapChanged: (data: EbayCategoryMap) => Promise<void>
|
|
30
|
+
selectedEcommerceCategoryMappingRow?: ExtendedEbayCategoryMap | SelectedEbayCategoryMapRow | null
|
|
31
|
+
selectedEcommerceCategoryId?: number | null
|
|
32
|
+
selectedEbayCategoryType?: string | null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
ebayCategoryList = [],
|
|
37
|
+
ebayCategoryMapList = $bindable([]),
|
|
38
|
+
inventoryTypeList = [],
|
|
39
|
+
categoryMapChanged = async (_: EbayCategoryMap) => {},
|
|
40
|
+
}: Props = $props()
|
|
41
|
+
|
|
42
|
+
// Local state
|
|
43
|
+
let editItrackCategoryDisabled = $state(false) // for category mapping, if needed in futur
|
|
44
|
+
let editEcommerceCategoryDisabled = false
|
|
45
|
+
let isEditingCategoryMap = false
|
|
46
|
+
let show = $state(false)
|
|
47
|
+
let showAllOption = true
|
|
48
|
+
let selectedEbayCategoryType: string | null = $state(null)
|
|
49
|
+
let selectedEcommerceCategoryId: number | null = $state(null)
|
|
50
|
+
let selectedEcommerceCategoryMappingRow: ExtendedEbayCategoryMap | SelectedEbayCategoryMapRow | null = $state(null)
|
|
51
|
+
let selectedPartType: number | null = $state(null) // used in category map config component
|
|
52
|
+
|
|
53
|
+
// New empty items
|
|
54
|
+
let newCategoryMapping = {
|
|
55
|
+
ebayCategoryId: null,
|
|
56
|
+
ebayCategoryName: '',
|
|
57
|
+
inventoryTypeName: null,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// TODO: saved inventory type doesn't get removed from dropdown after upsert/save
|
|
61
|
+
async function confirm() {
|
|
62
|
+
if (!selectedEcommerceCategoryMappingRow) return
|
|
63
|
+
|
|
64
|
+
const mappingToSave = convertCategoryToSavableFormat(selectedEcommerceCategoryMappingRow)
|
|
65
|
+
await categoryMapChanged(mappingToSave)
|
|
66
|
+
close()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function close() {
|
|
70
|
+
selectedEbayCategoryType = null
|
|
71
|
+
selectedEcommerceCategoryId = null
|
|
72
|
+
selectedEcommerceCategoryMappingRow = null
|
|
73
|
+
selectedPartType = null
|
|
74
|
+
show = false
|
|
75
|
+
}
|
|
76
|
+
function convertCategoryToSavableFormat(row: EbayCategoryMap | SelectedEbayCategoryMapRow): EbayCategoryMap {
|
|
77
|
+
const mapping = {
|
|
78
|
+
ebayCategoryId: selectedEcommerceCategoryId || row.ebayCategoryId,
|
|
79
|
+
vehicleType: 'Car', // Set a default so I stop getting TS warnings
|
|
80
|
+
typeNum: selectedPartType || row.typeNum,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const matchingEbayCategoryName = ebayCategoryList.find(row => row.ebayCategoryId === mapping.ebayCategoryId)?.name
|
|
84
|
+
if (matchingEbayCategoryName) {
|
|
85
|
+
if (matchingEbayCategoryName.includes('Car')) {
|
|
86
|
+
mapping.vehicleType = 'Car'
|
|
87
|
+
} else if (matchingEbayCategoryName.includes('HeavyTruck')) {
|
|
88
|
+
mapping.vehicleType = 'HeavyTruck'
|
|
89
|
+
} else if (matchingEbayCategoryName.includes('MotorCycle')) {
|
|
90
|
+
mapping.vehicleType = 'MotorCycle'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return mapping
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Called on add/edit button click
|
|
98
|
+
function editCategoryMapRow(row?: any) {
|
|
99
|
+
// Set selected row
|
|
100
|
+
selectedEcommerceCategoryMappingRow = klona(row || newCategoryMapping)
|
|
101
|
+
|
|
102
|
+
// Update the selected values based on the row being edited
|
|
103
|
+
if (row) {
|
|
104
|
+
// Set the selectedItrackPartType to match the row's value
|
|
105
|
+
selectedPartType = row.typeNum || ''
|
|
106
|
+
selectedEcommerceCategoryId = row.ebayCategoryid
|
|
107
|
+
// When editing an existing condition, you might want to disable editing the condition
|
|
108
|
+
editItrackCategoryDisabled = true
|
|
109
|
+
} else {
|
|
110
|
+
// For new mappings, reset the selected values
|
|
111
|
+
selectedPartType = null
|
|
112
|
+
selectedEcommerceCategoryId = null
|
|
113
|
+
editItrackCategoryDisabled = false
|
|
114
|
+
}
|
|
115
|
+
show = true // Show the category mapping edit form
|
|
116
|
+
}
|
|
117
|
+
// Function to extract unique middle segments from eBay category names
|
|
118
|
+
function extractUniqueCategoryTypes(categories: Array<EbayCategory>): Array<string> {
|
|
119
|
+
// Set to store unique segments
|
|
120
|
+
const uniqueSegments = new Set<string>()
|
|
121
|
+
|
|
122
|
+
// Process each category
|
|
123
|
+
categories.forEach(category => {
|
|
124
|
+
if (!category.name) return
|
|
125
|
+
const parts = category.name.split('>')
|
|
126
|
+
// Check if there are at least 3 parts (to have a middle segment)
|
|
127
|
+
if (parts.length >= 3) {
|
|
128
|
+
// Extract the middle segment (index 1) and trim whitespace
|
|
129
|
+
const middleSegment = parts[1].trim()
|
|
130
|
+
uniqueSegments.add(middleSegment)
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// Convert Set to Array and sort alphabetically
|
|
135
|
+
return Array.from(uniqueSegments).sort()
|
|
136
|
+
}
|
|
137
|
+
// Inputs
|
|
138
|
+
|
|
139
|
+
let filteredEbayCategoriesByType = $derived(
|
|
140
|
+
ebayCategoryList.filter(
|
|
141
|
+
category => category.name && (selectedEbayCategoryType ? category.name.includes(selectedEbayCategoryType) : true),
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
let uniqueCategoryTypes = $derived(extractUniqueCategoryTypes(ebayCategoryList))
|
|
145
|
+
let unmappedPartTypes = $derived(
|
|
146
|
+
inventoryTypeList.filter(
|
|
147
|
+
partType =>
|
|
148
|
+
// Include the part type if it's the one being edited or if it's not already mapped
|
|
149
|
+
selectedEcommerceCategoryMappingRow?.inventoryTypeName === partType.name ||
|
|
150
|
+
!ebayCategoryMapList.some(mapping => mapping.inventoryTypeName === partType.name),
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
</script>
|
|
154
|
+
|
|
155
|
+
<div class="card-header">
|
|
156
|
+
<h4 class="mb-0">{translate('configuration.ecommerce.categoryMappings', 'Category Mappings')}</h4>
|
|
157
|
+
<p class="text-muted mb-0">
|
|
158
|
+
{translate('configuration.ecommerce.categoryMappingsHint', 'Map part types to eBay Categories')}
|
|
159
|
+
</p>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="card-body">
|
|
162
|
+
<div class="mb-3">
|
|
163
|
+
<Button
|
|
164
|
+
outline
|
|
165
|
+
color="success"
|
|
166
|
+
size="sm"
|
|
167
|
+
iconClass="plus"
|
|
168
|
+
onclick={() => editCategoryMapRow()}
|
|
169
|
+
disabled={isEditingCategoryMap}
|
|
170
|
+
>
|
|
171
|
+
{translate('configuration.ecommerce.add', 'Add')}
|
|
172
|
+
</Button>
|
|
173
|
+
</div>
|
|
174
|
+
<Table
|
|
175
|
+
responsive
|
|
176
|
+
stickyHeader
|
|
177
|
+
rows={ebayCategoryMapList}
|
|
178
|
+
parentClass="overflow-y-auto mh-500"
|
|
179
|
+
columns={[
|
|
180
|
+
{
|
|
181
|
+
property: 'inventoryTypeName',
|
|
182
|
+
name: translate('configuration.ecommerce.itrackInventoryType', 'Itrack InventoryType'),
|
|
183
|
+
defaultSortColumn: true,
|
|
184
|
+
},
|
|
185
|
+
{ property: 'ebayCategoryName', name: translate('configuration.ecommerce.ebayCategory', 'Ebay Category') },
|
|
186
|
+
]}
|
|
187
|
+
>
|
|
188
|
+
{#snippet children({ row })}
|
|
189
|
+
<tr
|
|
190
|
+
onclick={() => editCategoryMapRow(row)}
|
|
191
|
+
class="cursor-pointer"
|
|
192
|
+
>
|
|
193
|
+
<td>{row.inventoryTypeName}</td>
|
|
194
|
+
<td>{row.ebayCategoryName}</td>
|
|
195
|
+
</tr>
|
|
196
|
+
{/snippet}
|
|
197
|
+
</Table>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<Modal
|
|
201
|
+
bind:show
|
|
202
|
+
title={translate('configuration.ecommerce.addEditCategoryMapping', 'Add/Edit New Category Mapping')}
|
|
203
|
+
modalSize="lg"
|
|
204
|
+
confirmButtonText={translate('configuration.ecommerce.save', 'save')}
|
|
205
|
+
cancelShown={true}
|
|
206
|
+
{confirm}
|
|
207
|
+
{close}
|
|
208
|
+
>
|
|
209
|
+
<div class="card-header">
|
|
210
|
+
<h4 class="mb-0">{translate('configuration.ecommerce.categoryMapping', 'Category Mapping')}</h4>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="card-body">
|
|
213
|
+
<Select
|
|
214
|
+
label={translate('configuration.ecommerce.partType', 'Part Type')}
|
|
215
|
+
showEmptyOption={showAllOption}
|
|
216
|
+
emptyValue={null}
|
|
217
|
+
emptyText={translate('configuration.ecommerce.selectType', 'Select Type')}
|
|
218
|
+
disabled={editItrackCategoryDisabled}
|
|
219
|
+
bind:value={selectedPartType}
|
|
220
|
+
>
|
|
221
|
+
{#each unmappedPartTypes as type}
|
|
222
|
+
<option value={type.inventoryTypeId}>{type.inventoryTypeId} - {type.name}</option>
|
|
223
|
+
{/each}
|
|
224
|
+
{#if selectedEcommerceCategoryMappingRow && selectedEcommerceCategoryMappingRow.typeNum && !unmappedPartTypes.find(t => t.inventoryTypeId === selectedEcommerceCategoryMappingRow?.typeNum)}
|
|
225
|
+
<option
|
|
226
|
+
value={selectedEcommerceCategoryMappingRow.typeNum}
|
|
227
|
+
selected
|
|
228
|
+
>
|
|
229
|
+
{selectedEcommerceCategoryMappingRow.typeNum} - {selectedEcommerceCategoryMappingRow.inventoryTypeName}
|
|
230
|
+
</option>
|
|
231
|
+
{/if}
|
|
232
|
+
</Select>
|
|
233
|
+
<!-- Dropdown for unique category segments -->
|
|
234
|
+
<Select
|
|
235
|
+
label={translate('ecommerce.configuration.categoryTypeFilter', 'Category Type Filter')}
|
|
236
|
+
showEmptyOption={showAllOption}
|
|
237
|
+
emptyValue={null}
|
|
238
|
+
emptyText={translate('configuration.ecommerce.selectType', 'Select Type')}
|
|
239
|
+
bind:value={selectedEbayCategoryType}
|
|
240
|
+
>
|
|
241
|
+
{#each uniqueCategoryTypes as type}
|
|
242
|
+
<option value={type}>{type}</option>
|
|
243
|
+
{/each}
|
|
244
|
+
</Select>
|
|
245
|
+
<Select
|
|
246
|
+
label={translate('ecommerce.configuration.ebayCategory', 'Ebay Category')}
|
|
247
|
+
showEmptyOption={showAllOption}
|
|
248
|
+
emptyValue={null}
|
|
249
|
+
emptyText={translate('configuration.ecommerce.selectCategory', 'Select Category')}
|
|
250
|
+
disabled={editEcommerceCategoryDisabled}
|
|
251
|
+
bind:value={selectedEcommerceCategoryId}
|
|
252
|
+
>
|
|
253
|
+
{#each filteredEbayCategoriesByType as category}
|
|
254
|
+
<option value={category.ebayCategoryId}>{category.name}</option>
|
|
255
|
+
{/each}
|
|
256
|
+
{#if selectedEcommerceCategoryMappingRow && selectedEcommerceCategoryMappingRow.ebayCategoryId && !ebayCategoryList.find(t => t.ebayCategoryId === selectedEcommerceCategoryMappingRow?.ebayCategoryId)}
|
|
257
|
+
<option
|
|
258
|
+
value={selectedEcommerceCategoryMappingRow.ebayCategoryId}
|
|
259
|
+
selected
|
|
260
|
+
>
|
|
261
|
+
{selectedEcommerceCategoryMappingRow.ebayCategoryName}
|
|
262
|
+
</option>
|
|
263
|
+
{/if}
|
|
264
|
+
</Select>
|
|
265
|
+
</div>
|
|
266
|
+
</Modal>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EbayCategory, EbayCategoryMap, ExtendedEbayCategoryMap, InventoryType, SelectedEbayCategoryMapRow } from './utils.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
ebayCategoryList: EbayCategory[];
|
|
4
|
+
ebayCategoryMapList: ExtendedEbayCategoryMap[];
|
|
5
|
+
inventoryTypeList?: InventoryType[];
|
|
6
|
+
selectedPartType?: number | null;
|
|
7
|
+
categoryMapChanged: (data: EbayCategoryMap) => Promise<void>;
|
|
8
|
+
selectedEcommerceCategoryMappingRow?: ExtendedEbayCategoryMap | SelectedEbayCategoryMapRow | null;
|
|
9
|
+
selectedEcommerceCategoryId?: number | null;
|
|
10
|
+
selectedEbayCategoryType?: string | null;
|
|
11
|
+
}
|
|
12
|
+
declare const EcommerceCategoryMapConfiguration: import("svelte").Component<Props, {}, "ebayCategoryMapList">;
|
|
13
|
+
type EcommerceCategoryMapConfiguration = ReturnType<typeof EcommerceCategoryMapConfiguration>;
|
|
14
|
+
export default EcommerceCategoryMapConfiguration;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { i18n } from 'i18next'
|
|
3
|
+
import { getContext } from 'svelte'
|
|
4
|
+
|
|
5
|
+
import Table from '@isoftdata/svelte-table'
|
|
6
|
+
import Button from '@isoftdata/svelte-button'
|
|
7
|
+
import Input from '@isoftdata/svelte-input'
|
|
8
|
+
import Select from '@isoftdata/svelte-select'
|
|
9
|
+
import Modal from '@isoftdata/svelte-modal'
|
|
10
|
+
import klona from 'klona'
|
|
11
|
+
import type {
|
|
12
|
+
EcommerceCondition,
|
|
13
|
+
EcommerceConditionMap,
|
|
14
|
+
ExtendedEcommerceConditionMap,
|
|
15
|
+
NewEcommerceConditionMap,
|
|
16
|
+
NewConditionMappingState,
|
|
17
|
+
} from './utils.js'
|
|
18
|
+
|
|
19
|
+
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
20
|
+
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
21
|
+
|
|
22
|
+
interface SelectedEcommerceConditionMapRow extends EcommerceConditionMap {
|
|
23
|
+
originalIndex: number
|
|
24
|
+
uuid: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Add index signature to make it compatible with Table component
|
|
28
|
+
interface TableRow extends ExtendedEcommerceConditionMap {
|
|
29
|
+
[key: string]: any
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface Props {
|
|
33
|
+
ecommerceConditionMappingList: ExtendedEcommerceConditionMap[] // mapping between itrack and ebay conditions
|
|
34
|
+
ecommerceConditionList: EcommerceCondition[]
|
|
35
|
+
inventoryConditionList: string[] // unique conditions from inventory table
|
|
36
|
+
conditionMapChanged: (data: EcommerceConditionMap) => Promise<void>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let {
|
|
40
|
+
ecommerceConditionMappingList = $bindable([]),
|
|
41
|
+
ecommerceConditionList = [],
|
|
42
|
+
inventoryConditionList = [],
|
|
43
|
+
conditionMapChanged = async (_: EcommerceConditionMap) => {},
|
|
44
|
+
}: Props = $props()
|
|
45
|
+
|
|
46
|
+
// New empty items
|
|
47
|
+
let newConditionMapping: NewConditionMappingState = Object.freeze({
|
|
48
|
+
itrackCondition: null,
|
|
49
|
+
ecommerceConditionId: null,
|
|
50
|
+
description: null,
|
|
51
|
+
})
|
|
52
|
+
// Local state
|
|
53
|
+
let selectedEcommerceConditionMappingRow: SelectedEcommerceConditionMapRow | NewConditionMappingState =
|
|
54
|
+
$state(newConditionMapping)
|
|
55
|
+
|
|
56
|
+
let editEcommerceConditionDisabled = $state(false)
|
|
57
|
+
let editItrackConditionDisabled = $state(false)
|
|
58
|
+
let isEditingConditionMap = $state(false)
|
|
59
|
+
let showAllOption = $state(true)
|
|
60
|
+
let show = $state(false)
|
|
61
|
+
|
|
62
|
+
let unmappedConditions = $derived(
|
|
63
|
+
inventoryConditionList.filter(
|
|
64
|
+
condition =>
|
|
65
|
+
selectedEcommerceConditionMappingRow?.itrackCondition === condition ||
|
|
66
|
+
!ecommerceConditionMappingList.some(mapping => mapping.itrackCondition === condition),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
function editConditionMapRow(row?: ExtendedEcommerceConditionMap) {
|
|
71
|
+
// Set selected row
|
|
72
|
+
selectedEcommerceConditionMappingRow = klona(row || newConditionMapping)
|
|
73
|
+
|
|
74
|
+
show = true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Add function to convert condtion row to savable format
|
|
78
|
+
function convertConditionToSavableFormat(
|
|
79
|
+
row: SelectedEcommerceConditionMapRow | NewConditionMappingState,
|
|
80
|
+
): EcommerceConditionMap {
|
|
81
|
+
// Handle the case where we have a NewConditionMappingState with null values
|
|
82
|
+
if ('ecommerceConditionMapId' in row && row.ecommerceConditionMapId !== undefined) {
|
|
83
|
+
// This is an existing record (EcommerceConditionMap or SelectedEcommerceConditionMapRow)
|
|
84
|
+
return {
|
|
85
|
+
ecommerceConditionMapId: row.ecommerceConditionMapId,
|
|
86
|
+
ecommercePartnerId: row.ecommercePartnerId!,
|
|
87
|
+
itrackCondition: row.itrackCondition!,
|
|
88
|
+
ecommerceConditionId: row.ecommerceConditionId!,
|
|
89
|
+
description: row.description || row.itrackCondition!,
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
// This is a new record - we need to create it without the ID
|
|
93
|
+
// The API will assign the ID when creating
|
|
94
|
+
// TODO: is there a way to avoid 'any' here?
|
|
95
|
+
const newMapping: any = {
|
|
96
|
+
ecommercePartnerId: row.ecommercePartnerId || 0, // Default value, should be set by parent
|
|
97
|
+
itrackCondition: row.itrackCondition!,
|
|
98
|
+
ecommerceConditionId: row.ecommerceConditionId!,
|
|
99
|
+
description: row.description || row.itrackCondition!,
|
|
100
|
+
}
|
|
101
|
+
return newMapping as EcommerceConditionMap
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function confirm() {
|
|
106
|
+
if (!selectedEcommerceConditionMappingRow) return
|
|
107
|
+
|
|
108
|
+
const mappingToSave = convertConditionToSavableFormat(selectedEcommerceConditionMappingRow)
|
|
109
|
+
|
|
110
|
+
await conditionMapChanged(mappingToSave)
|
|
111
|
+
close()
|
|
112
|
+
}
|
|
113
|
+
function close() {
|
|
114
|
+
// Reset related data and flags
|
|
115
|
+
selectedEcommerceConditionMappingRow = newConditionMapping
|
|
116
|
+
show = false
|
|
117
|
+
}
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<div class="card-header">
|
|
121
|
+
<h4 class="mb-0">{translate('ecommerce.configuration.conditionMappings', 'Condition Mappings')}</h4>
|
|
122
|
+
<p class="text-muted mb-0">
|
|
123
|
+
{translate('ecommerce.configuration.mapConditionValues', 'Map condition values to eBay condition values')}
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="card-body">
|
|
127
|
+
<div class="mb-3">
|
|
128
|
+
<Button
|
|
129
|
+
outline
|
|
130
|
+
color="success"
|
|
131
|
+
size="sm"
|
|
132
|
+
iconClass="plus"
|
|
133
|
+
onclick={() => editConditionMapRow()}
|
|
134
|
+
disabled={isEditingConditionMap}
|
|
135
|
+
>
|
|
136
|
+
{translate('ecommerce.configuration.add', 'Add')}
|
|
137
|
+
</Button>
|
|
138
|
+
</div>
|
|
139
|
+
<Table
|
|
140
|
+
parentClass="overflow-y-auto mh-500"
|
|
141
|
+
rows={ecommerceConditionMappingList as TableRow[]}
|
|
142
|
+
columns={[
|
|
143
|
+
{
|
|
144
|
+
property: 'itrackCondition',
|
|
145
|
+
name: translate('ecommerce.configuration.itrackCondition', 'Itrack Condition'),
|
|
146
|
+
defaultSortColumn: true,
|
|
147
|
+
},
|
|
148
|
+
{ property: 'name', name: translate('ecommerce.configuration.ebayCondition', 'Ebay Condition') },
|
|
149
|
+
{
|
|
150
|
+
property: 'description',
|
|
151
|
+
name: translate('ecommerce.configuration.conditionDescription', 'Condition Description'),
|
|
152
|
+
},
|
|
153
|
+
]}
|
|
154
|
+
stickyHeader
|
|
155
|
+
responsive
|
|
156
|
+
>
|
|
157
|
+
{#snippet children({ row })}
|
|
158
|
+
<tr
|
|
159
|
+
onclick={() => editConditionMapRow(row as ExtendedEcommerceConditionMap)}
|
|
160
|
+
class="cursor-pointer"
|
|
161
|
+
>
|
|
162
|
+
<td>{row.itrackCondition}</td>
|
|
163
|
+
<td>{row.name}</td>
|
|
164
|
+
<td>{row.description}</td>
|
|
165
|
+
</tr>
|
|
166
|
+
{/snippet}
|
|
167
|
+
</Table>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<Modal
|
|
171
|
+
bind:show
|
|
172
|
+
title={translate('ecommerce.configuration.addEditConditionMapping', 'Add/Edit New Condition Mapping')}
|
|
173
|
+
modalSize="lg"
|
|
174
|
+
confirmButtonText={translate('ecommerce.configuration.save', 'Save')}
|
|
175
|
+
cancelShown={true}
|
|
176
|
+
{confirm}
|
|
177
|
+
{close}
|
|
178
|
+
>
|
|
179
|
+
<div class="card-header">
|
|
180
|
+
<h4 class="mb-0">{translate('ecommerce.configuration.conditionMapping', 'Condition Mapping')}</h4>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="card-body">
|
|
183
|
+
<Select
|
|
184
|
+
label={translate('ecommerce.configuration.itrackCondition', 'Itrack Condition')}
|
|
185
|
+
showEmptyOption={showAllOption}
|
|
186
|
+
emptyValue={null}
|
|
187
|
+
emptyText={translate('ecommerce.configuration.selectCondition', 'Select Condition')}
|
|
188
|
+
disabled={editItrackConditionDisabled}
|
|
189
|
+
bind:value={selectedEcommerceConditionMappingRow.itrackCondition}
|
|
190
|
+
>
|
|
191
|
+
{#each unmappedConditions as itrackCondition}
|
|
192
|
+
<option value={itrackCondition}>{itrackCondition}</option>
|
|
193
|
+
{/each}
|
|
194
|
+
</Select>
|
|
195
|
+
<Select
|
|
196
|
+
label={translate('ecommerce.configuration.ecommerceCondition', 'Ecommerce Condition')}
|
|
197
|
+
showEmptyOption={showAllOption}
|
|
198
|
+
emptyValue={null}
|
|
199
|
+
emptyText={translate('ecommerce.configuration.selectCondition', 'Select Condition')}
|
|
200
|
+
disabled={editEcommerceConditionDisabled}
|
|
201
|
+
bind:value={selectedEcommerceConditionMappingRow.ecommerceConditionId}
|
|
202
|
+
>
|
|
203
|
+
{#each ecommerceConditionList as ecommerceCondition}
|
|
204
|
+
<option value={ecommerceCondition.ecommerceConditionId ?? null}>{ecommerceCondition.name}</option>
|
|
205
|
+
{/each}
|
|
206
|
+
</Select>
|
|
207
|
+
<Input
|
|
208
|
+
label={translate('ecommerce.configuration.conditionDescription', 'Condition Description')}
|
|
209
|
+
maxlength={1000}
|
|
210
|
+
bind:value={selectedEcommerceConditionMappingRow.description}
|
|
211
|
+
placeholder=""
|
|
212
|
+
/>
|
|
213
|
+
</div>
|
|
214
|
+
</Modal>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EcommerceCondition, EcommerceConditionMap, ExtendedEcommerceConditionMap } from './utils.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
ecommerceConditionMappingList: ExtendedEcommerceConditionMap[];
|
|
4
|
+
ecommerceConditionList: EcommerceCondition[];
|
|
5
|
+
inventoryConditionList: string[];
|
|
6
|
+
conditionMapChanged: (data: EcommerceConditionMap) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
declare const EcommerceConditionMapConfiguration: import("svelte").Component<Props, {}, "ecommerceConditionMappingList">;
|
|
9
|
+
type EcommerceConditionMapConfiguration = ReturnType<typeof EcommerceConditionMapConfiguration>;
|
|
10
|
+
export default EcommerceConditionMapConfiguration;
|