@streamoid/catalogix-chat 0.2.20 → 0.2.21

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/dist/index.d.ts CHANGED
@@ -186,11 +186,12 @@ interface EditFeedProps {
186
186
  sourceMp: string;
187
187
  marketplaceOv: number | string;
188
188
  transformedUrl: string;
189
+ mappingKey: string;
189
190
  submitted?: boolean;
190
191
  submittedValues?: Record<string, unknown>;
191
192
  onSubmit: (values: Record<string, unknown>, message?: string) => void;
192
193
  }
193
- declare function EditFeed({ criticalIssues: initialCriticalIssues, rawErrorData: initialRawErrorData, dataIssuesRaw: initialDataIssuesRaw, columns: initialColumns, skuField, storeId, feedFileType, downloadUrl, userId, mappingObj, sourceMp, marketplaceOv, transformedUrl: initialTransformedUrl, submitted, submittedValues, onSubmit, }: EditFeedProps): react_jsx_runtime.JSX.Element;
194
+ declare function EditFeed({ criticalIssues: initialCriticalIssues, rawErrorData: initialRawErrorData, dataIssuesRaw: initialDataIssuesRaw, columns: initialColumns, skuField, storeId, feedFileType, downloadUrl, userId, mappingObj, sourceMp, marketplaceOv, transformedUrl: initialTransformedUrl, mappingKey, submitted, submittedValues, onSubmit, }: EditFeedProps): react_jsx_runtime.JSX.Element;
194
195
 
195
196
  interface ProductAutomationProps {
196
197
  storeId: string;
package/dist/index.js CHANGED
@@ -3125,66 +3125,33 @@ function buildDataIssueMap(issues) {
3125
3125
  }
3126
3126
  return map;
3127
3127
  }
