233 lines
7.3 KiB
TypeScript
233 lines
7.3 KiB
TypeScript
import { useState } from 'react'
|
|
import { toast } from '@redwoodjs/web/toast'
|
|
import Popover from '@material-ui/core/Popover'
|
|
import Svg from 'src/components/Svg/Svg'
|
|
import Button from 'src/components/Button/Button'
|
|
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
|
|
import { canvasToBlob, blobTo64 } from 'src/helpers/canvasToBlob'
|
|
import { useUpdateProject } from 'src/helpers/hooks/useUpdateProject'
|
|
import {
|
|
useUpdateSocialCard,
|
|
makeSocialPublicId,
|
|
} from 'src/helpers/hooks/useUpdateSocialCard'
|
|
import {
|
|
uploadToCloudinary,
|
|
serverVerifiedImageUpload,
|
|
} from 'src/helpers/cloudinary'
|
|
import SocialCardCell from 'src/components/SocialCardCell/SocialCardCell'
|
|
import { toJpeg } from 'html-to-image'
|
|
import { useAuth } from '@redwoodjs/auth'
|
|
|
|
const anchorOrigin = {
|
|
vertical: 'bottom',
|
|
horizontal: 'center',
|
|
}
|
|
const transformOrigin = {
|
|
vertical: 'top',
|
|
horizontal: 'center',
|
|
}
|
|
|
|
const CaptureButton = ({
|
|
canEdit,
|
|
TheButton,
|
|
shouldUpdateImage,
|
|
projectTitle,
|
|
userName,
|
|
}) => {
|
|
const [captureState, setCaptureState] = useState<any>({})
|
|
const [anchorEl, setAnchorEl] = useState(null)
|
|
const [whichPopup, setWhichPopup] = useState(null)
|
|
const { state, project } = useIdeContext()
|
|
const ref = React.useRef<HTMLDivElement>(null)
|
|
const { updateProject } = useUpdateProject({
|
|
onCompleted: () => toast.success('Image updated'),
|
|
})
|
|
const { updateSocialCard } = useUpdateSocialCard({})
|
|
const { getToken } = useAuth()
|
|
|
|
const getSocialBlob = async (): Promise<string> => {
|
|
const tokenPromise = getToken()
|
|
const blob = await toJpeg(ref.current, { cacheBust: true, quality: 0.75 })
|
|
const token = await tokenPromise
|
|
const { publicId } = await serverVerifiedImageUpload(
|
|
blob,
|
|
project?.id,
|
|
token,
|
|
makeSocialPublicId(userName, projectTitle)
|
|
)
|
|
return publicId
|
|
}
|
|
|
|
const onCapture = async () => {
|
|
const threeInstance = state.threeInstance
|
|
const isOpenScadImage = state?.objectData?.type === 'png'
|
|
let imgBlob
|
|
let image64
|
|
if (!isOpenScadImage) {
|
|
imgBlob = canvasToBlob(threeInstance, { width: 500, height: 375 })
|
|
image64 = blobTo64(
|
|
await canvasToBlob(threeInstance, { width: 500, height: 522 })
|
|
)
|
|
} else {
|
|
imgBlob = state.objectData.data
|
|
image64 = blobTo64(state.objectData.data)
|
|
}
|
|
const config = {
|
|
image: await imgBlob,
|
|
currImage: project?.mainImage,
|
|
imageObjectURL: window.URL.createObjectURL(await imgBlob),
|
|
callback: uploadAndUpdateImage,
|
|
cloudinaryImgURL: '',
|
|
updated: false,
|
|
image64: await image64,
|
|
}
|
|
setCaptureState(config)
|
|
|
|
async function uploadAndUpdateImage() {
|
|
const [cloudinaryImgURL, socialCloudinaryURL] = await Promise.all([
|
|
uploadToCloudinary(config.image),
|
|
getSocialBlob(),
|
|
])
|
|
|
|
updateSocialCard({
|
|
variables: {
|
|
projectId: project?.id,
|
|
url: socialCloudinaryURL,
|
|
},
|
|
})
|
|
|
|
// Save the screenshot as the mainImage
|
|
updateProject({
|
|
variables: {
|
|
id: project?.id,
|
|
input: {
|
|
mainImage: cloudinaryImgURL.public_id,
|
|
},
|
|
},
|
|
})
|
|
|
|
return cloudinaryImgURL
|
|
}
|
|
|
|
// if there isn't a screenshot saved yet, just go ahead and save right away
|
|
if (shouldUpdateImage) {
|
|
config.cloudinaryImgURL = (await uploadAndUpdateImage()).public_id
|
|
config.updated = true
|
|
setCaptureState(config)
|
|
}
|
|
}
|
|
|
|
const handleDownload = (url) => {
|
|
const aTag = document.createElement('a')
|
|
document.body.appendChild(aTag)
|
|
aTag.href = url
|
|
aTag.style.display = 'none'
|
|
aTag.download = `${project?.title}-${new Date().toISOString()}.jpg`
|
|
aTag.click()
|
|
document.body.removeChild(aTag)
|
|
}
|
|
|
|
const handleClick = ({ event, whichPopup }) => {
|
|
setAnchorEl(event.currentTarget)
|
|
setWhichPopup(whichPopup)
|
|
}
|
|
|
|
const handleClose = () => {
|
|
setAnchorEl(null)
|
|
setWhichPopup(null)
|
|
}
|
|
return (
|
|
<div>
|
|
{canEdit && (
|
|
<div>
|
|
<TheButton
|
|
onClick={async (event) => {
|
|
handleClick({ event, whichPopup: 'capture' })
|
|
onCapture()
|
|
}}
|
|
/>
|
|
<Popover
|
|
id={'capture-popover'}
|
|
open={whichPopup === 'capture'}
|
|
anchorEl={anchorEl}
|
|
onClose={handleClose}
|
|
anchorOrigin={anchorOrigin}
|
|
transformOrigin={transformOrigin}
|
|
className="material-ui-overrides transform translate-y-4"
|
|
>
|
|
<div className="text-sm p-2 text-gray-500">
|
|
{!captureState ? (
|
|
'Loading...'
|
|
) : (
|
|
<div className="grid grid-cols-2">
|
|
<div
|
|
className="rounded m-auto"
|
|
style={{ width: 'fit-content', overflow: 'hidden' }}
|
|
>
|
|
<img src={captureState.imageObjectURL} className="w-32" />
|
|
</div>
|
|
<div className="p-2 text-indigo-800">
|
|
{captureState.currImage && !captureState.updated ? (
|
|
<button
|
|
className="flex justify-center mb-4"
|
|
onClick={async () => {
|
|
const cloudinaryImg = await captureState.callback()
|
|
setCaptureState({
|
|
...captureState,
|
|
currImage: cloudinaryImg.public_id,
|
|
updated: true,
|
|
})
|
|
}}
|
|
>
|
|
<Svg
|
|
name="refresh"
|
|
className="mr-2 w-4 text-indigo-600"
|
|
/>{' '}
|
|
Update Project Image
|
|
</button>
|
|
) : (
|
|
<div className="flex justify-center mb-4">
|
|
<Svg
|
|
name="checkmark"
|
|
className="mr-2 w-6 text-indigo-600"
|
|
/>{' '}
|
|
Part Image Updated
|
|
</div>
|
|
)}
|
|
<Button
|
|
iconName="save"
|
|
className="shadow-md hover:shadow-lg border-indigo-600 border-2 border-opacity-0 hover:border-opacity-100 bg-indigo-200 text-indigo-100 text-opacity-100 bg-opacity-80"
|
|
shouldAnimateHover
|
|
onClick={() =>
|
|
handleDownload(captureState.imageObjectURL)
|
|
}
|
|
>
|
|
Download
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
<div className="rounded-lg shadow-md mt-4 overflow-hidden">
|
|
<div
|
|
className="transform scale-50 origin-top-left"
|
|
style={{ width: '600px', height: '315px' }}
|
|
>
|
|
<div style={{ width: '1200px', height: '630px' }} ref={ref}>
|
|
<SocialCardCell
|
|
userName={userName}
|
|
projectTitle={projectTitle}
|
|
image64={captureState.image64}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Popover>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default CaptureButton
|