From cf53e46805ca64e5d324e7122718128b85ca1a25 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 8 Aug 2024 18:08:23 +0800 Subject: [PATCH] Chore/support pasting images in feedback widget (#28475) * Support pasting images in feedback widget * Remove unnecessary usage of local storage * Revert changes to local storeage --- .../FeedbackDropdown/FeedbackDropdown.tsx | 14 +--- .../FeedbackDropdown/FeedbackWidget.tsx | 67 +++++++++++-------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx index 777ede00cce..86271efb77d 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx @@ -7,16 +7,6 @@ const FeedbackDropdown = () => { const [feedback, setFeedback] = useState('') const [screenshot, setScreenshot] = useState() - function onOpen() { - setIsOpen((isOpen) => !isOpen) - } - - function onClose() { - setFeedback('') - setScreenshot(undefined) - setIsOpen(false) - } - return ( { }} > - setIsOpen(false)} feedback={feedback} setFeedback={setFeedback} screenshot={screenshot} diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx index 55d6ceb7171..3e8b036772c 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx @@ -1,5 +1,5 @@ -import { useParams } from 'common' import { toPng } from 'html-to-image' +import { Camera, Image as ImageIcon, Upload, X } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import { ChangeEvent, useEffect, useRef, useState } from 'react' @@ -10,30 +10,27 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, - IconCamera, - IconImage, - IconUpload, - IconX, Input, } from 'ui' +import { useParams } from 'common' import { useSendFeedbackMutation } from 'data/feedback/feedback-send' import { timeout } from 'lib/helpers' import { convertB64toBlob, uploadAttachment } from './FeedbackDropdown.utils' interface FeedbackWidgetProps { - onClose: () => void feedback: string - setFeedback: (value: string) => void screenshot: string | undefined + onClose: () => void + setFeedback: (value: string) => void setScreenshot: (value: string | undefined) => void } const FeedbackWidget = ({ - onClose, feedback, - setFeedback, screenshot, + onClose, + setFeedback, setScreenshot, }: FeedbackWidgetProps) => { const FEEDBACK_STORAGE_KEY = 'feedback_content' @@ -41,11 +38,11 @@ const FeedbackWidget = ({ const router = useRouter() const { ref, slug } = useParams() - const inputRef = useRef(null) - const uploadButtonRef = useRef() + const uploadButtonRef = useRef(null) const [isSending, setSending] = useState(false) const [isSavingScreenshot, setIsSavingScreenshot] = useState(false) + const { mutate: submitFeedback } = useSendFeedbackMutation({ onSuccess: () => { setFeedback('') @@ -86,14 +83,6 @@ const FeedbackWidget = ({ } }, [screenshot]) - useEffect(() => { - inputRef?.current?.focus() - }, [inputRef]) - - function onFeedbackChange(e: any) { - setFeedback(e.target.value) - } - const clearFeedback = () => { setFeedback('') setScreenshot(undefined) @@ -118,7 +107,7 @@ const FeedbackWidget = ({ localStorage.setItem(SCREENSHOT_STORAGE_KEY, dataUrl) setScreenshot(dataUrl) }) - .catch((error: any) => toast.error('Failed to capture screenshot')) + .catch(() => toast.error('Failed to capture screenshot')) .finally(() => { setIsSavingScreenshot(false) }) @@ -140,6 +129,24 @@ const FeedbackWidget = ({ event.target.value = '' } + const handlePasteEvent = async () => { + // [Joshen] Support pasting images via Cmd / Ctrl + V + const [data] = await navigator.clipboard.read() + + if (screenshot === undefined && data.types[0] === 'image/png') { + const blob = await data.getType('image/png') + const reader = new FileReader() + reader.onload = function (event) { + const dataUrl = event.target?.result + if (typeof dataUrl === 'string') { + setScreenshot(dataUrl) + localStorage.setItem(SCREENSHOT_STORAGE_KEY, dataUrl) + } + } + reader.readAsDataURL(blob) + } + } + const sendFeedback = async () => { if (feedback.length === 0 && screenshot !== undefined) { return toast.error('Please include a message in your feedback.') @@ -171,12 +178,19 @@ const FeedbackWidget = ({ placeholder="Ideas on how to improve this page. Use the Support Form for technical issues." rows={5} value={feedback} - onChange={onFeedbackChange} + onChange={(e) => setFeedback(e.target.value)} + onPaste={handlePasteEvent} />
-
@@ -203,7 +217,7 @@ const FeedbackWidget = ({ setScreenshot(undefined) }} > - +
) : ( @@ -215,7 +229,7 @@ const FeedbackWidget = ({ loading={isSavingScreenshot} className="px-2 py-1.5" > - + @@ -226,7 +240,7 @@ const FeedbackWidget = ({ if (uploadButtonRef.current) (uploadButtonRef.current as any).click() }} > - + Upload screenshot captureScreenshot()} > - + Capture screenshot @@ -242,7 +256,6 @@ const FeedbackWidget = ({ )}