{"version":3,"file":"ProfileImage.rypSSCUZ.mjs","names":["useState","useUser","useMemo","updateProfilePicture"],"sources":["https:/framerusercontent.com/modules/y1eqhCpy9kJJrQd8oSH3/4OXW9FbxU8AAvas4pdWT/ProfileImage.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{useState,startTransition,useEffect,useMemo}from\"react\";import{addPropertyControls,ControlType}from\"framer\";import{useUser,updateProfilePicture}from\"https://cdn.jsdelivr.net/npm/@framerauth/sdk@2/dist/framerauth.mjs\";/**\n * What the picker offers, mirrored from the API's `/profile/avatar` route.\n * It is a filter, not a check: the API reads the file's bytes and decides,\n * and its refusal is what the user sees. Change the route and change this.\n */const AVATAR_FILE_ACCEPT=\"image/jpeg,image/png,image/webp\";/**\n * The one refusal the API can never voice. A body over ~4.5MB is dropped at\n * the Vercel edge before the route runs, with no message in the reply — so an\n * oversized file is turned away here, at the API's own 4MB cap, with the\n * sentence the API would have used. Every other refusal is left to the API.\n * Change the route's cap and change this.\n */const MAX_AVATAR_FILE_BYTES=4*1024*1024;const AVATAR_TOO_LARGE=\"Avatar is larger than the 4MB maximum\";/**\n * ProfileImage.tsx\n *\n * @framerDisableUnlink\n *\n * @framerSupportedLayoutWidth fixed\n * @framerSupportedLayoutHeight fixed\n */export default function ProfileImage(props){const{image,borderRadius,iconColor,iconSize,border,backgroundColor,viewOnly,style}=props;const[isHovered,setIsHovered]=useState(false);const[isAnimating,setIsAnimating]=useState(false);const[isUploading,setIsUploading]=useState(false);const[optimisticImageUrl,setOptimisticImageUrl]=useState(null);const{user,setUser}=useUser();const isDisabled=useMemo(()=>{if(!user||viewOnly===true){return true;}return false;},[user,viewOnly]);const defaultImage=\"https://framerauth.b-cdn.net/pictures/ProfilePic.png\";const[currentImageSrc,setCurrentImageSrc]=useState(defaultImage);useEffect(()=>{const newImageSrc=optimisticImageUrl||user?.image||image?.src||defaultImage;setCurrentImageSrc(newImageSrc);},[user,image,defaultImage,optimisticImageUrl]);const handleMouseEnter=()=>{startTransition(()=>setIsHovered(true));};const handleMouseLeave=()=>{startTransition(()=>setIsHovered(false));};const handleClick=()=>{if(isDisabled||isUploading)return;const input=document.createElement(\"input\");input.type=\"file\";input.accept=AVATAR_FILE_ACCEPT;input.onchange=async e=>{const file=e.target.files?.[0];if(file){if(file.size>MAX_AVATAR_FILE_BYTES){alert(AVATAR_TOO_LARGE);return;}setIsUploading(true);setIsAnimating(true);// Create optimistic blob URL for immediate feedback\nconst blobUrl=URL.createObjectURL(file);setOptimisticImageUrl(blobUrl);try{// Create FormData and append the file\nconst formData=new FormData;formData.append(\"file\",file);const response=await updateProfilePicture(formData);if(response.data){// Clean up the blob URL since we have the real URL now\nURL.revokeObjectURL(blobUrl);setOptimisticImageUrl(null);// TODO: We should not set the user in the component the SDK should manage it\nsetUser({...user,image:response.data.url});}else{// The API names its refusal; repeat it, as ActionButton\n// does. No message of our own: the API's is the one\n// that will be translated.\nconsole.error(\"Upload failed:\",response.error);URL.revokeObjectURL(blobUrl);setOptimisticImageUrl(null);alert(response.error?.message??response.error?.statusText);}}catch(error){// The SDK folds failures into `response.error`, so this is\n// only reached by something thrown outside the request.\nconsole.error(\"Upload error:\",error);URL.revokeObjectURL(blobUrl);setOptimisticImageUrl(null);}finally{setIsUploading(false);setTimeout(()=>setIsAnimating(false),150);}}};input.click();};const containerStyle={...style,width:\"100%\",height:\"100%\",borderRadius,backgroundColor,position:\"relative\",overflow:\"hidden\",cursor:isDisabled||isUploading?\"default\":\"pointer\",...border,backgroundImage:`url(${currentImageSrc})`,backgroundSize:\"cover\",backgroundPosition:\"center\",display:\"flex\",alignItems:\"center\",justifyContent:\"center\",opacity:isAnimating?.8:1,filter:isUploading?\"brightness(0.9)\":\"brightness(1)\"};const overlayStyle={position:\"absolute\",top:0,left:0,right:0,bottom:0,backgroundColor:\"rgba(0, 0, 0, 0.5)\",display:\"flex\",alignItems:\"center\",justifyContent:\"center\",opacity:isHovered&&!isDisabled||isUploading?1:0,transition:\"opacity 0.2s ease\",borderRadius};const LoadingSpinner=()=>{const[rotation,setRotation]=useState(0);useEffect(()=>{const startTime=Date.now();const animate=()=>{const elapsed=Date.now()-startTime;setRotation(elapsed/8%360)// Complete rotation every 2.88 seconds\n;requestAnimationFrame(animate);};const animationId=requestAnimationFrame(animate);return()=>cancelAnimationFrame(animationId);},[]);return /*#__PURE__*/_jsxs(\"svg\",{width:iconSize,height:iconSize,viewBox:\"0 0 24 24\",style:{transform:`rotate(${rotation}deg)`},children:[/*#__PURE__*/_jsx(\"circle\",{cx:\"12\",cy:\"12\",r:\"10\",fill:\"none\",stroke:iconColor,strokeWidth:\"2\",opacity:\"0.2\"}),/*#__PURE__*/_jsx(\"circle\",{cx:\"12\",cy:\"12\",r:\"10\",fill:\"none\",stroke:iconColor,strokeWidth:\"2\",strokeDasharray:\"15 85\",strokeLinecap:\"round\",opacity:\"1\"})]});};const UploadIcon=()=>/*#__PURE__*/_jsxs(\"svg\",{width:iconSize,height:iconSize,viewBox:\"0 0 24 24\",fill:\"none\",stroke:iconColor,strokeWidth:\"2\",children:[/*#__PURE__*/_jsx(\"line\",{x1:\"12\",y1:\"5\",x2:\"12\",y2:\"19\"}),/*#__PURE__*/_jsx(\"line\",{x1:\"5\",y1:\"12\",x2:\"19\",y2:\"12\"})]});return /*#__PURE__*/_jsx(\"div\",{style:containerStyle,onMouseEnter:isDisabled||isUploading?undefined:handleMouseEnter,onMouseLeave:isDisabled||isUploading?undefined:handleMouseLeave,onClick:isDisabled?undefined:handleClick,role:isDisabled?\"img\":\"button\",tabIndex:isDisabled?-1:0,\"aria-label\":isDisabled?\"Profile image\":isUploading?\"Uploading...\":\"Upload profile image\",children:/*#__PURE__*/_jsx(\"div\",{style:overlayStyle,children:isUploading?/*#__PURE__*/_jsx(LoadingSpinner,{}):/*#__PURE__*/_jsx(UploadIcon,{})})});}addPropertyControls(ProfileImage,{viewOnly:{type:ControlType.Boolean,title:\"View Only\",defaultValue:false,enabledTitle:\"Yes\",disabledTitle:\"No\"},image:{type:ControlType.ResponsiveImage,title:\"Placeholder\"},borderRadius:{type:ControlType.BorderRadius,title:\"Radius\",defaultValue:\"100px\"},border:{type:ControlType.Border,title:\"Border\",defaultValue:{borderWidth:2,borderStyle:\"solid\",borderColor:\"#EEEEEE\"},optional:true},iconColor:{type:ControlType.Color,title:\"Icon\",defaultValue:\"#FFFFFF\"},iconSize:{type:ControlType.Number,title:\"Icon Size\",defaultValue:24,min:12,max:48,step:2,unit:\"px\"}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"ProfileImage\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerSupportedLayoutHeight\":\"fixed\",\"framerDisableUnlink\":\"*\",\"framerSupportedLayoutWidth\":\"fixed\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./ProfileImage.map"],"mappings":"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"}