3128
- function rowsToCsvBlob(rows, columns) {
3129
- const escape = (v) => {
3130
- if (v.includes(",") || v.includes('"') || v.includes("\n")) {
3131
- return `"${v.replace(/"/g, '""')}"`;
3132
- }
3133
- return v;
3134
- };
3135
- const lines = [columns.map(escape).join(",")];
3136
- for (const row of rows) {
3137
- lines.push(columns.map((c) => escape(row[c] ?? "")).join(","));
3138
- }
3139
- return new Blob([lines.join("\n")], { type: "text/csv" });
3140
- }
3141
- async function uploadCorrectedCsv(storeId, csvBlob, fileName) {
3128
+ async function validateRow(storeId, mappingKey, rowData) {
3142
3129
  const { catalogixBaseUrl } = getApiConfig();
3143
- const form = new FormData();
3144
- form.append("file_type", "csv");
3145
- form.append("file_data", csvBlob, fileName);
3146
- form.append("data", JSON.stringify({ fileName, size: csvBlob.size / 1024 }));
3147
- const resp = await fetch(
3148
- `${catalogixBaseUrl}/api/v1/store/${storeId}/feed/onboard`,
3149
- { method: "POST", credentials: "include", body: form }
3130
+ const params = new URLSearchParams({ mapping_key: mappingKey });
3131
+ return fetchJson(
3132
+ `${catalogixBaseUrl}/api/v1/feed/${storeId}/validate/row?${params}`,
3133
+ {
3134
+ method: "POST",
3135
+ headers: { "Content-Type": "application/json" },
3136
+ body: JSON.stringify([rowData])
3137
+ }
3150
3138
  );
3151
- if (!resp.ok) throw new Error(`Upload failed: ${resp.status}`);
3152
- const json = await resp.json();
3153
- return json.data.download_url;
3154
3139
  }
3155
- async function validateFeed(storeId, fileUrl, feedFileType, clientFeedUrl, userId, mappingObj, sourceMp, marketplaceOv, reValidate) {
3140
+ async function mergeFeed(fileUrl, feedFormat, changes) {
3156
3141
  const { catalogixBaseUrl } = getApiConfig();
3157
3142
  const params = new URLSearchParams({
3158
3143
  file_url: fileUrl,
3159
- feed_format: feedFileType,
3160
- client_feed_url: clientFeedUrl,
3161
- catalogix_user_id: userId,
3162
- re_validate: String(reValidate)
3144
+ feed_format: feedFormat
3163
3145
  });
3164
3146
  return fetchJson(
3165
- `${catalogixBaseUrl}/api/v1/feed/${storeId}/validate/v2?${params}`,
3147
+ `${catalogixBaseUrl}/api/v1/feed/merge?${params}`,
3166
3148
  {
3167
3149
  method: "POST",
3168
3150
  headers: { "Content-Type": "application/json" },
3169
- body: JSON.stringify({
3170
- mapping: {
3171
- ...mappingObj,
3172
- catalogix_user_id: userId,
3173
- mp: sourceMp,
3174
- template: reValidate ? null : "",
3175
- source_ov: reValidate ? marketplaceOv : String(marketplaceOv)
3176
- }
3177
- })
3151
+ body: JSON.stringify(changes)
3178
3152
  }
3179
3153
  );
3180
3154
  }
3181
- async function fetchValidationErrors(issueFilesUrl) {
3182
- const { catalogixBaseUrl } = getApiConfig();
3183
- const params = new URLSearchParams({ excelUrl: issueFilesUrl });
3184
- return fetchJson(
3185
- `${catalogixBaseUrl}/api/v1/format-sheet-data-for-mapping?${params}`
3186
- );
3187
- }
3188
3155
  function EditableCell2({
3189
3156
  value,
3190
3157
  hasError,
@@ -3310,6 +3277,7 @@ function EditFeed({
3310
3277
  sourceMp,
3311
3278
  marketplaceOv,
3312
3279
  transformedUrl: initialTransformedUrl,
3280
+ mappingKey,
3313
3281
  submitted,
3314
3282
  submittedValues,
3315
3283
  onSubmit
@@ -3326,6 +3294,9 @@ function EditFeed({
3326
3294
  return out;
3327
3295
  })
3328
3296
  );
3297
+ const [rowNumbers, setRowNumbers] = useState8(
3298
+ () => initialRawErrorData.map((r) => Number(r.row_number ?? 0))
3299
+ );
3329
3300
  const [criticalIssues, setCriticalIssues] = useState8(initialCriticalIssues);
3330
3301
  const [dataIssuesRaw, setDataIssuesRaw] = useState8(initialDataIssuesRaw);
3331
3302
  const [columns] = useState8(
@@ -3367,77 +3338,64 @@ function EditFeed({
3367
3338
  setIsLoading(true);
3368
3339
  setErrorMsg("");
3369
3340
  try {
3370
- setStatusMsg("Building corrected CSV...");
3371
- const csvBlob = rowsToCsvBlob(rows, columns);
3372
- const fileName = `corrected_${Date.now()}.csv`;
3373
- setStatusMsg("Uploading corrected feed...");
3374
- const newFileUrl = await uploadCorrectedCsv(storeId, csvBlob, fileName);
3375
- setStatusMsg("Re-validating feed...");
3376
- const result = await validateFeed(
3377
- storeId,
3378
- newFileUrl,
3379
- feedFileType,
3380
- downloadUrl,
3381
- userId,
3382
- mappingObj,
3383
- sourceMp,
3384
- marketplaceOv,
3385
- true
3386
- );
3387
- const data = result.data;
3388
- if (data.validation) {
3389
- setStatusMsg("Validation passed!");
3390
- onSubmit(
3391
- { transformedUrl: data.transformed_url },
3392
- "Feed corrections validated successfully."
3393
- );
3341
+ const editedRowIndices = /* @__PURE__ */ new Set();
3342
+ for (const key of editedCells) {
3343
+ const idx = parseInt(key.split(":")[0], 10);
3344
+ editedRowIndices.add(idx);
3345
+ }
3346
+ if (editedRowIndices.size === 0) {
3347
+ setErrorMsg("No cells have been edited. Please fix the highlighted values first.");
3348
+ setIsLoading(false);
3394
3349
  return;
3395
3350
  }
3396
- setStatusMsg("Validation still failing \u2014 fetching new errors...");
3397
- const issueUrl = data.errors?.issue_files_url;
3398
- if (issueUrl) {
3399
- const errResp = await fetchValidationErrors(issueUrl);
3400
- const newRaw = errResp.data.raw_error_data ?? [];
3401
- const newRows = newRaw.map((r) => {
3402
- const out = {};
3403
- for (const [k, v] of Object.entries(r)) {
3404
- if (k !== "row_number") out[k] = String(v ?? "");
3351
+ const failedRows = [];
3352
+ for (const rowIdx of editedRowIndices) {
3353
+ const rowNum = rowNumbers[rowIdx];
3354
+ setStatusMsg(`Validating row ${rowIdx + 1} of ${rows.length}...`);
3355
+ const fullRowData = { ...rows[rowIdx], row_number: rowNum };
3356
+ const result = await validateRow(storeId, mappingKey, fullRowData);
3357
+ if (!result.data.validation) {
3358
+ failedRows.push({ rowIdx, errors: result.data.errors });
3359
+ }
3360
+ }
3361
+ if (failedRows.length > 0) {
3362
+ const newCritical = [];
3363
+ for (const { rowIdx, errors } of failedRows) {
3364
+ const sku = rows[rowIdx][skuField] ?? "";
3365
+ for (const err of errors) {
3366
+ if (err["Invalid Value"] || err["Invalid Attribute"]) {
3367
+ newCritical.push({
3368
+ rowNumber: rowNumbers[rowIdx],
3369
+ columnNumber: err["Column Number"] || void 0,
3370
+ skuCode: err["SKU Code"] || sku,
3371
+ errorMessage: [err["Invalid Attribute"], err["Invalid Value"]].filter(Boolean).join(": ")
3372
+ });
3373
+ }
3405
3374
  }
3406
- return out;
3407
- });
3408
- setRows(newRows);
3375
+ }
3376
+ if (newCritical.length > 0) setCriticalIssues(newCritical);
3409
3377
  setEditedCells(/* @__PURE__ */ new Set());
3410
- const newCritical = (errResp.data.critical_issues ?? []).map(
3411
- (ci) => {
3412
- let errMsgRaw = String(ci.error_message ?? "");
3413
- errMsgRaw = errMsgRaw.replace(/^[{' ]+|[}' ]+$/g, "");
3414
- return {
3415
- rowNumber: ci["Row Number"],
3416
- columnNumber: ci["Column Number"],
3417
- skuCode: String(ci["SKU Code"] ?? ""),
3418
- errorMessage: errMsgRaw
3419
- };
3420
- }
3421
- );
3422
- setCriticalIssues(newCritical);
3423
- const newDataIssues = (errResp.data.data_issues_raw ?? []).map(
3424
- (di) => ({
3425
- rowNumber: String(di["Row Number"] ?? ""),
3426
- skuCode: String(di["SKU Code"] ?? ""),
3427
- missingAttributes: String(
3428
- di["Attribute Required For Listing"] ?? ""
3429
- )
3430
- })
3431
- );
3432
- setDataIssuesRaw(newDataIssues);
3433
3378
  setErrorMsg(
3434
- "Validation still has errors. Please fix the remaining issues and try again."
3435
- );
3436
- } else {
3437
- setErrorMsg(
3438
- "Validation failed but no detailed error info was returned."
3379
+ `${failedRows.length} row(s) still have errors. Please fix the remaining issues and try again.`
3439
3380
  );
3381
+ return;
3440
3382
  }
3383
+ setStatusMsg("Merging corrections into feed...");
3384
+ const changes = {};
3385
+ for (const key of editedCells) {
3386
+ const [idxStr, col] = [key.split(":")[0], key.slice(key.indexOf(":") + 1)];
3387
+ const rowIdx = parseInt(idxStr, 10);
3388
+ const rowNum = String(rowNumbers[rowIdx]);
3389
+ if (!changes[rowNum]) changes[rowNum] = {};
3390
+ changes[rowNum][col] = rows[rowIdx][col] ?? "";
3391
+ }
3392
+ const mergeResult = await mergeFeed(transformedUrl, feedFileType, changes);
3393
+ const newFileUrl = mergeResult.data.new_file_url;
3394
+ setStatusMsg("Validation passed!");
3395
+ onSubmit(
3396
+ { transformedUrl: newFileUrl },
3397
+ "Feed corrections validated successfully."
3398
+ );
3441
3399
  } catch (err) {
3442
3400
  setErrorMsg(
3443
3401
  `Error: ${err instanceof Error ? err.message : String(err)}`
@@ -3448,14 +3406,14 @@ function EditFeed({
3448
3406
  }
3449
3407
  }, [
3450
3408
  rows,
3409
+ rowNumbers,
3451
3410
  columns,
3411
+ editedCells,
3452
3412
  storeId,
3453
3413
  feedFileType,
3454
- downloadUrl,
3455
- userId,
3456
- mappingObj,
3457
- sourceMp,
3458
- marketplaceOv,
3414
+ mappingKey,
3415
+ transformedUrl,
3416
+ skuField,
3459
3417
  onSubmit
3460
3418
  ]);
3461
3419
  return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3", children: [
@@ -4708,6 +4666,7 @@ function CatalogixChat(props) {
4708
4666
  sourceMp: uiProps.sourceMp ?? "SMP",
4709
4667
  marketplaceOv: uiProps.marketplaceOv ?? 34,
4710
4668
  transformedUrl: uiProps.transformedUrl ?? "",
4669
+ mappingKey: uiProps.mappingKey ?? "",
4711
4670
  submitted: props.submitted,
4712
4671
  submittedValues: props.submittedValues,
4713
4672
  onSubmit: (values, msg) => onSubmit(values, msg)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoid/catalogix-chat",
3
- "version": "0.2.20",
3
+ "version": "0.2.21",
4
4
  "description": "Catalogix chat components for the Streamoid chat host — store creation, product selection, automations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",