import React, { CSSProperties, useEffect, useState } from 'react'; // Plotno Library Imports import { observer } from 'mobx-react-lite'; import { SectionTab } from 'polotno/side-panel'; import type { StoreType } from 'polotno/model/store'; import type { TemplatesSection } from 'polotno/side-panel'; // Hooks import { useDispatch, useSelector } from 'react-redux'; import { AppDispatch, RootState } from '../../../redux/store'; // Actions import { failure, success } from '../../../redux/actions/snackbarActions'; import { SET_ROS_OFFER_PERCENTAGE } from '../../../redux/actions/action-types'; // Utils import { MESSAGES } from '../../../utils/message'; import { copyToClipboard, getEnv, getIsSandbox, getPublicApiKey } from '../../../utils/helper'; // Components import Input from '../../GenericUIBlocks/Input'; // MUI Components import GeneralTootip from '../../GenericUIBlocks/GeneralTooltip'; import Typography from '../../GenericUIBlocks/Typography'; import Button from '../../../components/GenericUIBlocks/Button'; // Dummy Image for GSV import { DEMO_PO_GENERATOR_URL, DEMO_S3_URL, GOOGLE_STREET_VIEW_IMAGE_URL, PROD_PO_GENERATOR_URL, PROD_S3_URL, STAGE_PO_GENERATOR_URL, STAGE_S3_URL, } from '../../../utils/constants'; // Icons //@ts-ignore import CustomAddOnIcon from '../../../assets/images/templates/custom-add-on-icon'; import ContentCopyIcon from '../../../assets/images/templates/content-copy-icon'; import InfoIcon from '../../../assets/images/templates/info-icon'; import GsvIcon from '../../../assets/images/templates/gsv-icon'; import EpoIcon from '../../../assets/images/templates/epo-icon'; import './styles.scss'; type SideSection = typeof TemplatesSection; type CustomAddOnsSectionProps = { store: StoreType; onClick: () => void; allowedAddOns?: any; propertyOfferCost?: number; customPropertyOfferCost?: number; gsvCost?: number; }; const iconButtonStyles: CSSProperties = { backgroundColor: 'transparent', position: 'absolute', top: "10px", right: "10px", height: "auto" }; // define the new custom section const CustomAddOns: SideSection = { name: 'CustomAddOns', Tab: observer( (props: { store: StoreType; active: boolean; onClick: () => void }) => ( ) ) as SideSection['Tab'], // we need observer to update component automatically on any store changes Panel: observer(({ store, allowedAddOns, propertyOfferCost, gsvCost, customPropertyOfferCost }: CustomAddOnsSectionProps) => { const [customRosValue, setCustomRosValue] = useState(''); const currentTemplate = useSelector( (state: RootState) => state.templates.template ) as Record; const currentOfferPercentage = useSelector( (state: RootState) => state.templates.offerPercentage ) as string; const dispatch: AppDispatch = useDispatch(); const googleStreetViewSrc: string = (getEnv() === 'local' || getEnv() === 'staging' ? STAGE_S3_URL : getIsSandbox() ? DEMO_S3_URL : PROD_S3_URL) + GOOGLE_STREET_VIEW_IMAGE_URL; const propertyOfferGeneratorURL: string = (getEnv() === 'local' || getEnv() === 'staging' ? STAGE_PO_GENERATOR_URL : getIsSandbox() ? DEMO_PO_GENERATOR_URL : PROD_PO_GENERATOR_URL) + `?apiKey=${getPublicApiKey()}`; const PropertyOfferfieldValue = '{{ROS.PROPERTY_OFFER}}'; const handleAddElementOnScreen = ( event: Event, value: string, type: string ) => { event.preventDefault(); const currentPage = store.activePage.toJSON(); if (type === 'gsv') { if ( currentPage?.children?.length && currentPage.children.find( (item: any) => item.id === `gsv-image_${store.activePage.id}` ) ) { dispatch(failure(MESSAGES.TEMPLATE.GSV_RESTRICT_ONE_PER_PAGE)); return; } store.activePage?.addElement({ id: `gsv-image_${store.activePage.id}`, type: 'image', src: googleStreetViewSrc, width: 287, height: 188, contentEditable: false, keepRatio: true, opacity: 1, custom: { elementType: value, }, }); } else if (type === 'rpo') { const randomizedId = Math.random().toString(36).substring(2, 7); store.activePage.addElement({ id: `ros_${randomizedId}`, type: 'text', x: 100, y: 100, text: value, width: 175, contentEditable: false, }); } else if (type === 'custom_rpo') { if (!customRosValue) { percentageRequired(); return; } if (!validCustomRosRange()) return false; dispatch({ type: SET_ROS_OFFER_PERCENTAGE, payload: customRosValue }); const randomizedId = Math.random().toString(36).substring(2, 7); store.activePage.addElement({ id: `ros_${randomizedId}`, type: 'text', x: 100, y: 100, text: value, width: 175, contentEditable: false, custom: { ros_custom_value: customRosValue } }); } }; const percentageRequired = () => dispatch(failure(`Please enter the offer percentage`)); const validCustomRosRange = () => { if(+customRosValue < 1 || +customRosValue > 100) { dispatch(failure(`Please enter an offer percentage between 1 and 100`)); return false; } return true; } const copyPropertyOfferField = (e: React.MouseEvent) => { e.stopPropagation(); copyToClipboard(PropertyOfferfieldValue); dispatch({ type: SET_ROS_OFFER_PERCENTAGE, payload: customRosValue }); dispatch(success(`ROS Property Offer Copied`)); }; useEffect(() => { if (!allowedAddOns?.includes('custom_property_offer')) return; if (currentOfferPercentage || currentOfferPercentage === "") { setCustomRosValue(currentOfferPercentage); } else if (currentTemplate?.meta?.rosOfferPercentage) { setCustomRosValue(currentTemplate.meta.rosOfferPercentage); dispatch({ type: SET_ROS_OFFER_PERCENTAGE, payload: currentTemplate.meta.rosOfferPercentage }); } }, [allowedAddOns, currentOfferPercentage, currentTemplate?.meta?.rosOfferPercentage]); return (
{MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.TITLE}{' '}
{(!allowedAddOns || allowedAddOns?.includes('gsv')) && (
handleAddElementOnScreen(event, 'GOOGLE_STREET_VIEW', 'gsv') } > {MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.GSV.TITLE} {gsvCost && typeof gsvCost === 'number' ? '$' + gsvCost + MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.GSV.CUSTOM_PRICE : MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.GSV.DESCRIPTION}
)} {allowedAddOns?.includes('property_offer') && (
handleAddElementOnScreen(event, PropertyOfferfieldValue, 'rpo') } > {MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.TITLE} {MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.DESCRIPTION} {propertyOfferCost && typeof propertyOfferCost === 'number' ? '$' + propertyOfferCost + MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.CUSTOM_PRICE : MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.PRICE}
)} {allowedAddOns?.includes('custom_property_offer') && (
handleAddElementOnScreen( event, PropertyOfferfieldValue, 'custom_rpo' ) } > {customPropertyOfferCost && typeof customPropertyOfferCost === 'number' ? `Add an offer (+$${customPropertyOfferCost} per mail piece)` : MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.CUSTOM.TITLE} {MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.CUSTOM.DESCRIPTION} {customPropertyOfferCost && typeof customPropertyOfferCost === 'number' ? `$${customPropertyOfferCost} per mail piece` : MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.PROPERTY_OFFER.CUSTOM.CUSTOM_PRICE}
e.stopPropagation()} style={{ width: '18rem', marginBottom: '15px' }} > {allowedAddOns?.includes('custom_property_offer') && ( { const val = e.target.value; if (val === "") { setCustomRosValue(""); dispatch({ type: SET_ROS_OFFER_PERCENTAGE, payload: "" }); return; } const num = Number(val); if (!isNaN(num) && num >= 1 && num <= 100) { setCustomRosValue(val); dispatch({ type: SET_ROS_OFFER_PERCENTAGE, payload: val }); } else { dispatch(failure("Please enter a number between 1 and 100")); } }} /> )}
)}
{!allowedAddOns || allowedAddOns?.length === 0 && {MESSAGES.TEMPLATE.CUSTOM_ADD_ONS.NO_RESULT}}
); }) as unknown as SideSection['Panel'], }; export default CustomAddOns;