{"version":3,"file":"static/js/cc259fc5135008f19d70.bundle.js","mappings":"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","sources":["webpack://nss-commerce/./src/actions/review.action.ts?ebf0","webpack://nss-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\nconst getCaseInsensitive = (obj: any, key: string): any => {\r\n if (obj === undefined) {\r\n return undefined;\r\n }\r\n\r\n const lowerKey = key.toLowerCase();\r\n for (const prop in obj) {\r\n if (prop.toLowerCase() === lowerKey) {\r\n return obj[prop];\r\n }\r\n }\r\n return undefined;\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 = getCaseInsensitive(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 = getCaseInsensitive(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","getCaseInsensitive","obj","key","lowerKey","toLowerCase","prop","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","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","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","_getCaseInsensitive$R","_getCaseInsensitive","_json$Includes","Includes","Products","ReviewStatistics","AverageOverallRating","TotalResults","BazaarVoiceReviewOverview","_props$productId2","_props$productName","isLoaded","setIsLoaded","customerReviews","setCustomerReviews","showReviews","setShowReviews","isModalOpen","setIsModalOpen","processApiData","_getCaseInsensitive$R2","_getCaseInsensitive2","_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":""}