{"version":3,"sources":["webpack:///./app/javascript/components/modal.js","webpack:///./app/javascript/components/spinner.js","webpack:///./app/javascript/designer/file-uploader.js","webpack:///./app/javascript/designer/icons.js","webpack:///./app/javascript/designer/save-to-s3.js"],"names":["sizes","md","lg","xl","ModalContext","createContext","portalId","Modal","children","enabled","onClose","size","focusOnProps","useState","isRendered","setIsRendered","useEffect","portalRef","useRef","Math","random","toString","substr","onClickOutside","onEscapeKey","classes","classnames","Provider","value","current","className","hidden","style","zIndex","id","ref","Hidable","rest","cx","Spinner","label","LoadingContainer","isLoading","LoadingImage","src","loaded","setLoaded","img","Image","onload","FileUploader","actionOptions","accept","container","useContext","apikey","library","add","faAlignLeft","faBold","faCopy","faCrop","faCaretDown","faGripLines","faCircle","faExpand","faEye","faImage","faItalic","faLayerGroup","faMinus","faArrowLeft","faPlus","faKerning","faSave","faPalette","faQuestion","faTintSlash","faSpinner","faTrash","faAlignCenter","faAlignRight","faBringForward","faSendBackward","faFillDrip","faDownload","faCheck","faBooks","fasRedo","fasUndo","faBan","faTimes","faUpload","faRedo","faUndo","faText","fasFillDrip","faFont","faChevronUp","faEclipse","faChevronRight","faChevronDown","faRectanglePortrait","bucket","assetHost","extensions","s3","S3","accessKeyId","secretAccessKey","upload","params","Promise","resolve","reject","err","data","uploadDesign","Body","ContentType","preview","filename","uuid","filepath","Bucket","Key","ACL","Tagging","assetUrl","then","uploadDesignFromDataUrl","dataUrl","contentType","blob","dataURLToBlob"],"mappings":"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","file":"js/3-22f670fd19b9bca90369.chunk.js","sourcesContent":["import React, { createContext, useEffect, useRef, useState } from \"react\"\nimport { FocusOn } from \"react-focus-on\"\nimport classnames from \"classnames\"\n\nconst sizes = {\n  md: \"max-w-screen-md\",\n  lg: \"max-w-screen-lg\",\n  xl: \"max-w-screen-xl\"\n}\n\nexport const ModalContext = createContext({ portalId: null })\n\nconst Modal = ({\n  children,\n  enabled = true,\n  onClose,\n  size = \"lg\",\n  focusOnProps = {}\n}) => {\n  /*\n   * Inside the focus trap for this modal we render a div with a ref on it\n   * that is passed down via context to children that want to render things\n   * at the \"root\" (to escape z-index, etc) but need to be within the focus trap\n   * (so body won't work). We want this ref to be defined by the time the children\n   * render so we want until the modal is rendered before rendering it's children.\n   */\n  const [isRendered, setIsRendered] = useState(false)\n\n  useEffect(() => {\n    setIsRendered(true)\n  }, [])\n\n  // Pass a reference to a DOM node at the bottom of the modal focus\n  // area. Useful for escaping z-index but staying within the focus area.\n  const portalRef = useRef()\n  const portalId = useRef(\n    \"modal_\" +\n      Math.random()\n        .toString(36)\n        .substr(2, 9)\n  )\n\n  focusOnProps = { ...focusOnProps, enabled }\n\n  if (onClose) {\n    focusOnProps = {\n      ...focusOnProps,\n      onClickOutside: onClose,\n      onEscapeKey: onClose\n    }\n  }\n\n  const classes = classnames(\n    \"z-10 shadow-lg w-full h-full\",\n    \"sm:container sm:mx-auto sm:w-11/12 sm:h-auto\",\n    sizes[size]\n  )\n\n  return (\n    <ModalContext.Provider value={{ portalId: portalId.current, portalRef }}>\n      <div\n        className={classnames(\n          \"modal z-50 fixed inset-0 flex items-center justify-center\",\n          { hidden: !enabled }\n        )}\n        style={{ zIndex: 1025 }}\n      >\n        <div className=\"absolute inset-0 h-full w-full bg-gray-700 opacity-75\"></div>\n        <div className={classes} style={{ zIndex: 999 }}>\n          <FocusOn {...focusOnProps} className=\"h-full w-full\">\n            <div\n              className={classnames(\n                \"rm-modal-content h-full w-full overflow-y-auto bg-white sm:rounded\"\n              )}\n            >\n              {isRendered && children}\n            </div>\n            <div id={portalId.current} ref={portalRef} />\n          </FocusOn>\n        </div>\n      </div>\n    </ModalContext.Provider>\n  )\n}\n\nexport default Modal\n","import React, { useEffect, useState } from \"react\"\nimport cx from \"classnames\"\n\nexport const Hidable = ({ className, hidden, ...rest }) => (\n  <div className={cx(hidden && \"hidden\", className)} {...rest} />\n)\n\nexport const Spinner = ({ label }) => (\n  <div className=\"h-full w-full flex flex-col items-center justify-center p-5\">\n    <div className=\"ball-grid-container\">\n      <div className=\"ball-grid-pulse bg-gray-500\">\n        <div />\n        <div />\n        <div />\n        <div />\n        <div />\n        <div />\n        <div />\n        <div />\n        <div />\n      </div>\n    </div>\n    {label && (\n      <div className=\"mt-5 opacity-50 text-lg font-bold text-center\">\n        {label}\n      </div>\n    )}\n  </div>\n)\n\nexport const LoadingContainer = ({ isLoading, label, size, ...rest }) => (\n  <>\n    {isLoading && <Spinner size={size} label={label} />}\n    <Hidable hidden={isLoading} {...rest} />\n  </>\n)\n\nexport const LoadingImage = ({ label = \"Loading image\", src, ...rest }) => {\n  const [loaded, setLoaded] = useState(false)\n\n  useEffect(() => {\n    if (src) {\n      setLoaded(false)\n\n      const img = new Image()\n      img.onload = () => setLoaded(true)\n      img.src = src\n    }\n  }, [src])\n\n  return loaded ? <img src={src} {...rest} /> : <Spinner label={label} />\n}\n","import React, { useContext } from \"react\"\nimport ReactFilestack from \"filestack-react\"\nimport { ModalContext } from \"../components/modal\"\n\n/*\n * The FileStack component needs to be mounted inside\n * our designer modal focus area. It can't be rendered\n * here as it needs to escape its ancestors z-index to\n * be placed over the entire designer.\n */\nconst FileUploader = ({ actionOptions = {}, ...rest }) => {\n  const { portalId } = useContext(ModalContext)\n\n  actionOptions = {\n    accept: \"image/*\",\n    container: portalId,\n    ...actionOptions\n  }\n\n  return (\n    <ReactFilestack\n      apikey=\"AQzBP0d3jTvi9yidzdGcdz\"\n      actionOptions={actionOptions}\n      {...rest}\n    />\n  )\n}\n\nexport default FileUploader\n","import { library } from \"@fortawesome/fontawesome-svg-core\"\n\nimport {\n  faAlignCenter,\n  faAlignLeft,\n  faAlignRight,\n  faArrowLeft,\n  faBan,\n  faBold,\n  faCheck,\n  faChevronDown,\n  faChevronRight,\n  faChevronUp,\n  faCopy,\n  faCrop,\n  faDownload,\n  faEclipse,\n  faExpand,\n  faEye,\n  faFillDrip,\n  faFont,\n  faGripLines,\n  faImage,\n  faItalic,\n  faKerning,\n  faLayerGroup,\n  faMinus,\n  faPalette,\n  faPlus,\n  faQuestion,\n  faRedo,\n  faSave,\n  faSpinner,\n  faText,\n  faTimes,\n  faTintSlash,\n  faTrash,\n  faUndo,\n  faUpload\n} from \"@fortawesome/pro-regular-svg-icons\"\n\nimport {\n  faBooks,\n  faBringForward,\n  faCaretDown,\n  faCircle,\n  faRectanglePortrait,\n  faSendBackward,\n  faFillDrip as fasFillDrip,\n  faRedo as fasRedo,\n  faUndo as fasUndo\n} from \"@fortawesome/pro-solid-svg-icons\"\n\nlibrary.add(\n  faAlignLeft,\n  faBold,\n  faCopy,\n  faCrop,\n  faCaretDown,\n  faGripLines,\n  faCircle,\n  faExpand,\n  faEye,\n  faImage,\n  faItalic,\n  faLayerGroup,\n  faMinus,\n  faArrowLeft,\n  faPlus,\n  faKerning,\n  faSave,\n  faPalette,\n  faQuestion,\n  faTintSlash,\n  faSpinner,\n  faTrash,\n  faAlignCenter,\n  faAlignRight,\n  faBringForward,\n  faSendBackward,\n  faFillDrip,\n  faDownload,\n  faCheck,\n  faBooks,\n  fasRedo,\n  fasUndo,\n  faBan,\n  faTimes,\n  faUpload,\n  faRedo,\n  faUndo,\n  faText,\n  fasFillDrip,\n  faFont,\n  faChevronUp,\n  faEclipse,\n  faChevronRight,\n  faChevronDown,\n  faRectanglePortrait\n)\n","import { dataURLToBlob } from \"blob-util\"\nimport { v4 as uuid } from \"uuid\"\nimport S3 from \"aws-sdk/clients/s3\"\n\n/*\n * This bucket has public read access with CORS enabled.\n * It also has a lifecycle policy that deletes objects\n * taggaed with tmp=true after 1 day.\n */\nconst bucket = \"personalwine.designs\"\n\n/*\n * We have a Cloudfront distribution in front of the S3\n * bucket configured to respect CORS headers and pointed\n * to be a CNAME.\n */\nconst assetHost = \"https://designs.personalwine.com\"\n\n/*\n * Map content types to file extensions.\n */\nconst extensions = {\n  \"image/jpg\": \"jpg\",\n  \"image/png\": \"png\"\n}\n\n/*\n * PersonalWineWeb IAM user w/ access to PutObject and PutObjectACL on our S3 buckets.\n */\nconst s3 = new S3({\n  accessKeyId: \"AKIAY2YKAVY67USO5DVE\",\n  secretAccessKey: \"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\"\n})\n\n// Wrap upload with a Promise\nconst upload = params =>\n  new Promise((resolve, reject) => {\n    s3.upload(params, (err, data) => {\n      if (err) {\n        reject(err)\n      } else {\n        resolve(data)\n      }\n    })\n  })\n\n/*\n * Our S3 bucket is configured so objects tagged with tmp=true will\n * be deleted after one day. We use this ONLY for temporary images\n * we want to store to generate previews. Obviously this tag shouldn't\n * be used for the final save.\n */\nexport const uploadDesign = (Body, ContentType, preview = false) => {\n  const filename = `${uuid()}.${extensions[ContentType]}`\n  const filepath = (preview ? \"preview/\" : \"final/\") + filename\n  const params = {\n    Body,\n    ContentType,\n    Bucket: bucket,\n    Key: filepath,\n    ACL: \"public-read\"\n  }\n\n  if (preview) {\n    params.Tagging = \"tmp=true\"\n  }\n\n  // Get the CDN path to the image\n  const assetUrl = `${assetHost}/${filepath}`\n\n  return upload(params).then(() => assetUrl)\n}\n\nexport const uploadDesignFromDataUrl = (\n  dataUrl,\n  contentType,\n  preview = false\n) => {\n  const blob = dataURLToBlob(dataUrl)\n  return uploadDesign(blob, contentType, preview)\n}\n"],"sourceRoot":""}