merchi_sdk_js 0.5.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "merchi_sdk_js",
3
- "version": "0.5.0",
3
+ "version": "0.5.3",
4
4
  "type": "module",
5
5
  "main": "src/merchi.js",
6
6
  "module": "src/merchi.js",
package/src/domain.js CHANGED
@@ -261,6 +261,187 @@ export function Domain() {
261
261
  return {payload: payload || {}, success: success, error: error};
262
262
  }
263
263
 
264
+ /**
265
+ * @typedef {Object} StorefrontChecksSummary
266
+ * @property {'passing'|'failing'|'pending'|'unknown'} [overall]
267
+ * @property {string} [statusState]
268
+ * @property {{total?: number, passed?: number, failed?: number, pending?: number, neutral?: number}} [counts]
269
+ * @property {string} [updatedAt]
270
+ */
271
+
272
+ /**
273
+ * @typedef {Object} StorefrontV2Config
274
+ * @property {number} [id]
275
+ * @property {number} [domainId]
276
+ * @property {string} [status]
277
+ * @property {string|null} [starterTemplate]
278
+ * @property {string|null} [urlStructure]
279
+ * @property {string|null} [defaultBranch]
280
+ * @property {string|null} [activePreviewBranchName]
281
+ * @property {string|null} [activePreviewStartedAt]
282
+ * @property {number|null} [activePreviewLastRequestId]
283
+ * @property {string|null} [repoProvider]
284
+ * @property {string|null} [repoOwner]
285
+ * @property {string|null} [repoName]
286
+ * @property {string|null} [vercelProjectId]
287
+ * @property {string|null} [lastSuccessfulCommitSha]
288
+ * @property {Array<string>} [approvedStarterTemplates]
289
+ * @property {string} [providerMode]
290
+ */
291
+
292
+ /**
293
+ * @typedef {Object} StorefrontV2ChangeRequest
294
+ * @property {number} id
295
+ * @property {number} domainId
296
+ * @property {number} storefrontV2Id
297
+ * @property {string} status
298
+ * @property {string} prompt
299
+ * @property {string|null} [branchName]
300
+ * @property {string|null} [commitSha]
301
+ * @property {number|null} [pullRequestNumber]
302
+ * @property {string|null} [previewUrl]
303
+ * @property {string|null} [summary]
304
+ * @property {StorefrontChecksSummary|null} [checksSummary]
305
+ * @property {string|null} [checksUpdatedAt]
306
+ * @property {string|null} [errorDetails]
307
+ * @property {Array<StorefrontExecutionEvent>|null} [executionEvents]
308
+ */
309
+
310
+ /**
311
+ * @typedef {Object} StorefrontRequestContextImage
312
+ * @property {string} name
313
+ * @property {string|null} [mimeType]
314
+ * @property {string} dataUrl
315
+ */
316
+
317
+ /**
318
+ * @typedef {Object} StorefrontV2ChangeRequestPayload
319
+ * @property {string} prompt
320
+ * @property {Array<string>} [contextFilePaths]
321
+ * @property {Array<StorefrontRequestContextImage>} [contextImages]
322
+ * @property {string} [branchName]
323
+ * @property {boolean} [startNewBranch]
324
+ * @property {Object<string, string|Array<string>>} [clarificationAnswers]
325
+ * @property {string} [generationBriefSummary]
326
+ * @property {string} [generationBoilerplateFit]
327
+ * @property {boolean} [clarificationSkipped]
328
+ */
329
+
330
+ /**
331
+ * @typedef {Object} StorefrontV2GenerationBrief
332
+ * @property {string} planSummary
333
+ * @property {string} boilerplateFit
334
+ * @property {Array<Object>} gapTopics
335
+ * @property {Array<Object>} questions
336
+ * @property {number} questionCount
337
+ */
338
+
339
+ /**
340
+ * @typedef {Object} StorefrontV2GenerationBriefPayload
341
+ * @property {StorefrontV2SiteContext} siteContext
342
+ * @property {string} [urlStructure]
343
+ * @property {string} [starterTemplate]
344
+ */
345
+
346
+ /**
347
+ * @typedef {Object} StorefrontV2ResetResult
348
+ * @property {string} status
349
+ * @property {boolean} isProvisioned
350
+ * @property {string} [providerMode]
351
+ * @property {Array<string>} [approvedStarterTemplates]
352
+ */
353
+
354
+ /**
355
+ * @typedef {Object} StorefrontV2RepositoryTree
356
+ * @property {string} path
357
+ * @property {string} ref
358
+ * @property {Array<{name: string, path: string, type: string}>} entries
359
+ */
360
+
361
+ /**
362
+ * @typedef {Object} StorefrontV2RepositoryBranches
363
+ * @property {string} defaultBranch
364
+ * @property {string|null} [activeBranchName]
365
+ * @property {Array<string>} branches
366
+ */
367
+
368
+ /**
369
+ * @typedef {Object} StorefrontV2RepositoryFile
370
+ * @property {string} path
371
+ * @property {string} ref
372
+ * @property {string} [sha]
373
+ * @property {string} content
374
+ */
375
+
376
+ /**
377
+ * @typedef {Object} StorefrontV2RepositoryFileUpdatePayload
378
+ * @property {string} path
379
+ * @property {string} content
380
+ * @property {string} [message]
381
+ * @property {string} [branch]
382
+ */
383
+
384
+ /**
385
+ * @typedef {Object} StorefrontV2ProductPublishPayload
386
+ * @property {string} [productName]
387
+ * @property {string} [productUrl]
388
+ * @property {string} [branchName]
389
+ */
390
+
391
+ /**
392
+ * @typedef {Object} StorefrontV2CategoryPublishPayload
393
+ * @property {string} [categoryName]
394
+ * @property {string} [categoryUrl]
395
+ * @property {string} [branchName]
396
+ */
397
+
398
+ /**
399
+ * @typedef {Object} StorefrontV2SiteContextInput
400
+ * @property {string} [url]
401
+ * @property {string} [sourceUrl]
402
+ */
403
+
404
+ /**
405
+ * @typedef {Object} StorefrontExecutionEvent
406
+ * @property {string} timestamp
407
+ * @property {string} stage
408
+ * @property {string} [level]
409
+ * @property {string} message
410
+ * @property {Object} [metadata]
411
+ */
412
+
413
+ /**
414
+ * @typedef {Object} StorefrontV2ProvisionPayload
415
+ * @property {string} [starterTemplate]
416
+ * @property {string} [urlStructure]
417
+ */
418
+
419
+ /**
420
+ * @typedef {Object} StorefrontV2StarterTemplateUrlStructurePayload
421
+ * @property {string} starterTemplate
422
+ */
423
+
424
+ /**
425
+ * @typedef {Object} StorefrontV2SiteContext
426
+ * @property {string} sourceUrl
427
+ * @property {Object} [style]
428
+ * @property {Array<string>} [sitemap]
429
+ * @property {Array<Object>} [navigation]
430
+ * @property {Array<string>} [categories]
431
+ * @property {Array<string>} [products]
432
+ * @property {Array<Object>} [tracking]
433
+ * @property {Array<string>} [wireframe]
434
+ * @property {Array<Object>} [stylesheets]
435
+ * @property {Array<Object>} [pageAnalysis]
436
+ * @property {Object} [emulationSpec]
437
+ * @property {string} [analysisMarkdown]
438
+ * @property {string} [analysisFilePath]
439
+ * @property {string} [analysisJsonFilePath]
440
+ * @property {Array<string>} [analysisScreenshotPaths]
441
+ * @property {Array<Object>} [analysisScreenshots]
442
+ * @property {string} [analysisBranch]
443
+ */
444
+
264
445
  function appendPayload(request, payload) {
265
446
  Object.keys(payload).forEach(function(key) {
266
447
  var value = payload[key];
@@ -275,10 +456,18 @@ export function Domain() {
275
456
  });
276
457
  }
277
458
 
278
- function sendStorefrontRequest(resource, method, payload, success, error) {
459
+ function sendStorefrontRequest(resource, method, payload, success, error, queryParams) {
279
460
  var request = new Request();
280
461
  request.resource(resource).method(method);
281
462
  request.query().add('skip_rights', 'y');
463
+ if (queryParams) {
464
+ Object.keys(queryParams).forEach(function(key) {
465
+ var value = queryParams[key];
466
+ if (value !== undefined && value !== null && value !== '') {
467
+ request.query().add(key, value);
468
+ }
469
+ });
470
+ }
282
471
  if (payload) {
283
472
  appendPayload(request, payload);
284
473
  }
@@ -310,6 +499,11 @@ export function Domain() {
310
499
  );
311
500
  };
312
501
 
502
+ /**
503
+ * @param {StorefrontV2ProvisionPayload|Function} payload
504
+ * @param {Function} [success]
505
+ * @param {Function} [error]
506
+ */
313
507
  this.provisionStorefrontV2 = function (payload, success, error) {
314
508
  var args = parsePayloadAndCallbacks(payload, success, error);
315
509
  sendStorefrontRequest(
@@ -321,6 +515,43 @@ export function Domain() {
321
515
  );
322
516
  };
323
517
 
518
+ /**
519
+ * @param {StorefrontV2StarterTemplateUrlStructurePayload|Function} payload
520
+ * @param {Function} [success]
521
+ * @param {Function} [error]
522
+ */
523
+ this.resolveStarterTemplateUrlStructure = function (payload, success, error) {
524
+ var args = parsePayloadAndCallbacks(payload, success, error);
525
+ sendStorefrontRequest(
526
+ '/domains/' + this.id() + '/storefront_v2/starter_template/url_structure/',
527
+ 'POST',
528
+ args.payload,
529
+ args.success,
530
+ args.error
531
+ );
532
+ };
533
+
534
+ /**
535
+ * @param {StorefrontV2SiteContextInput|Function} payload
536
+ * @param {Function} [success]
537
+ * @param {Function} [error]
538
+ */
539
+ this.extractStorefrontV2SiteContext = function (payload, success, error) {
540
+ var args = parsePayloadAndCallbacks(payload, success, error);
541
+ sendStorefrontRequest(
542
+ '/domains/' + this.id() + '/storefront_v2/site_context/extract/',
543
+ 'POST',
544
+ args.payload,
545
+ args.success,
546
+ args.error
547
+ );
548
+ };
549
+
550
+ /**
551
+ * @param {StorefrontV2ChangeRequestPayload|Function} payload
552
+ * @param {Function} [success]
553
+ * @param {Function} [error]
554
+ */
324
555
  this.createStorefrontChangeRequest = function (payload, success, error) {
325
556
  var args = parsePayloadAndCallbacks(payload, success, error);
326
557
  sendStorefrontRequest(
@@ -332,6 +563,43 @@ export function Domain() {
332
563
  );
333
564
  };
334
565
 
566
+ /**
567
+ * @param {StorefrontV2GenerationBriefPayload|Function} payload
568
+ * @param {Function} [success]
569
+ * @param {Function} [error]
570
+ */
571
+ this.createStorefrontV2GenerationBrief = function (payload, success, error) {
572
+ var args = parsePayloadAndCallbacks(payload, success, error);
573
+ sendStorefrontRequest(
574
+ '/domains/' + this.id() + '/storefront_v2/generation_brief/',
575
+ 'POST',
576
+ args.payload,
577
+ args.success,
578
+ args.error
579
+ );
580
+ };
581
+
582
+ this.resetStorefrontV2 = function (success, error) {
583
+ if (typeof success === 'function' && error === undefined) {
584
+ sendStorefrontRequest(
585
+ '/domains/' + this.id() + '/storefront_v2/reset/',
586
+ 'POST',
587
+ null,
588
+ success,
589
+ error
590
+ );
591
+ return;
592
+ }
593
+ var args = parsePayloadAndCallbacks(success, error);
594
+ sendStorefrontRequest(
595
+ '/domains/' + this.id() + '/storefront_v2/reset/',
596
+ 'POST',
597
+ args.payload,
598
+ args.success,
599
+ args.error
600
+ );
601
+ };
602
+
335
603
  this.getStorefrontChangeRequest = function (requestId, success, error) {
336
604
  sendStorefrontRequest(
337
605
  '/storefront_change_requests/' + requestId + '/',
@@ -342,6 +610,16 @@ export function Domain() {
342
610
  );
343
611
  };
344
612
 
613
+ this.getStorefrontChangeRequestEvents = function (requestId, success, error) {
614
+ sendStorefrontRequest(
615
+ '/storefront_change_requests/' + requestId + '/events/',
616
+ 'GET',
617
+ null,
618
+ success,
619
+ error
620
+ );
621
+ };
622
+
345
623
  this.runStorefrontChangeRequest = function (requestId, payload, success, error) {
346
624
  var args = parsePayloadAndCallbacks(payload, success, error);
347
625
  sendStorefrontRequest(
@@ -406,6 +684,113 @@ export function Domain() {
406
684
  args.error
407
685
  );
408
686
  };
687
+
688
+ /**
689
+ * @param {{path?: string, ref?: string}|Function} payload
690
+ * @param {Function} [success]
691
+ * @param {Function} [error]
692
+ */
693
+ this.getStorefrontV2RepositoryTree = function (payload, success, error) {
694
+ var args = parsePayloadAndCallbacks(payload, success, error);
695
+ sendStorefrontRequest(
696
+ '/domains/' + this.id() + '/storefront_v2/repository_tree/',
697
+ 'GET',
698
+ null,
699
+ args.success,
700
+ args.error,
701
+ args.payload
702
+ );
703
+ };
704
+
705
+ this.getStorefrontV2RepositoryBranches = function (success, error) {
706
+ sendStorefrontRequest(
707
+ '/domains/' + this.id() + '/storefront_v2/repository_branches/',
708
+ 'GET',
709
+ null,
710
+ success,
711
+ error
712
+ );
713
+ };
714
+
715
+ /**
716
+ * @param {string} path
717
+ * @param {{ref?: string}|Function} refOrSuccess
718
+ * @param {Function} [success]
719
+ * @param {Function} [error]
720
+ */
721
+ this.getStorefrontV2RepositoryFile = function (path, refOrSuccess, success, error) {
722
+ var queryParams = {path: path};
723
+ if (typeof refOrSuccess === 'function') {
724
+ sendStorefrontRequest(
725
+ '/domains/' + this.id() + '/storefront_v2/repository_file/',
726
+ 'GET',
727
+ null,
728
+ refOrSuccess,
729
+ success,
730
+ queryParams
731
+ );
732
+ return;
733
+ }
734
+ if (refOrSuccess && refOrSuccess.ref) {
735
+ queryParams.ref = refOrSuccess.ref;
736
+ }
737
+ sendStorefrontRequest(
738
+ '/domains/' + this.id() + '/storefront_v2/repository_file/',
739
+ 'GET',
740
+ null,
741
+ success,
742
+ error,
743
+ queryParams
744
+ );
745
+ };
746
+
747
+ /**
748
+ * @param {StorefrontV2RepositoryFileUpdatePayload|Function} payload
749
+ * @param {Function} [success]
750
+ * @param {Function} [error]
751
+ */
752
+ this.updateStorefrontV2RepositoryFile = function (payload, success, error) {
753
+ var args = parsePayloadAndCallbacks(payload, success, error);
754
+ sendStorefrontRequest(
755
+ '/domains/' + this.id() + '/storefront_v2/repository_file/',
756
+ 'POST',
757
+ args.payload,
758
+ args.success,
759
+ args.error
760
+ );
761
+ };
762
+
763
+ /**
764
+ * @param {StorefrontV2ProductPublishPayload|Function} payload
765
+ * @param {Function} [success]
766
+ * @param {Function} [error]
767
+ */
768
+ this.publishStorefrontV2Product = function (payload, success, error) {
769
+ var args = parsePayloadAndCallbacks(payload, success, error);
770
+ sendStorefrontRequest(
771
+ '/domains/' + this.id() + '/storefront_v2/products/publish/',
772
+ 'POST',
773
+ args.payload,
774
+ args.success,
775
+ args.error
776
+ );
777
+ };
778
+
779
+ /**
780
+ * @param {StorefrontV2CategoryPublishPayload|Function} payload
781
+ * @param {Function} [success]
782
+ * @param {Function} [error]
783
+ */
784
+ this.publishStorefrontV2Category = function (payload, success, error) {
785
+ var args = parsePayloadAndCallbacks(payload, success, error);
786
+ sendStorefrontRequest(
787
+ '/domains/' + this.id() + '/storefront_v2/categories/publish/',
788
+ 'POST',
789
+ args.payload,
790
+ args.success,
791
+ args.error
792
+ );
793
+ };
409
794
  }
410
795
 
411
796
  export function Domains() {
package/src/job.js CHANGED
@@ -51,6 +51,7 @@ export function Job() {
51
51
  addPropertyTo(this, 'deadline');
52
52
  addPropertyTo(this, 'updated');
53
53
  addPropertyTo(this, 'dateLastActioned');
54
+ addPropertyTo(this, 'dateFirstActioned');
54
55
  addPropertyTo(this, 'deductionDate');
55
56
  addPropertyTo(this, 'preDraftCommentsCount');
56
57
  addPropertyTo(this, 'clientFiles', MerchiFile);
package/src/merchi.js CHANGED
@@ -1,3 +1,4 @@
1
+ import axios from 'axios';
1
2
  import { isBrowser } from 'browser-or-node';
2
3
  import { generateUUID } from './uuid.js';
3
4
  import { isNull, isUndefined, isUndefinedOrNull, id,
@@ -88,6 +89,12 @@ import { AgentSkillApproval, AgentSkillApprovals } from './agent_skill_approval.
88
89
  import { DomainChatSettings, DomainChatSettingsList } from './domain_chat_settings.js';
89
90
  import { SupportConversation, SupportConversations } from './support_conversation.js';
90
91
  import { SupportMessage, SupportMessages } from './support_message.js';
92
+ import {
93
+ ProductReview,
94
+ ProductReviews,
95
+ normalizeProductReviewApiJson,
96
+ wireProductReviewCreateBody,
97
+ } from './product_review.js';
91
98
 
92
99
  export function merchi(backendUri, websocketUri) {
93
100
  getGlobal().merchiJsonpHandlers = {};
@@ -866,6 +873,98 @@ export function merchi(backendUri, websocketUri) {
866
873
  request.send();
867
874
  }
868
875
 
876
+ function productReviewsApiRoot() {
877
+ var base = getGlobal().merchiBackendUri;
878
+ if (!base.endsWith('/')) {
879
+ base += '/';
880
+ }
881
+ return base + 'v6';
882
+ }
883
+
884
+ function productReviewsSessionSuffix() {
885
+ if (getGlobal().currentSession &&
886
+ getGlobal().currentSession.token()) {
887
+ return '?session_token=' + encodeURIComponent(
888
+ getGlobal().currentSession.token());
889
+ }
890
+ return '';
891
+ }
892
+
893
+ /**
894
+ * List product reviews (domain manager/admin). ``success`` receives
895
+ * ``{ productReviews: ... }`` — same keys as the API, but each row is a
896
+ * ``ProductReview`` model instance with ``job`` / ``product`` / ``domain``.
897
+ */
898
+ function listProductReviews(productId, success, error) {
899
+ var url = productReviewsApiRoot() + '/products/' + productId +
900
+ '/reviews/' + productReviewsSessionSuffix();
901
+ axios.get(url)
902
+ .then(function (res) {
903
+ var reviews = new ProductReviews().fromProductListResponse(
904
+ res.data);
905
+ success(Object.assign({}, res.data, {productReviews: reviews}));
906
+ })
907
+ .catch(function (err) {
908
+ error(err.response ? err.response.data : err);
909
+ });
910
+ }
911
+
912
+ /**
913
+ * Create a product review (buyer, JSON body). Send ``jobId`` or ``job: { id }``
914
+ * (completed job whose catalog product matches ``productId`` after clone
915
+ * resolution), plus ``rating`` and optional ``title`` / ``content``.
916
+ * ``success`` receives ``{ productReview }`` as a ``ProductReview`` model.
917
+ */
918
+ function createProductReview(productId, data, success, error) {
919
+ var url = productReviewsApiRoot() + '/products/' + productId +
920
+ '/reviews/' + productReviewsSessionSuffix();
921
+ axios.post(url, wireProductReviewCreateBody(data), {
922
+ headers: {'Content-Type': 'application/json'},
923
+ })
924
+ .then(function (res) {
925
+ var pr = fromJson(
926
+ new ProductReview(),
927
+ normalizeProductReviewApiJson(res.data.productReview),
928
+ {makesDirty: false});
929
+ success(Object.assign({}, res.data, {productReview: pr}));
930
+ })
931
+ .catch(function (err) {
932
+ error(err.response ? err.response.data : err);
933
+ });
934
+ }
935
+
936
+ /**
937
+ * Patch a review (``formFields`` plain object: status, rejectionReason,
938
+ * rating, title, content — sent as multipart form data).
939
+ * ``success`` receives ``{ productReview }`` as a model when present.
940
+ */
941
+ function patchProductReview(reviewId, formFields, success, error) {
942
+ var url = productReviewsApiRoot() + '/product-reviews/' + reviewId +
943
+ '/' + productReviewsSessionSuffix();
944
+ var fd = new FormData();
945
+ Object.keys(formFields || {}).forEach(function (k) {
946
+ var v = formFields[k];
947
+ if (v !== undefined && v !== null) {
948
+ fd.append(k, String(v));
949
+ }
950
+ });
951
+ axios.patch(url, fd)
952
+ .then(function (res) {
953
+ if (!res.data || !res.data.productReview) {
954
+ success(res.data);
955
+ return;
956
+ }
957
+ var pr = fromJson(
958
+ new ProductReview(),
959
+ normalizeProductReviewApiJson(res.data.productReview),
960
+ {makesDirty: false});
961
+ success(Object.assign({}, res.data, {productReview: pr}));
962
+ })
963
+ .catch(function (err) {
964
+ error(err.response ? err.response.data : err);
965
+ });
966
+ }
967
+
869
968
  function getProductShipmentOptions(
870
969
  productId, quantity, address, success, error) {
871
970
  var request = new Request(),
@@ -1025,6 +1124,10 @@ export function merchi(backendUri, websocketUri) {
1025
1124
  'supportConversations': new SupportConversations(),
1026
1125
  'SupportMessage': SupportMessage,
1027
1126
  'supportMessages': new SupportMessages(),
1127
+ 'ProductReview': ProductReview,
1128
+ 'productReviews': new ProductReviews(),
1129
+ 'normalizeProductReviewApiJson': normalizeProductReviewApiJson,
1130
+ 'wireProductReviewCreateBody': wireProductReviewCreateBody,
1028
1131
  'SubscriptionPlan': SubscriptionPlan,
1029
1132
  'subscriptionPlans': new SubscriptionPlans(),
1030
1133
  'VariationField': VariationField,
@@ -1103,5 +1206,8 @@ export function merchi(backendUri, websocketUri) {
1103
1206
  'productTypes': productTypes,
1104
1207
  'productTypesInts': productTypesInts,
1105
1208
  'productTypesSeller': productTypesSeller,
1106
- 'getProductShipmentOptions': getProductShipmentOptions};
1209
+ 'getProductShipmentOptions': getProductShipmentOptions,
1210
+ 'listProductReviews': listProductReviews,
1211
+ 'createProductReview': createProductReview,
1212
+ 'patchProductReview': patchProductReview};
1107
1213
  }
package/src/model.js CHANGED
@@ -335,6 +335,10 @@ export function getList(resource, success, error, parameters, withUpdates) {
335
335
  if (parameters.asRole) {
336
336
  request.query().add('as_role', JSON.stringify(parameters.asRole));
337
337
  }
338
+ if (notEmpty(parameters.isJobManager)) {
339
+ request.query().add('is_job_manager',
340
+ JSON.stringify(parameters.isJobManager));
341
+ }
338
342
  if (parameters.groupBuyOnly) {
339
343
  request.query().add('group_buy_only',
340
344
  JSON.stringify(parameters.groupBuyOnly));
@@ -0,0 +1,96 @@
1
+ import { generateUUID } from './uuid.js';
2
+ import { addPropertyTo, fromJson } from './model.js';
3
+ import { Domain } from './domain.js';
4
+ import { Job } from './job.js';
5
+ import { Product } from './product.js';
6
+
7
+ /**
8
+ * Map flat API fields (jobId, productId, domainId) onto job / product / domain
9
+ * before ``fromJson``.
10
+ */
11
+ export function normalizeProductReviewApiJson(json) {
12
+ if (json === null || json === undefined || typeof json !== 'object') {
13
+ return json;
14
+ }
15
+ var row = Object.assign({}, json);
16
+ if (row.jobId !== undefined && row.job === undefined) {
17
+ if (row.jobId != null) {
18
+ row.job = {id: row.jobId};
19
+ }
20
+ delete row.jobId;
21
+ }
22
+ if (row.productId !== undefined && row.product === undefined) {
23
+ if (row.productId != null) {
24
+ row.product = {id: row.productId};
25
+ }
26
+ delete row.productId;
27
+ }
28
+ if (row.domainId !== undefined && row.domain === undefined) {
29
+ if (row.domainId != null) {
30
+ row.domain = {id: row.domainId};
31
+ }
32
+ delete row.domainId;
33
+ }
34
+ return row;
35
+ }
36
+
37
+ /**
38
+ * Turn create payload ``{ job: { id }, rating, ... }`` into API JSON with ``jobId``.
39
+ * Pass-through if ``jobId`` is already set.
40
+ */
41
+ export function wireProductReviewCreateBody(data) {
42
+ if (!data || typeof data !== 'object') {
43
+ return data;
44
+ }
45
+ var body = Object.assign({}, data);
46
+ if (body.job && body.job.id != null && body.jobId === undefined) {
47
+ body.jobId = body.job.id;
48
+ delete body.job;
49
+ }
50
+ return body;
51
+ }
52
+
53
+ export function ProductReview() {
54
+ this.resource = '/product-reviews';
55
+ this.json = 'productReview';
56
+ this.temporaryId = generateUUID();
57
+
58
+ addPropertyTo(this, 'id');
59
+ addPropertyTo(this, 'product', Product);
60
+ addPropertyTo(this, 'domain', Domain);
61
+ addPropertyTo(this, 'authorUserId');
62
+ addPropertyTo(this, 'authorName');
63
+ addPropertyTo(this, 'job', Job);
64
+ addPropertyTo(this, 'rating');
65
+ addPropertyTo(this, 'title');
66
+ addPropertyTo(this, 'content');
67
+ addPropertyTo(this, 'status');
68
+ addPropertyTo(this, 'purchaseInvoiceId');
69
+ addPropertyTo(this, 'submittedAt');
70
+ addPropertyTo(this, 'updatedAt');
71
+ addPropertyTo(this, 'rejectionReason');
72
+ }
73
+
74
+ export function ProductReviews() {
75
+ this.json = 'productReviews';
76
+ this.single = ProductReview;
77
+
78
+ /**
79
+ * @param {object} data - API body with ``productReviews`` array
80
+ * @param {object} [options] - passed to ``fromJson`` (e.g. ``{makesDirty: false}``)
81
+ * @returns {ProductReview[]}
82
+ */
83
+ this.fromProductListResponse = function (data, options) {
84
+ var raw = (data && data.productReviews) ? data.productReviews : [];
85
+ var self = this;
86
+ var defaults = {makesDirty: false};
87
+ var opts = Object.assign({}, defaults, options);
88
+ return raw.map(function (row) {
89
+ return fromJson(
90
+ new self.single(),
91
+ normalizeProductReviewApiJson(row),
92
+ opts
93
+ );
94
+ });
95
+ };
96
+ }