{"version":3,"file":"static/js/e306df93ac8c18889104.bundle.js","mappings":"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","sources":["webpack://illumina-commerce/./src/actions/review.action.ts?ebf0","webpack://illumina-commerce/./src/components/review.view.tsx?4a18"],"sourcesContent":["import { DataServiceQuery } from '@msdyn365-commerce/retail-proxy';\r\nimport { IActionContext } from '@msdyn365-commerce/core';\r\nimport { Buffer } from 'buffer';\r\n\r\nexport interface IBazaarVoiceResult {\r\n Title?: string;\r\n Rating: number;\r\n ReviewText?: string;\r\n SubmissionTime?: string;\r\n UserNickname?: string;\r\n}\r\n\r\nexport interface IBazaarVoiceReviewsJson {\r\n TotalResults?: number;\r\n Results?: IBazaarVoiceResult[];\r\n Includes?: {\r\n Products?: {\r\n [key: string]: {\r\n Name: string;\r\n ReviewStatistics?: {\r\n AverageOverallRating: number;\r\n };\r\n };\r\n };\r\n };\r\n}\r\n\r\nexport interface ISecondaryRating {\r\n label: string;\r\n value?: number;\r\n}\r\n\r\nexport interface IBazaarVoiceReviewSubmission {\r\n rating: number;\r\n email?: string;\r\n nickname?: string;\r\n title?: string;\r\n review?: string;\r\n recommendedString?: '' | 'yes' | 'no';\r\n agreedToTermsAndConditions?: boolean;\r\n secondaryRating: ISecondaryRating[];\r\n photos: File[];\r\n photoCaptions: string[];\r\n fingerprint?: string;\r\n errors: IBazaarVoiceFieldError[];\r\n}\r\n\r\nexport interface IBazaarVoiceFieldError {\r\n Code: string;\r\n Field: string;\r\n Message: string;\r\n}\r\n\r\nexport interface IBazaarVoiceField {\r\n Id: string;\r\n MinLength: number;\r\n MaxLength: number;\r\n}\r\n\r\nexport interface IBazaarVoiceReviewSubmissionResponse {\r\n Data: {\r\n Fields: {\r\n [key: string]: IBazaarVoiceField;\r\n };\r\n FieldsOrder: string[];\r\n };\r\n HasErrors: any;\r\n Form: any;\r\n FormErrors: {\r\n FieldErrors?: {\r\n [key: string]: IBazaarVoiceFieldError;\r\n };\r\n FieldErrorsOrder?: string[];\r\n };\r\n TypicalHoursToPost: number | null;\r\n SubmissionId: string | null;\r\n Review: any;\r\n Locale: string;\r\n Errors: any[];\r\n}\r\n\r\nexport async function getRatings(\r\n context: IActionContext,\r\n productId: string,\r\n pageSize: number,\r\n offset: number = 0\r\n): Promise {\r\n const query = new DataServiceQuery();\r\n const request = query.createDataServiceRequestForOperation(\r\n 'GetBZReviews',\r\n false,\r\n '',\r\n 'false',\r\n { bypassCache: 'get', returnEntity: '' },\r\n { ProductId: productId, PageSize: pageSize, Offset: offset }\r\n );\r\n\r\n const data = await request.execute(context);\r\n const json = JSON.parse(data);\r\n\r\n return json;\r\n}\r\n\r\nexport async function getReviewMetadata(context: IActionContext, productId: string): Promise {\r\n const query = new DataServiceQuery();\r\n const request = query.createDataServiceRequestForOperation(\r\n 'GetBZMetadata',\r\n false,\r\n '',\r\n 'false',\r\n { bypassCache: 'get', returnEntity: '' },\r\n { ProductId: productId }\r\n );\r\n\r\n const data = await request.execute(context);\r\n const json = JSON.parse(data);\r\n\r\n return json;\r\n}\r\n\r\nexport async function submitReview(\r\n context: IActionContext,\r\n productId: string,\r\n submission: IBazaarVoiceReviewSubmission\r\n): Promise {\r\n const photos: any[] = [];\r\n for (let i = 0; i < submission.photos.length; i++) {\r\n const file: File = submission.photos[i];\r\n const caption: string = submission.photoCaptions[i];\r\n const arrayBuffer: ArrayBuffer = await file.arrayBuffer();\r\n const buffer: Buffer = Buffer.from(arrayBuffer);\r\n const base64data: string = buffer.toString('base64');\r\n\r\n photos.push({\r\n Name: file.name,\r\n Data: base64data,\r\n Caption: caption\r\n });\r\n }\r\n\r\n const query = new DataServiceQuery();\r\n const request = query.createDataServiceRequestForOperation(\r\n 'PostBZReview',\r\n true,\r\n '',\r\n 'false',\r\n { bypassCache: 'get', returnEntity: '' },\r\n {\r\n request: {\r\n ProductId: productId,\r\n Rating: submission.rating,\r\n Email: submission.email,\r\n Nickname: submission.nickname,\r\n Title: submission.title,\r\n Review: submission.review,\r\n Recommended: submission.recommendedString === undefined ? undefined : submission.recommendedString === 'yes',\r\n SecondaryRatings: submission.secondaryRating\r\n .filter((rating: ISecondaryRating) => rating.value)\r\n .map((rating: ISecondaryRating) => {\r\n return { Label: `rating_${rating.label}`, Rating: rating.value };\r\n }),\r\n Photos: photos,\r\n Fingerprint: submission.fingerprint,\r\n AgreedToTermsAndConditions: submission.agreedToTermsAndConditions\r\n }\r\n }\r\n );\r\n const data = await request.execute(context);\r\n const json = JSON.parse(data);\r\n\r\n return json;\r\n}\r\n","import React, { ChangeEvent } from 'react';\r\nimport {\r\n IBazaarVoiceReviewsJson,\r\n IBazaarVoiceResult,\r\n getRatings,\r\n getReviewMetadata,\r\n IBazaarVoiceReviewSubmission,\r\n submitReview,\r\n ISecondaryRating,\r\n IBazaarVoiceFieldError,\r\n IBazaarVoiceField\r\n} from '../actions/review.action';\r\nimport { Modal, ModalBody, ModalFooter, ModalHeader, Waiting } from '@msdyn365-commerce-modules/utilities';\r\nimport FingerprintJS from '@fingerprintjs/fingerprintjs';\r\nimport { IActionContext } from '@msdyn365-commerce/core';\r\n\r\nconst getRatingsPageSize = 10;\r\n\r\n/*\r\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTERFACES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n */\r\ninterface ICustomerReviewProps {\r\n title: string;\r\n rating: number;\r\n description: string;\r\n timestamp: string;\r\n nickname: string;\r\n}\r\n\r\ninterface IStarProps {\r\n stars: number;\r\n level?: number;\r\n}\r\n\r\ninterface IAverageRatingProps {\r\n stars?: number;\r\n reviewCount?: number;\r\n}\r\n\r\ninterface IPagingControlProps {\r\n offset: number;\r\n totalReviews: number;\r\n setOffset: (value: number) => void;\r\n}\r\n\r\ninterface IBazaarVoiceStarsProps {\r\n context: IActionContext;\r\n productId?: string;\r\n align?: 'left' | 'center' | 'right' | 'fit';\r\n size?: '' | 'small';\r\n withCount?: boolean;\r\n rating?: number;\r\n}\r\n\r\ninterface ILeaveReviewModalProps {\r\n context: IActionContext;\r\n isOpen: boolean;\r\n toggle: () => void;\r\n productId: string;\r\n productName?: string;\r\n}\r\n\r\ninterface IBazaarVoiceReviewOverviewProps {\r\n context: IActionContext;\r\n productId?: string;\r\n productName?: string;\r\n}\r\n\r\nconst formatDate = (date: Date | string) => {\r\n date = new Date(date);\r\n const month = String(date.getMonth() + 1).padStart(2, '0');\r\n const day = String(date.getDate()).padStart(2, '0');\r\n const year = date.getFullYear();\r\n const hour = date.getHours() % 12 || 12;\r\n const minute = String(date.getMinutes()).padStart(2, '0');\r\n const ampm = date.getHours() < 12 ? 'am' : 'pm';\r\n\r\n const dateString: string = `${month}/${day}/${year} ${hour}:${minute} ${ampm}`;\r\n return dateString;\r\n};\r\n\r\n/*\r\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRIVATE COMPONENT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n */\r\n\r\n/*\r\n * Renders a single star based on the rating and star level\r\n *\r\n * Resulting star is either filled, left-partially-filled, or empty\r\n */\r\nconst Star = (props: IStarProps) => {\r\n const stars: number = props.stars ?? 0;\r\n const level: number = props.level ?? 0;\r\n\r\n // round to the nearest tenth\r\n const tenths: number = Math.round((stars + 1 - level) * 10);\r\n // full star if more than 10/10 of star\r\n const isFullStar: boolean = tenths >= 10;\r\n // empty star if less than 0/10 of star\r\n const isEmptyStar: boolean = tenths <= 0;\r\n\r\n let starClass = 'nss-review__star';\r\n if (isFullStar) {\r\n starClass += ' nss-review__full-star';\r\n } else if (isEmptyStar) {\r\n starClass += ' nss-review__empty-star';\r\n } else {\r\n starClass += ` nss-review__${tenths}-tenth-star`;\r\n }\r\n\r\n return
;\r\n};\r\n\r\n/*\r\n * Renders 5 stars for a five star rating, partial stars allowed\r\n */\r\nexport const StarRating = (props: IStarProps) => {\r\n const stars: number = props.stars ?? 0;\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\n/*\r\n * Renders the five star rating with the review count\r\n */\r\nexport const AverageRating = (props: IAverageRatingProps) => {\r\n const stars: number = props.stars ?? 0;\r\n const reviewCount: number = props.reviewCount ?? 0;\r\n const roundedStars: number = Math.round(stars * 10) / 10;\r\n\r\n return (\r\n
\r\n
\r\n \r\n
\r\n
from {reviewCount} reviews
\r\n
\r\n );\r\n};\r\n\r\n/*\r\n * Renders a single customer review for the review overview\r\n */\r\nconst CustomerReview = (props: ICustomerReviewProps) => {\r\n const { title, rating, description, timestamp, nickname } = props;\r\n\r\n return (\r\n <>\r\n
\r\n
\r\n
{title}
\r\n
\r\n \r\n
\r\n
\r\n
{description}
\r\n
\r\n
{timestamp}
\r\n
{nickname}
\r\n
\r\n
\r\n \r\n );\r\n};\r\n\r\nconst PagingControl = (props: IPagingControlProps) => {\r\n const offset: number = props.offset;\r\n const totalReviews: number = props.totalReviews;\r\n const setOffset: (value: number) => void = (value: number) => {\r\n const minOffset = 0;\r\n const maxOffset = (totalPages - 1) * getRatingsPageSize;\r\n\r\n // limit the offset to the desired range\r\n value = value < minOffset ? minOffset : value;\r\n value = value > maxOffset ? maxOffset : value;\r\n\r\n // call the passed function\r\n props.setOffset(value);\r\n };\r\n\r\n const index: number = offset / getRatingsPageSize;\r\n const totalPages: number = Math.ceil(totalReviews / getRatingsPageSize);\r\n const pageRange: number[] = [];\r\n\r\n // start two before index\r\n let startIndex: number = index - 2;\r\n\r\n // bounds check start index\r\n startIndex = startIndex < 0 ? 0 : startIndex;\r\n\r\n // end four after start\r\n let endIndex: number = startIndex + 4;\r\n\r\n // bounds check end index\r\n endIndex = endIndex >= totalPages ? totalPages - 1 : endIndex;\r\n\r\n // special case where we are on one of the last few pages\r\n startIndex = startIndex > endIndex - 4 ? endIndex - 4 : startIndex;\r\n startIndex = startIndex < 0 ? 0 : startIndex;\r\n\r\n // fill page range\r\n for (let i = startIndex; i <= endIndex; i++) {\r\n pageRange.push(i);\r\n }\r\n\r\n return (\r\n
    \r\n
  • setOffset(0)} title='First Page'>\r\n <<\r\n
  • \r\n
  • setOffset(offset - getRatingsPageSize)} title='Previous Page'>\r\n <\r\n
  • \r\n {pageRange.map((value: number) => (\r\n setOffset(value * getRatingsPageSize)}\r\n >\r\n {value + 1}\r\n \r\n ))}\r\n
  • setOffset(offset + getRatingsPageSize)} title='Next Page'>\r\n >\r\n
  • \r\n
  • setOffset((totalPages - 1) * getRatingsPageSize)} title='Final Page'>\r\n >>\r\n
  • \r\n
