1window.__reviewXState__ = function () { 2 return { 3 rvxAttributes: { 4 // settings: { 5 // isVerified: 'no', 6 // }, 7 product: { 8 id: null, 9 postType: 'product', 10 }, 11 userInfo: { 12 isLoggedIn: null, 13 id: null, 14 name: null, 15 email: null, 16 isVerified: false, 17 }, 18 baseDomain: '', 19 baseRestUrl: '', 20 formLevelData: {} 21 }, 22 newReview: { 23 rating: 5, 24 reviewer_email: '', 25 reviewer_name: '', 26 is_anonymous: false, 27 consent: false, 28 title: '', 29 feedback: '', 30 is_recommended: 'true' 31 }, 32 isRvxUserLoggedIn: false, 33 isRvxUserVerified: false, 34 fetchReviewsIsLoading: true, 35 isReviewSubmitting: false, 36 fetchReviewsSettingsIsLoading: false, 37 haveReviews: false, 38 isFiltering: false, 39 reviewsData: null, 40 reviewsAllData: null, 41 reviewListShortCodeData: null, 42 reviewWithReviewIdsShortCodeData: null, 43 reviewSettingsData: undefined, 44 reviewAggregationData: null, 45 isLoadMoreReviews: false, 46 isLoadMoreAllReviews: false, 47 layoutView: 'list', 48 formatAggregations: [], 49 formatMultiCriteriaAggregations: [], 50 multiCriteriaRatings: [], 51 attachmentFiles: [], 52 showReviewSuccessModal: false, 53 showReviewDetailsModal: false, 54 selectedReviewDetails: {}, 55 storeFrontReviewQuery: {}, 56 storeFrontAllReviewQuery: {}, 57 storeFrontAllReviewParams: {}, 58 storeFrontReviewListShortcodeQuery: {}, 59 storeFrontValidation: { 60 isValidReviewTitle: false, 61 isValidReviewFeedback: false, 62 isValidReviewerName: false, 63 isValidReviewerEmail: false, 64 isNotRobot: false, 65 reviewSubmitFailed: false, 66 isAcceptConsent: false 67 }, 68 showErrorToastMessage: false, 69 errorToastMessage: '', 70 71 rvxAttributesDataSetHandler(rvxAttributes) { 72 this.rvxAttributes = { 73 ...this.rvxAttributes, 74 ...rvxAttributes, 75 baseDomain: `${rvxAttributes.domain.baseDomain}/wp-json/reviewx/api/v1/storefront`, 76 baseRestUrl: `${rvxAttributes.domain.baseRestUrl}/api/v1/storefront` 77 } 78 this.isRvxUserLoggedIn = this.rvxAttributes?.userInfo?.isLoggedIn ? true : false 79 this.isRvxUserVerified = this.rvxAttributes?.userInfo?.isVerified ? true : false 80 }, 81 selectedReviewDetailsHandler(review) { 82 this.selectedReviewDetails = review 83 this.showReviewDetailsModal = true 84 }, 85 appendReviews(newRes) { 86 this.reviewsData = { 87 ...this.reviewsData, 88 data: { 89 ...this.reviewsData.data, 90 reviews: [ 91 ...this.reviewsData.data.reviews, 92 ...newRes.data.reviews], 93 meta: { ...this.reviewsData.data.meta, ...newRes.data.meta }, 94 } 95 }; 96 }, 97 appendAllReviews(newRes) { 98 this.reviewsAllData = { 99 ...this.reviewsAllData, 100 data: { 101 ...this.reviewsAllData.data, 102 reviews: [ 103 ...this.reviewsAllData.data.reviews, 104 ...newRes.data.reviews], 105 meta: { ...this.reviewsAllData.data.meta, ...newRes.data.meta }, 106 } 107 }; 108 }, 109 async fetchReviews({ query, loadMoreReview, productId }) { 110 if (loadMoreReview) { 111 this.isLoadMoreReviews = true 112 } else { 113 this.fetchReviewsIsLoading = true; 114 } 115 let queryParams; 116 if (query) { 117 const newQuery = { 118 ...query 119 } 120 queryParams = this.generateQueryParams(newQuery) 121 } 122 try { 123 const url = `${this.rvxAttributes.baseRestUrl}/${productId}/reviews${queryParams ? '?' + queryParams : ''}`; 124 const data = await fetch(url); 125 const res = await data.json(); 126 if (loadMoreReview && this.reviewsData?.data?.reviews?.length) { 127 this.appendReviews(res); 128 } else { 129 this.reviewsData = res; 130 this.reviewListShortCodeData = res; 131 } 132 133 if (res?.data?.reviews?.length) { 134 this.haveReviews = true; 135 } 136 } catch (e) { 137 // console.log('Error fetching reviews:', e); 138 } finally { 139 this.fetchReviewsIsLoading = false;
140 this.isLoadMoreReviews = false 141 } 142 }, 143 async fetchReviewsListShortcode({ query, loadMoreReview, productId }) { 144 if (loadMoreReview) { 145 this.isLoadMoreReviews = true 146 } else { 147 this.fetchReviewsIsLoading = true; 148 } 149 let queryParams; 150 if (query) { 151 const newQuery = { 152 ...query 153 } 154 queryParams = this.generateQueryParams(newQuery) 155 } 156 try { 157 const url = `${this.rvxAttributes.baseRestUrl}/${productId}/reviews/shortcode${queryParams ? '?' + queryParams : ''}`; 158 // console.log('URL =====', url) 159 const data = await fetch(url); 160 const res = await data.json(); 161 if (loadMoreReview && this.reviewsData?.data?.reviews?.length) { 162 this.appendReviews(res); 163 } else { 164 this.reviewsData = res; 165 this.reviewListShortCodeData = res; 166 } 167 168 if (res?.data?.reviews?.length) { 169 this.haveReviews = true; 170 } 171 } catch (e) { 172 // console.log('Error fetching reviews:', e); 173 } finally { 174 this.fetchReviewsIsLoading = false; 175 this.isLoadMoreReviews = false 176 } 177 }, 178 179 // ////////////////////////// 180 // async fetchReviewListShortCodes(ids) { 181 // this.fetchReviewsIsLoading = true; 182 // const reviewListShortCodeIds = ids?.[0] 183 // if (!reviewListShortCodeIds) return 184 // try { 185 // const url = `${this.rvxAttributes.baseRestUrl}/${reviewListShortCodeIds}/reviews`; 186 // const data = await fetch(url); 187 // const res = await data.json(); 188 // if (!res?.data?.reviews?.length) { 189 // this.haveReviews = true; // No more reviews available 190 // } else { 191 // this.reviewListShortCodeData = res; 192 // } 193 // } catch (e) { 194 // console.log('Error fetching reviews:', e); 195 // } finally { 196 // this.fetchReviewsIsLoading = false; 197 // } 198 // }, 199 // ////////////////////////// 200 201 async fetchAllReviewListShortCodes({ query, loadMoreReview }) { 202 if (loadMoreReview) { 203 this.isLoadMoreAllReviews = true 204 } else { 205 this.fetchReviewsIsLoading = true; 206 } 207 let queryParams; 208 if (query) { 209 const newQuery = { 210 ...query 211 } 212 queryParams = this.generateQueryParams(newQuery) 213 } 214 try { 215 const params = {} 216 217 // Only include if value is a non-empty string 218 if (typeof this.storeFrontAllReviewParams?.post_type === 'string' && this.storeFrontAllReviewParams.post_type.trim() !== '') { 219 params.post_type = this.storeFrontAllReviewParams.post_type.trim() 220 } 221 if (typeof this.storeFrontAllReviewParams?.sort_by === 'string' && this.storeFrontAllReviewParams.sort_by.trim() !== '') { 222 params.sort_by = this.storeFrontAllReviewParams.sort_by.trim() 223 } 224 if (typeof this.storeFrontAllReviewParams?.rating === 'string' && this.storeFrontAllReviewParams.rating.trim() !== '') { 225 params.rating = this.storeFrontAllReviewParams.rating.trim() 226 } 227 if (typeof this.storeFrontAllReviewParams?.attachment === 'string' && this.storeFrontAllReviewParams.attachment.trim() !== '') { 228 params.attachment = this.storeFrontAllReviewParams.attachment.trim() 229 } 230 231 // Build query string for dynamic params 232 const dynamicParams = new URLSearchParams(params).toString() 233 234 let queryString = '' 235 236 if (dynamicParams && queryParams) { 237 queryString = `?${dynamicParams}&${queryParams}` 238 } else if (dynamicParams) { 239 queryString = `?${dynamicParams}` 240 } else if (queryParams) { 241 queryString = `?${queryParams}` 242 } 243 244 const url = `${this.rvxAttributes.baseRestUrl}/all/reviews/shortcode${queryString}` 245 246 const data = await fetch(url, { 247 method: 'POST', 248 headers: { 'Content-Type': 'application/json' }, 249 body: JSON.stringify(query), 250 }) 251 const res = await data.json() 252 253 254 if (loadMoreReview && this.reviewsAllData?.data?.reviews?.length) { 255 this.appendAllReviews(res); 256 } else { 257 this.reviewsAllData = res; 258 } 259 260 if (res?.data?.reviews?.length) { 261 this.haveReviews = true; 262 } 263 } catch (e) { 264 console.log('Error fetching reviews:', e); 265 } finally { 266 this.fetchReviewsIsLoading = false;
267 this.isLoadMoreAllReviews = false 268 } 269 }, 270 271 async fetchReviewListWithIdsShortCodes(ids) { 272 this.fetchReviewsIsLoading = true; 273 const reviewsShortCodeIds = ids 274 if (!reviewsShortCodeIds?.length) return 275 const payload = { 276 review_ids: reviewsShortCodeIds 277 } 278 try { 279 const url = `${this.rvxAttributes.baseRestUrl}/widgets/short/code/reviews`; 280 const data = await fetch(url, { 281 method: 'POST', 282 body: JSON.stringify(payload), 283 headers: { 284 'Content-Type': 'application/json' 285 } 286 }); 287 const res = await data.json(); 288 // console.log('res =====', res) 289 if (!res?.data?.reviews?.length) { 290 this.haveReviews = true; // No more reviews available 291 } else { 292 this.reviewWithReviewIdsShortCodeData = res; 293 } 294 } catch (e) { 295 console.log('Error fetching reviews:', e); 296 } finally { 297 this.fetchReviewsIsLoading = false; 298 } 299 }, 300 loadMoreReviewHandler() { 301 // this.isLoadMoreReviews = true; 302 const cursor = this.reviewsData?.data?.meta?.next_cursor; 303 if (cursor) { 304 this.storeFrontReviewQuery = { 305 ...this.storeFrontReviewQuery, 306 cursor 307 }; 308 this.fetchReviews({ 309 query: this.storeFrontReviewQuery, 310 loadMoreReview: true, 311 productId: this.rvxAttributes?.product?.id 312 }); 313 } 314 }, 315 loadMoreReviewAllHandler() { 316 // this.isLoadMoreAllReviews = true; 317 const cursor = this.reviewsAllData?.data?.meta?.next_cursor; 318 if (cursor) { 319 this.storeFrontAllReviewQuery = { 320 ...this.storeFrontAllReviewQuery, 321 cursor 322 }; 323 this.fetchAllReviewListShortCodes({ 324 query: this.storeFrontAllReviewQuery, 325 loadMoreReview: true, 326 }); 327 } 328 }, 329 async fetchReviewListShortcodeReviews({ query, loadMoreReview, productId }) { 330 if (loadMoreReview) { 331 this.isLoadMoreReviews = true; 332 } else { 333 this.fetchReviewsIsLoading = true; 334 } 335 let queryParams; 336 if (query) { 337 const newQuery = { ...query }; 338 queryParams = this.generateQueryParams(newQuery); 339 } 340 try { 341 const url = `${this.rvxAttributes.baseRestUrl}/${productId}/reviews${queryParams ? '?' + queryParams : ''}`; 342 const data = await fetch(url); 343 const res = await data.json(); 344 345 if (loadMoreReview) { 346 // Append new reviews to existing data 347 if (this.reviewListShortCodeData?.data?.reviews) { 348 this.reviewListShortCodeData = { 349 ...this.reviewListShortCodeData, 350 data: { 351 ...this.reviewListShortCodeData.data, 352 reviews: [...this.reviewListShortCodeData.data.reviews, ...res.data.reviews], 353 meta: res.data.meta // Update next_cursor 354 } 355 }; 356 } else { 357 this.reviewListShortCodeData = res; 358 } 359 } else { 360 // Initial load 361 this.reviewListShortCodeData = res; 362 } 363 364 if (res?.data?.reviews?.length) { 365 this.haveReviews = true; 366 } 367 } catch (e) { 368 console.log('Error fetching reviews:', e); 369 } finally { 370 this.fetchReviewsIsLoading = false;
371 this.isLoadMoreReviews = false; 372 } 373 }, 374 async fetchAllReviewListShortcodeReviews({ query, loadMoreReview }) { 375 if (loadMoreReview) { 376 this.isLoadMoreAllReviews = true; 377 } else { 378 this.fetchReviewsIsLoading = true; 379 } 380 let queryParams; 381 if (query) { 382 queryParams = query; 383 } 384 try { 385 const url = `${this.rvxAttributes.baseRestUrl}/all/reviews/shortcode`; 386 const data = await fetch(url, { 387 method: 'POST', // Use POST instead of GET 388 headers: { 389 'Content-Type': 'application/json', 390 }, 391 body: JSON.stringify(queryParams), 392 }); 393 const res = await data.json(); 394 395 if (loadMoreReview) { 396 // Append new reviews to existing data 397 if (this.reviewListShortCodeData?.data?.reviews) { 398 this.reviewListShortCodeData = { 399 ...this.reviewListShortCodeData, 400 data: { 401 ...this.reviewListShortCodeData.data, 402 reviews: [...this.reviewListShortCodeData.data.reviews, ...res.data.reviews], 403 meta: res.data.meta // Update next_cursor 404 } 405 }; 406 } else { 407 this.reviewListShortCodeData = res; 408 } 409 } else { 410 // Initial load 411 this.reviewListShortCodeData = res; 412 } 413 414 if (res?.data?.reviews?.length) { 415 this.haveReviews = true; 416 } 417 } catch (e) { 418 console.log('Error fetching reviews:', e); 419 } finally { 420 this.fetchReviewsIsLoading = false; 421 this.isLoadMoreAllReviews = false; 422 } 423 }, 424 loadMoreReviewListShortcodeHandler() { 425 const cursor = this.reviewListShortCodeData?.data?.meta?.next_cursor; 426 if (cursor) { 427 this.storeFrontReviewListShortcodeQuery = { 428 ...this.storeFrontReviewListShortcodeQuery, 429 cursor 430 }; 431 this.fetchReviewListShortcodeReviews({ 432 query: this.storeFrontReviewListShortcodeQuery, 433 loadMoreReview: true, 434 productId: this.reviewListShortCodeData?.data?.reviews[0]?.product_wp_id 435 }); 436 console.log('Product ID: ', storeFrontReviewListShortcodeQuery); 437 } 438 }, 439 loadMoreAllReviewListShortcodeHandler() { 440 const cursor = this.reviewListShortCodeData?.data?.meta?.next_cursor; 441 const per_page = this.reviewListShortCodeData?.data?.meta?.per_page; 442 443 if (cursor) { 444 this.storeFrontReviewListShortcodeQuery = { 445 ...this.storeFrontReviewListShortcodeQuery, 446 cursor, 447 per_page 448 }; 449 this.fetchAllReviewListShortcodeReviews({ 450 query: this.storeFrontReviewListShortcodeQuery, 451 loadMoreReview: true 452 }); 453 console.log('Product ID: ', storeFrontReviewListShortcodeQuery); 454 } 455 }, 456 async fetchReviewsSettings() { 457 this.fetchReviewsSettingsIsLoading = true; 458 let postType = this.rvxAttributes?.product?.postType ? this.rvxAttributes?.product?.postType : 'product'; 459 try { 460 const data = await fetch(`${this.rvxAttributes.baseRestUrl}/wp/settings${'?cpt_type=' + postType}`); 461 const res = await data.json(); 462 this.reviewSettingsData = res; 463 this.layoutView = res?.data.setting?.widget_settings?.outline?.layout_type 464 // console.log('Settings:', res); 465 if (res?.data?.setting?.review_settings) { 466 this.multiCriteriaRatings = this.createMultiCriteriaRatingObject({ 467 criterias: res?.data.setting.review_settings.reviews.multicriteria.criterias 468 }) 469 } 470 471 if (res.data.setting.review_settings?.reviews?.recaptcha?.enabled) { 472 const script = document.createElement('script'); 473 script.src = `https://www.google.com/recaptcha/api.js?render=${res.data.setting.review_settings?.reviews?.recaptcha.site_key}` 474 document.head.appendChild(script); 475 } 476 } catch (e) { 477 console.log('Error fetching settings:', e); 478 } finally { 479 this.fetchReviewsSettingsIsLoading = false;
480 } 481 }, 482 async fetchReviewsAggregation({ productId }) { 483 // console.log('Fetching review Aggregation'); 484 this.fetchReviewsSettingsIsLoading = true; 485 try { 486 const data = await fetch(`${this.rvxAttributes.baseRestUrl}/${productId}/insight`); 487 const res = await data.json(); 488 if (res.data?.aggregation) { 489 this.formatAggregations = [ 490 { 491 rating: 5, 492 total: res?.data?.aggregation.five.total, 493 percent: res?.data.aggregation.five.percentage 494 }, 495 { 496 rating: 4, 497 total: res?.data?.aggregation.four.total, 498 percent: res?.data.aggregation.four.percentage 499 }, 500 { 501 rating: 3, 502 total: res?.data?.aggregation.three.total, 503 percent: res?.data.aggregation.three.percentage 504 }, 505 { 506 rating: 2, 507 total: res?.data?.aggregation.two.total, 508 percent: res?.data.aggregation.two.percentage 509 }, 510 { 511 rating: 1, 512 total: res?.data?.aggregation.one.total, 513 percent: res?.data.aggregation.one.percentage 514 }, 515 ] 516 this.formatMultiCriteriaAggregations = this.formattedMultiCriteriaAggregation({ 517 criteriaStats: res.data.criteria_stats, 518 criterias: this.reviewSettingsData.data.setting.review_settings.reviews.multicriteria.criterias, 519 totalAvaReview: res.data?.aggregation.total_avg_review 520 }) 521 } 522 this.reviewAggregationData = res; 523 524 } catch (e) { 525 console.log('Error fetching settings:', e); 526 } finally { 527 this.fetchReviewsSettingsIsLoading = false; 528 } 529 }, 530 formattedMultiCriteriaAggregation({ criteriaStats, criterias, totalAvaReview, percentDefaultValue = 5 }) { 531 return criterias?.map((criteria) => { 532 const total = criteriaStats[criteria.key] || 0; 533 let modifyTotal 534 if (total === 0 && totalAvaReview > 0) { 535 modifyTotal = totalAvaReview 536 } else { 537 modifyTotal = total 538 } 539 const percent = (modifyTotal / percentDefaultValue) * 100; 540 return { 541 key: criteria.key, 542 name: criteria.name, 543 total: modifyTotal, 544 // total, 545 percent, 546 }; 547 }); 548 }, 549 createMultiCriteriaRatingObject({ criterias, criteriaStats, existingRating }) { 550 const newCriterial = criterias.map((criteria) => { 551 if (criteriaStats) { 552 let rating; 553 const getRating = criteriaStats?.[criteria.key]; 554 if (getRating) { 555 rating = getRating; 556 } else if (existingRating) { 557 rating = Number(existingRating); 558 } else { 559 rating = 5 560 } 561 return { 562 ...criteria, 563 rating, 564 }; 565 } else { 566 return { 567 ...criteria, 568 rating: 5, 569 }; 570 } 571 }); 572 return newCriterial; 573 }, 574 notifyAttachmentAdded(files) { 575 this.attachmentFiles = files.blobFiles 576 }, 577 multiCriteriaRatingsToObject(array) { 578 return array.reduce((acc, curr) => { 579 acc[curr.key] = curr.rating; 580 return acc; 581 }, {}); 582 }, 583 googleRecaptchaVerify() { 584 return new Promise((resolve, reject) => { 585 const siteKey = this.reviewSettingsData?.data?.setting.review_settings?.reviews?.recaptcha.site_key; 586 if (!siteKey || !grecaptcha) { 587 return reject('Recaptcha or site key is not defined'); 588 } 589 const baseAPIEndPoint = this.rvxAttributes.baseRestUrl 590 grecaptcha.ready(function () { 591 grecaptcha.execute(siteKey, { action: 'submit' }).then(async function (token) { 592 try { 593 const payload = { 594 token 595 } 596 const data = await fetch(`${baseAPIEndPoint}/google/recaptcha/verify`, { 597 method: 'post', 598 body: JSON.stringify(payload), 599 headers: { 600 'Content-Type': 'application/json', 601 } 602 }) 603 const res = await data.json() 604 resolve(res.result); 605 } catch (e) { 606 reject(e); 607 } 608 }).catch(function (error) { 609 console.error('Recaptcha error:', error); 610 reject(error); 611 }); 612 }); 613 }); 614 }, 615 checkValidity(field) { 616 this.storeFrontValidation[field] = !!this.newReview[field]; 617 }, 618 async fetchUserIPAddress() { 619 try { 620 const response = await fetch('https://api.ipify.org?format=json'); 621 const data = await response.json(); 622 // console.log('Your IP address is:', data.ip); 623 return data.ip; 624 } catch (error) { 625 console.error('Error fetching IP address:', error); 626 return null; // Handle error as needed 627 } 628 }, 629 async reviewFormValidation() { 630 let isValid = true; 631 const allowReviewTitle = this.reviewSettingsData?.data?.setting?.review_settings.reviews.allow_review_titles 632 this.storeFrontValidation = { 633 isValidReviewTitle: false, 634 isValidReviewFeedback: false, 635 isValidReviewerName: false, 636 isValidReviewerEmail: false, 637 isNotRobot: false, 638 reviewSubmitFailed: false, 639 isAcceptConsent: false 640 } 641 642 if (this.reviewSettingsData?.data?.setting.review_settings?.reviews?.recaptcha?.enabled) { 643 const res = await this.googleRecaptchaVerify() 644 this.storeFrontValidation.isNotRobot = res.result; 645 isValid = !res.result 646 } 647 if (this.reviewSettingsData?.data?.setting.review_settings?.reviews?.show_consent_checkbox?.enabled && !this.newReview.consent) { 648 this.storeFrontValidation.isAcceptConsent = true; 649 isValid = false;
650 } 651 652 if (this.isRvxUserLoggedIn) { 653 if (allowReviewTitle && !this.newReview.title) { 654 this.storeFrontValidation.isValidReviewTitle = true; 655 isValid = false; 656 } 657 if (!this.newReview.feedback) { 658 this.storeFrontValidation.isValidReviewFeedback = true; 659 isValid = false; 660 } 661 } else { 662 if (allowReviewTitle && !this.newReview.title) { 663 this.storeFrontValidation.isValidReviewTitle = true; 664 665 isValid = false; 666 } 667 if (!this.newReview.feedback) { 668 this.storeFrontValidation.isValidReviewFeedback = true; 669 isValid = false; 670 } 671 672 if (!this.newReview.reviewer_name) { 673 this.storeFrontValidation.isValidReviewerName = true; 674 isValid = false; 675 } 676 if (!this.newReview.reviewer_email) { 677 this.storeFrontValidation.isValidReviewerEmail = true; 678 isValid = false; 679 } 680 } 681 682 return isValid 683 }, 684 async reviewSubmitHandler() { 685 const result = await this.reviewFormValidation() 686 console.log('validate result ===========', result) 687 const userIP = await this.fetchUserIPAddress() 688 if (!result) return 689 this.isReviewSubmitting = true 690 const newCriterias = this.multiCriteriaRatingsToObject(this.multiCriteriaRatings) 691 const updatedReviewPayload = { 692 feedback: this.newReview.feedback, 693 reviewer_name: this.isRvxUserLoggedIn ? this.rvxAttributes.userInfo?.name : this.newReview.reviewer_name, 694 reviewer_email: this.isRvxUserLoggedIn ? this.rvxAttributes.userInfo?.email : this.newReview.reviewer_email, 695 user_id: this.isRvxUserLoggedIn ? this.rvxAttributes.userInfo?.id : 0, 696 criterias: newCriterias, 697 rating: this.newReview.rating, 698 is_anonymous: this.newReview.is_anonymous, 699 wp_post_id: this.reviewAggregationData?.data?.product?.wp_id, 700 ip: userIP ?? '0.0.0.0' 701 } 702 if (this.reviewSettingsData?.data?.setting?.review_settings.reviews.allow_recommendations) { 703 updatedReviewPayload.is_recommended = this.newReview.is_recommended; 704 } 705 706 if (this.reviewSettingsData?.data?.setting?.review_settings.reviews.allow_review_titles) { 707 updatedReviewPayload.title = this.newReview.title; 708 } 709 710 if (this.reviewSettingsData?.data?.setting?.review_settings.reviews.photo_reviews_allowed && this.attachmentFiles.length) { 711 updatedReviewPayload.attachments = this.attachmentFiles; 712 } 713 714 const payload = this.generateFormData({ objectData: updatedReviewPayload }) 715 // payload.forEach((value, key) => { 716 // if (value instanceof File) { 717 // console.log( 718 // `${key}: [File] Name: ${value.name}, Size: ${value.size}, Type: ${value.type}` 719 // ); 720 // } else { 721 // console.log(`${key}: ${value}`); 722 // } 723 // }); 724 try { 725 const data = await fetch(`${this.rvxAttributes.baseRestUrl}/reviews`, { 726 method: 'post', 727 body: payload, 728 }) 729 const res = await data.json() 730 // console.log('res =====', res.code) 731 // if(res.code) 732 this.notifyReviewAdded() 733 734 this.newReview = { 735 rating: 5, 736 reviewer_name: this.isRvxUserLoggedIn ? this.rvxAttributes.userInfo?.name : '', 737 reviewer_email: this.isRvxUserLoggedIn ? this.rvxAttributes.userInfo?.email : '', 738 is_anonymous: false, 739 consent: false, 740 title: '', 741 feedback: '', 742 is_recommended: 'true' 743 } 744 745 this.showReviewSuccessModal = true 746 document.getElementById('rvx-storefront-widget').scrollIntoView({ behavior: 'smooth' }); 747 if (this.reviewSettingsData?.data?.setting?.review_settings?.reviews?.auto_approve_reviews) { 748 await this.fetchReviews({ productId: this.rvxAttributes?.product?.id }); 749 } 750 } catch (error) { 751 console.log('error ======', error); 752 } finally { 753 this.isReviewSubmitting = false 754 } 755 }, 756 notifyReviewAdded() { 757 this.$dispatch('notify-review-added', { message: 'Success' }); 758 }, 759 generateQueryParams(params) { 760 const queryParams = new URLSearchParams(); 761 for (const key in params) { 762 if (params.hasOwnProperty(key)) { 763 let value = params[key]; 764 // Handle array values by appending multiple times with the same key 765 if (Array.isArray(value)) { 766 value.forEach((item) => queryParams.append(key, item)); 767 } else if (value !== null && value !== undefined) { 768 // Only append non-null and non-undefined values 769 queryParams.append(key, value); 770 } 771 } 772 } 773 return queryParams.toString(); 774 }, 775 isObject(value) { 776 return ( 777 typeof value === 'object' && 778 value !== null && 779 !Array.isArray(value) && 780 !(value instanceof File) 781 ); 782 }, 783 avatarComponent({ src = '', alt = 'Default Name' }) { 784 return { 785 hasError: false, 786 src: src, 787 alt: alt, 788 showImage() { 789 return this.src && !this.hasError; 790 }, 791 onError() { 792 this.hasError = true; 793 } 794 }; 795 }, 796 copyClipboardComponent() { 797 return { 798 copySuccess: false, 799 copyClipboard(input) { 800 navigator.clipboard.writeText(input) 801 .then(() => { 802 this.copySuccess = true; 803 setTimeout(() => this.copySuccess = false, 1000); 804 }) 805 .catch(err => { 806 console.error('Failed to copy: ', err); 807 }); 808 } 809 }; 810 }, 811 reviewHelpInfoComponent() { 812 return { 813 async likeDislikeHandler({ preference, uid, review }) { 814 if (!this.isRvxUserLoggedIn) { 815 this.errorToastMessage = 'Please login first'; 816 this.showErrorToastMessage = true 817 setTimeout(() => this.showErrorToastMessage = false, 3000); 818 return; 819 } 820 821 // Save original state for possible rollback 822 const originalLikes = review.likes; 823 const originalDislikes = review.dislikes; 824 const originalPreference = review.preference ? { ...review.preference } : null; 825 826 const prevPreference = review.preference?.preference; 827 828 // Optimistic update 829 if (prevPreference === preference) { 830 // Toggle off 831 if (preference === 1) review.likes--; 832 if (preference === 2) review.dislikes--; 833 review.preference = null; 834 } else { 835 // Change preference 836 if (prevPreference === 1) review.likes--; 837 if (prevPreference === 2) review.dislikes--; 838 839 if (preference === 1) review.likes++; 840 if (preference === 2) review.dislikes++; 841 842 review.preference = { preference }; 843 } 844 845 const payload = { 846 preference, 847 }; 848 try { 849 const res = await fetch(`${this.rvxAttributes.baseRestUrl}/reviews/${uid}/preference`, { 850 method: 'POST', 851 headers: { 852 'Content-Type': 'application/json', 853 }, 854 body: JSON.stringify(payload) 855 }); 856 857 if (!res.ok) { 858 throw new Error('API request failed'); 859 } 860 } catch (error) { 861 console.log('error =======', error); 862 // Rollback on error 863 review.likes = originalLikes; 864 review.dislikes = originalDislikes; 865 review.preference = originalPreference; 866 867 this.errorToastMessage = 'Something went wrong. Please try again later.'; 868 this.showErrorToastMessage = true; 869 setTimeout(() => this.showErrorToastMessage = false, 3000); 870 } 871 } 872 } 873 }, 874 generateFormData({ objectData, fileKey }) { 875 const formData = new FormData(); 876 const appendFormData = (key, value) => { 877 if (value instanceof File && fileKey) { 878 formData.append(fileKey, value); 879 } else if (value instanceof File) { 880 formData.append(key, value); 881 } else if (this.isObject(value)) { 882 for (const subKey in value) { 883 if (Object.prototype.hasOwnProperty.call(value, subKey)) { 884 appendFormData(`${key}[${subKey}]`, value[subKey]); 885 } 886 } 887 } else if (Array.isArray(value)) { 888 value.forEach((item, index) => { 889 if (item instanceof File) { 890 const fileArrayKey = fileKey 891 ? `${fileKey}[${index}]` 892 : `${key}[${index}]`; 893 formData.append(fileArrayKey, item); 894 } else if (this.isObject(item)) { 895 for (const subKey in item) { 896 if (Object.prototype.hasOwnProperty.call(item, subKey)) { 897 appendFormData(`${key}[${index}][${subKey}]`, item[subKey]); 898 } 899 } 900 } else { 901 formData.append(`${key}[${index}]`, item); 902 } 903 }); 904 } else { 905 formData.append(key, value); 906 } 907 }; 908 909 for (const key in objectData) { 910 if (Object.prototype.hasOwnProperty.call(objectData, key)) { 911 const value = objectData[key]; 912 appendFormData(key, value); 913 } 914 } 915 916 return formData; 917 }, 918 919 async initialize(data) { 920 const parseAttData = JSON.parse(data.data) 921 const parseFormLabels = JSON.parse(data.formLevelData) 922 const concatValue = { 923 ...parseAttData, 924 formLevelData: { 925 ...parseFormLabels 926 } 927 } 928 this.rvxAttributesDataSetHandler(concatValue) 929 try { 930 await this.fetchReviewsSettings(); 931 if (this.rvxAttributes?.product?.id) { 932 await this.fetchReviewsAggregation({ productId: this.rvxAttributes?.product?.id }); 933 await this.fetchReviews({ productId: this.rvxAttributes?.product?.id }); 934 } 935 } catch (error) { 936 console.error('Error during initialization:', error); 937 } 938 }, 939 940 async initializeReviewsListShortcode(data) { 941 const parseAttData = JSON.parse(data.data) 942 const parseFormLabels = JSON.parse(data.formLevelData) 943 const parseAttributes = JSON.parse(data.attributes) 944 const concatValue = { 945 ...parseAttData, 946 formLevelData: { 947 ...parseFormLabels 948 } 949 } 950 this.rvxAttributesDataSetHandler(concatValue) 951 try { 952 await this.fetchReviewsSettings(); 953 if (this.rvxAttributes?.product?.id && (parseAttributes?.graph == 'on' || parseAttributes?.form == 'on')) { 954 await this.fetchReviewsAggregation({ productId: this.rvxAttributes?.product?.id }); 955 } 956 if (this.rvxAttributes?.product?.id && parseAttributes?.list == 'on') { 957 await this.fetchReviewsListShortcode({ productId: this.rvxAttributes?.product?.id }); 958 } 959 } catch (error) { 960 console.error('Error during initialization:', error); 961 } 962 }, 963 964 async initializeMyAccountReviewForm(data) { 965 // const parseData = JSON.parse(data.data) 966 // console.log('init 2') 967 const parseAttData = JSON.parse(data.data) 968 const parseFormLabels = JSON.parse(data?.formLevelData) 969 // console.log('parseAttData', parseAttData) 970 // console.log('parseFormLabels', parseFormLabels) 971 const concatValue = { 972 ...parseAttData, 973 formLevelData: { 974 ...parseFormLabels 975 } 976 } 977 // console.log('concatValue', concatValue) 978 this.rvxAttributesDataSetHandler(concatValue) 979 // this.rvxAttributesDataSetHandler(parseData) 980 try { 981 await this.fetchReviewsSettings(); 982 } catch (error) { 983 console.error('Error during initialization:', error); 984 } 985 }, 986 async initializeMyAccountReviewFormOnProductChange(productId) { 987 try { 988 // console.log('init 3') 989 await this.fetchReviewsAggregation({ productId: productId }); 990 } catch (error) { 991 console.error('Error during initialization:', error); 992 } 993 }, 994 async initializeReviewGraphShortCodes(data) { 995 const parseData = JSON.parse(data.data) 996 this.rvxAttributesDataSetHandler(parseData) 997 // console.log('init 4') 998 try { 999 await this.fetchReviewsSettings(); 1000 await this.fetchReviewsAggregation({ productId: parseData.product.id }); 1001 } catch (error) { 1002 console.error('Error during initialization:', error); 1003 } 1004 }, 1005 1006 // ////////////////////////// 1007 // async initializeReviewListShortCodes(data) { 1008 // const parseData = JSON.parse(data.data) 1009 // this.rvxAttributesDataSetHandler(parseData) 1010 // try { 1011 // // console.log('init 5') 1012 // await this.fetchReviewsSettings(); 1013 // await this.fetchReviewListShortCodes(parseData.ids); 1014 // } catch (error) { 1015 // console.error('Error during initialization:', error); 1016 // } 1017 // }, 1018 // /////////////////////////// 1019 1020 async initializeAllReviewListShortCodes(data) { 1021 const parseData = JSON.parse(data.data) 1022 this.storeFrontAllReviewParams = parseData.params 1023 this.rvxAttributesDataSetHandler(parseData) 1024 try { 1025 await this.fetchReviewsSettings(); 1026 await this.fetchAllReviewListShortCodes(parseData); 1027 } catch (error) { 1028 console.error('
1028Error during initialization:', error); 1029 } 1030 }, 1031 async initializeReviewWithReviewIdsShortCodes(data) { 1032 const parseData = JSON.parse(data.data) 1033 this.rvxAttributesDataSetHandler(parseData) 1034 try { 1035 // console.log('init 6') 1036 await this.fetchReviewsSettings(); 1037 await this.fetchReviewListWithIdsShortCodes(parseData.ids); 1038 } catch (error) { 1039 console.error('Error during initialization:', error); 1040 } 1041 }, 1042 async initializeReviewStatsShortCodes(data) { 1043 const parseData = JSON.parse(data.data) 1044 this.rvxAttributesDataSetHandler(parseData) 1045 try { 1046 // console.log('init 7') 1047 await this.fetchReviewsSettings(); 1048 await this.fetchReviewsAggregation({ productId: parseData.product.id }); 1049 } catch (error) { 1050 console.error('Error during initialization:', error); 1051 } 1052 }, 1053 async initializeReviewSummaryShortCodes(data) { 1054 const parseData = JSON.parse(data.data) 1055 this.rvxAttributesDataSetHandler(parseData) 1056 try { 1057 // console.log('init 8') 1058 await this.fetchReviewsSettings(); 1059 await this.fetchReviewsAggregation({ productId: parseData.product.id }); 1060 } catch (error) { 1061 console.error('Error during initialization:', error); 1062 } 1063 }, 1064 } 1065}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.