\r\n );\r\n};\r\n\r\nconst FormRating = (props: any) => {\r\n const rating: number = props.rating;\r\n const setRating: (rating: number) => void = props.setRating;\r\n\r\n return (\r\n
\r\n
setRating(1)}>\r\n \r\n
\r\n
setRating(2)}>\r\n \r\n
\r\n
setRating(3)}>\r\n \r\n
\r\n
setRating(4)}>\r\n \r\n
\r\n
setRating(5)}>\r\n \r\n
\r\n
\r\n );\r\n};\r\n\r\nconst FieldError = (props: any) => {\r\n const fieldError: IBazaarVoiceFieldError | undefined = props.fieldError;\r\n\r\n return fieldError ?
{fieldError.Message}
: null;\r\n};\r\n\r\nconst getCharCountText = (textEntry: string | undefined, fieldMetadata: IBazaarVoiceField | undefined) => {\r\n if (fieldMetadata === undefined) {\r\n return '';\r\n }\r\n\r\n textEntry = textEntry ?? '';\r\n const length: number = textEntry.length;\r\n const minLength: number = fieldMetadata.MinLength;\r\n const maxLength: number = fieldMetadata.MaxLength;\r\n\r\n const charsToMin: number = minLength - length;\r\n const charsLeft: number = maxLength - length;\r\n\r\n if (length === 0 && minLength !== 0) {\r\n return `Enter at least ${minLength} characters`;\r\n }\r\n\r\n if (charsToMin > 0) {\r\n return `Enter ${charsToMin} more characters`;\r\n }\r\n\r\n if (charsLeft >= 0) {\r\n return `${charsLeft} characters remaining`;\r\n }\r\n\r\n return `Character limit exceeded by ${-charsLeft}`;\r\n};\r\n\r\nconst LeaveReviewModal = (props: ILeaveReviewModalProps) => {\r\n const context: IActionContext = props.context;\r\n const isOpen: boolean = props.isOpen;\r\n const toggle: () => void = props.toggle;\r\n const productId: string = props.productId;\r\n const productName: string = props.productName || '';\r\n\r\n const [formData, setFormData] = React.useState({\r\n rating: 0,\r\n secondaryRating: [],\r\n photos: [],\r\n photoCaptions: [],\r\n errors: []\r\n });\r\n const [isLoading, setIsLoading] = React.useState(false);\r\n const [fieldMetadata, setFieldMetadata] = React.useState<{ [key: string]: IBazaarVoiceField }>({});\r\n\r\n const clearForm = () => {\r\n setFormData({\r\n rating: 0,\r\n secondaryRating: [],\r\n photos: [],\r\n photoCaptions: [],\r\n errors: []\r\n });\r\n };\r\n\r\n React.useEffect(() => {\r\n clearForm();\r\n setIsLoading(true);\r\n getReviewMetadata(context, productId)\r\n .then(metadata => {\r\n const labels: ISecondaryRating[] = metadata.Data.FieldsOrder.filter(key => key.includes('rating_')).map(key => {\r\n return {\r\n label: key.replace('rating_', '')\r\n };\r\n });\r\n formData.secondaryRating = labels;\r\n const fields: { [key: string]: IBazaarVoiceField } = metadata.Data.Fields;\r\n\r\n setFormData({ ...formData });\r\n setFieldMetadata(fields);\r\n setIsLoading(false);\r\n })\r\n .catch(error => {\r\n console.log(error);\r\n setIsLoading(false);\r\n });\r\n }, [productId]);\r\n\r\n const setAgreedToTermsAndConditions = () => {\r\n formData.agreedToTermsAndConditions = !formData.agreedToTermsAndConditions;\r\n removeError('agreedtotermsandconditions');\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setRating = (rating: number) => {\r\n formData.rating = rating;\r\n removeError('rating');\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setEmail = (event: ChangeEvent) => {\r\n formData.email = event.target.value;\r\n formData.email = truncateText(formData.email, 'useremail');\r\n removeError('useremail');\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setNickname = (event: ChangeEvent) => {\r\n formData.nickname = event.target.value;\r\n formData.nickname = truncateText(formData.nickname, 'usernickname');\r\n removeError('usernickname');\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setTitle = (event: ChangeEvent) => {\r\n formData.title = event.target.value;\r\n formData.title = truncateText(formData.title, 'title');\r\n removeError('title');\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setReview = (event: ChangeEvent) => {\r\n formData.review = event.target.value;\r\n formData.review = truncateText(formData.review, 'reviewtext');\r\n removeError('reviewtext');\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setRecommended = (event: ChangeEvent) => {\r\n if (event.target.value === '' || event.target.value === 'yes' || event.target.value === 'no') {\r\n formData.recommendedString = event.target.value;\r\n setFormData({ ...formData });\r\n }\r\n };\r\n\r\n const setSecondaryRating = (i: number, rating: number) => {\r\n formData.secondaryRating[i].value = rating;\r\n setFormData({ ...formData });\r\n };\r\n\r\n const addPhoto = () => {\r\n removeError('photo');\r\n const photoInput: HTMLInputElement = document.createElement('input');\r\n photoInput.style.visibility = 'hidden';\r\n photoInput.setAttribute('type', 'file');\r\n photoInput.setAttribute('multiple', 'multiple');\r\n photoInput.setAttribute('accept', 'image/*');\r\n photoInput.onchange = () => {\r\n if (photoInput.files) {\r\n for (let i = 0; i < photoInput.files.length; i++) {\r\n const photo: File = photoInput.files[i];\r\n let validUpload: boolean = true;\r\n\r\n // check for error in file type\r\n if (!photo.type.startsWith('image')) {\r\n const message: string = `Cannot upload photo ${photo.name} because it is an unsupported file type.`;\r\n formData.errors.push({\r\n Code: 'ERROR_FORM_PHOTO_FILE_TYPE',\r\n Field: 'photo',\r\n Message: message\r\n });\r\n validUpload = false;\r\n }\r\n\r\n // check for file size limit\r\n if (photo.size > 10 * 1048576) {\r\n const message: string = `Cannot upload photo ${photo.name} exceeds maximum upload size of 10MB`;\r\n formData.errors.push({\r\n Code: 'ERROR_FORM_MAX_PHOTO_SIZE_EXCEEDED',\r\n Field: 'photo',\r\n Message: message\r\n });\r\n validUpload = false;\r\n }\r\n\r\n // check for upload count limit\r\n if (formData.photos.length >= 6) {\r\n formData.errors.push({\r\n Code: 'ERROR_FORM_MAX_PHOTO_COUNT_EXCEEDED',\r\n Field: 'photo',\r\n Message: 'Cannot upload any more photos, maximum number of photos (6) reached.'\r\n });\r\n validUpload = false;\r\n }\r\n\r\n // add to list if all checks pass\r\n if (validUpload) {\r\n formData.photos.push(photo);\r\n }\r\n }\r\n\r\n setFormData({ ...formData });\r\n }\r\n };\r\n document.body.appendChild(photoInput);\r\n photoInput.click();\r\n document.body.removeChild(photoInput);\r\n };\r\n\r\n const removePhoto = (index: number) => {\r\n removeError('photo');\r\n formData.photos = formData.photos.filter((file, i) => index !== i);\r\n formData.photoCaptions = formData.photoCaptions.filter((caption, i) => index !== i);\r\n setFormData({ ...formData });\r\n };\r\n\r\n const setPhotoCaption = (event: ChangeEvent, index: number) => {\r\n removeError('photo');\r\n formData.photoCaptions[index] = event.target.value;\r\n setFormData({ ...formData });\r\n };\r\n\r\n const submitForm = async () => {\r\n setIsLoading(true);\r\n\r\n try {\r\n const fp = await FingerprintJS.load();\r\n const { visitorId } = await fp.get();\r\n formData.fingerprint = visitorId;\r\n formData.errors = getClientErrors();\r\n\r\n if (formData.errors.length > 0) {\r\n // errors determined exist client side\r\n alert('Form contains errors, please correct errors and try again.');\r\n console.error(formData.errors);\r\n setFormData({ ...formData });\r\n setIsLoading(false);\r\n return;\r\n }\r\n\r\n // send request to proxy\r\n const response = await submitReview(context, productId, formData);\r\n\r\n if ('message' in response) {\r\n // error response\r\n const message: string = typeof response['message'] === 'string' ? response['message'] : '';\r\n\r\n formData.errors.push({\r\n Code: 'INTERNAL_SERVER_ERROR',\r\n Field: 'general',\r\n Message: message\r\n });\r\n alert('Form contains errors, please correct errors and try again.');\r\n console.error(formData.errors);\r\n setFormData({ ...formData });\r\n setIsLoading(false);\r\n return;\r\n }\r\n\r\n // check for server errors\r\n for (const error of response.Errors) {\r\n formData.errors.push({ ...error, Field: 'general' });\r\n }\r\n if (response.FormErrors.FieldErrors && response.FormErrors.FieldErrorsOrder) {\r\n for (const field of response.FormErrors.FieldErrorsOrder) {\r\n formData.errors.push(response.FormErrors.FieldErrors[field]);\r\n }\r\n }\r\n\r\n if (formData.errors.length > 0) {\r\n // errors determined exist server side\r\n alert('Form contains errors, please correct errors and try again.');\r\n console.error(formData.errors);\r\n setFormData({ ...formData });\r\n setIsLoading(false);\r\n return;\r\n }\r\n\r\n if (response.SubmissionId) {\r\n // form was sumbitted without errors\r\n const message: string = `Review submitted! Please allow ${response.TypicalHoursToPost} hours for your review to be posted.`;\r\n alert(message);\r\n clearForm();\r\n toggle();\r\n } else {\r\n // something else happened here, print some debugging\r\n console.error('Uncaught error submitting review', formData, response);\r\n alert('Something went wrong, Please try again later.');\r\n }\r\n } catch (exception) {\r\n // something else happened here, print some debugging\r\n console.error('Uncaught error submitting review', formData, exception);\r\n alert('Something went wrong, Please try again later.');\r\n }\r\n\r\n setIsLoading(false);\r\n };\r\n\r\n const getClientErrors = (): IBazaarVoiceFieldError[] => {\r\n const errors: IBazaarVoiceFieldError[] = [];\r\n\r\n if (!formData.agreedToTermsAndConditions) {\r\n errors.push({\r\n Code: 'ERROR_FORM_REQUIRES_TRUE',\r\n Field: 'agreedtotermsandconditions',\r\n Message: 'You must agree to terms and conditions to submit a review.'\r\n });\r\n }\r\n\r\n if (!formData.rating) {\r\n errors.push({\r\n Code: 'ERROR_FORM_REQUIRES_TRUE',\r\n Field: 'rating',\r\n Message: 'Rating is required.'\r\n });\r\n }\r\n\r\n if (!formData.email) {\r\n errors.push({\r\n Code: 'ERROR_FORM_REQUIRES_TRUE',\r\n Field: 'useremail',\r\n Message: 'Email is required.'\r\n });\r\n }\r\n\r\n if (!formData.nickname) {\r\n errors.push({\r\n Code: 'ERROR_FORM_REQUIRES_TRUE',\r\n Field: 'usernickname',\r\n Message: 'Nickname is required.'\r\n });\r\n }\r\n\r\n if (!formData.title) {\r\n errors.push({\r\n Code: 'ERROR_FORM_REQUIRES_TRUE',\r\n Field: 'title',\r\n Message: 'Title is required.'\r\n });\r\n }\r\n\r\n if (!formData.review) {\r\n errors.push({\r\n Code: 'ERROR_FORM_REQUIRES_TRUE',\r\n Field: 'reviewtext',\r\n Message: 'Review Text is required.'\r\n });\r\n }\r\n\r\n return errors;\r\n };\r\n\r\n const getError = (field: string): IBazaarVoiceFieldError | undefined => {\r\n return formData.errors.find(value => value.Field.toLowerCase().includes(field.toLowerCase()));\r\n };\r\n\r\n const removeError = (field: string): void => {\r\n formData.errors = formData.errors.filter(\r\n (value: IBazaarVoiceFieldError) => !value.Field.toLowerCase().includes(field.toLowerCase())\r\n );\r\n };\r\n\r\n const truncateText = (text: string, field: string): string => {\r\n if (text.length > fieldMetadata[field]?.MaxLength) {\r\n text = text.substring(0, fieldMetadata[field].MaxLength);\r\n }\r\n\r\n return text;\r\n };\r\n\r\n return (\r\n \r\n \r\n Write Review\r\n \r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n {getCharCountText(formData.email, fieldMetadata['useremail'])}\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n {getCharCountText(formData.nickname, fieldMetadata['usernickname'])}\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n {getCharCountText(formData.title, fieldMetadata['title'])}\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n {getCharCountText(formData.review, fieldMetadata['reviewtext'])}\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {formData.secondaryRating.map((secondaryRating, index) => (\r\n
\r\n \r\n setSecondaryRating(index, rating)} />\r\n
\r\n ))}\r\n
\r\n \r\n
\r\n {formData.photos.map((photo: File, index: number) => (\r\n
\r\n \r\n
\r\n ) => setPhotoCaption(event, index)}\r\n value={formData.photoCaptions[index]}\r\n >\r\n \r\n
\r\n
\r\n ))}\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n View Terms and Conditions\r\n \r\n \r\n I\r\n agree to the terms and conditions\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n );\r\n};\r\n\r\nconst Loading = (props: any) => {\r\n const isLoading = props.isLoading;\r\n\r\n if (!isLoading) {\r\n return null;\r\n }\r\n\r\n return (\r\n
\r\n
\r\n \r\n Loading...\r\n
\r\n
\r\n );\r\n};\r\n\r\n/*\r\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXPORTED COMPONENT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n */\r\nexport const BazaarVoiceStars = (props: IBazaarVoiceStarsProps) => {\r\n const context: IActionContext = props.context;\r\n const productId: string = props.productId ?? '';\r\n const align: string = props.align ?? 'center';\r\n const size: string = props.size ?? '';\r\n const withCount: boolean = props.withCount ?? false;\r\n const rating: number = props.rating ?? 0;\r\n\r\n const [isLoading, setIsLoading] = React.useState(true);\r\n const [error, setError] = React.useState(null);\r\n const [stars, setStars] = React.useState(rating);\r\n const [reviewCount, setReviewCount] = React.useState();\r\n\r\n React.useEffect(() => {\r\n getRatings(context, productId, getRatingsPageSize)\r\n .then((json: IBazaarVoiceReviewsJson) => {\r\n const stars: number = json?.Includes?.Products?.[productId]?.ReviewStatistics?.AverageOverallRating ?? 0;\r\n const reviewCount: number | undefined = json?.TotalResults;\r\n\r\n setStars(stars);\r\n setReviewCount(reviewCount);\r\n setIsLoading(false);\r\n setError(null);\r\n })\r\n .catch(error => {\r\n console.error(error);\r\n setIsLoading(false);\r\n setError(error);\r\n });\r\n }, [productId, rating]);\r\n\r\n if (isLoading) {\r\n return
Loading...
;\r\n }\r\n\r\n if (error) {\r\n return
Error loading review data
;\r\n }\r\n\r\n if (withCount) {\r\n if (!reviewCount) {\r\n return (\r\n \r\n );\r\n }\r\n\r\n return ;\r\n }\r\n\r\n if (!reviewCount || !stars) {\r\n return null;\r\n }\r\n\r\n return (\r\n
\r\n
\r\n \r\n
\r\n
\r\n );\r\n};\r\n\r\nexport const BazaarVoiceReviewOverview = (props: IBazaarVoiceReviewOverviewProps) => {\r\n const context: IActionContext = props.context;\r\n const productId: string = props.productId ?? '';\r\n const productName: string = props.productName ?? '';\r\n\r\n const [isLoaded, setIsLoaded] = React.useState(false);\r\n const [error, setError] = React.useState(null);\r\n const [stars, setStars] = React.useState();\r\n const [reviewCount, setReviewCount] = React.useState();\r\n const [customerReviews, setCustomerReviews] = React.useState([]);\r\n const [showReviews, setShowReviews] = React.useState(false);\r\n const [offset, setOffset] = React.useState(0);\r\n const [isModalOpen, setIsModalOpen] = React.useState(false);\r\n\r\n const processApiData = (json: IBazaarVoiceReviewsJson) => {\r\n const stars: number = json?.Includes?.Products?.[productId]?.ReviewStatistics?.AverageOverallRating ?? 0;\r\n const reviewCount: number = json?.TotalResults ?? 0;\r\n const customerReviews: ICustomerReviewProps[] =\r\n json?.Results?.map((result: IBazaarVoiceResult) => {\r\n return {\r\n title: result.Title ?? '',\r\n rating: result.Rating ?? '',\r\n description: result.ReviewText ?? '',\r\n timestamp: result.SubmissionTime ? formatDate(result.SubmissionTime) : '',\r\n nickname: result.UserNickname ?? ''\r\n };\r\n }) ?? [];\r\n\r\n setStars(stars);\r\n setReviewCount(reviewCount);\r\n setCustomerReviews(customerReviews);\r\n setIsLoaded(true);\r\n setError(null);\r\n };\r\n\r\n React.useEffect(() => {\r\n setOffset(0);\r\n getRatings(context, productId, getRatingsPageSize)\r\n .then(processApiData)\r\n .catch(error => {\r\n console.error(error);\r\n setIsLoaded(true);\r\n setError(error);\r\n });\r\n }, [productId]);\r\n\r\n React.useEffect(() => {\r\n getRatings(context, productId, getRatingsPageSize, offset)\r\n .then(processApiData)\r\n .catch(error => {\r\n console.error(error);\r\n setIsLoaded(true);\r\n setError(error);\r\n });\r\n }, [offset]);\r\n\r\n if (!isLoaded) {\r\n return
Loading...
;\r\n }\r\n\r\n if (error) {\r\n return
An error occurred loading review data
;\r\n }\r\n\r\n return (\r\n
\r\n

Customer Reviews

\r\n
\r\n \r\n setIsModalOpen(true)}>\r\n review\r\n \r\n setIsModalOpen(!isModalOpen)}\r\n />\r\n
\r\n \r\n {showReviews && (\r\n <>\r\n
\r\n {customerReviews?.map((review: ICustomerReviewProps, index: number) => (\r\n \r\n ))}\r\n
\r\n
\r\n {customerReviews !== undefined && reviewCount !== undefined && reviewCount > customerReviews.length && (\r\n \r\n )}\r\n
\r\n \r\n )}\r\n
\r\n );\r\n};\r\n"],"names":["async","getRatings","context","productId","pageSize","offset","arguments","length","undefined","query","DataServiceQuery","request","createDataServiceRequestForOperation","bypassCache","returnEntity","ProductId","PageSize","Offset","data","execute","json","JSON","parse","getReviewMetadata","submitReview","submission","photos","i","file","caption","photoCaptions","arrayBuffer","base64data","Buffer","from","toString","push","Name","name","Data","Caption","Rating","rating","Email","email","Nickname","nickname","Title","title","Review","review","Recommended","recommendedString","SecondaryRatings","secondaryRating","filter","value","map","Label","label","Photos","Fingerprint","fingerprint","AgreedToTermsAndConditions","agreedToTermsAndConditions","getRatingsPageSize","formatDate","date","Date","String","getMonth","padStart","getDate","getFullYear","getHours","getMinutes","Star","props","_props$stars","_props$level","stars","level","tenths","Math","round","starClass","React","className","StarRating","_props$stars2","AverageRating","_props$stars3","_props$reviewCount","reviewCount","roundedStars","CustomerReview","description","timestamp","PagingControl","totalReviews","setOffset","maxOffset","totalPages","index","ceil","pageRange","startIndex","endIndex","onClick","key","FormRating","setRating","FieldError","fieldError","Message","getCharCountText","textEntry","fieldMetadata","_textEntry","minLength","MinLength","charsToMin","charsLeft","MaxLength","LeaveReviewModal","isOpen","toggle","productName","formData","setFormData","errors","isLoading","setIsLoading","setFieldMetadata","clearForm","then","metadata","labels","FieldsOrder","includes","replace","fields","Fields","_objectSpread","catch","error","console","log","getClientErrors","Code","Field","getError","field","find","toLowerCase","removeError","truncateText","text","_fieldMetadata$field","substring","Modal","autoFocus","fade","applicationNode","Loading","ModalHeader","ModalBody","onChange","event","target","type","setSecondaryRating","photo","src","URL","createObjectURL","placeholder","setPhotoCaption","removePhoto","addPhoto","photoInput","document","createElement","style","visibility","setAttribute","onchange","files","validUpload","startsWith","message","size","body","appendChild","click","removeChild","href","rel","checked","setAgreedToTermsAndConditions","ModalFooter","fp","FingerprintJS","visitorId","get","alert","response","Errors","FormErrors","FieldErrors","FieldErrorsOrder","SubmissionId","TypicalHoursToPost","exception","Waiting","BazaarVoiceStars","_props$productId","_props$align","_props$size","_props$withCount","_props$rating","align","withCount","setError","setStars","setReviewCount","_json$Includes$Produc","_json$Includes","Includes","Products","ReviewStatistics","AverageOverallRating","TotalResults","BazaarVoiceReviewOverview","_props$productId2","_props$productName","isLoaded","setIsLoaded","customerReviews","setCustomerReviews","showReviews","setShowReviews","isModalOpen","setIsModalOpen","processApiData","_json$Includes$Produc2","_json$Includes2","_json$TotalResults","_json$Results$map","_json$Results","Results","result","_result$Title","_result$Rating","_result$ReviewText","_result$UserNickname","ReviewText","SubmissionTime","UserNickname","Object","assign"],"sourceRoot":""}