From 1dc1d08ac0ad6420a9aad8749f3ce911fa4e83fa Mon Sep 17 00:00:00 2001 From: vinit717 Date: Wed, 31 Jul 2024 17:04:31 +0530 Subject: [PATCH] chore: undo changes --- __tests__/components/LoginModal.test.tsx | 2 +- __tests__/components/Navbar/Navbar.test.tsx | 4 +- __tests__/components/QRCodeModal.test.tsx | 64 ++++++++++++++ __tests__/pages/app.test.tsx | 2 +- __tests__/pages/dashboard.test.tsx | 2 +- src/components/App/InputSection.tsx | 23 +++-- src/components/App/OutputSection.tsx | 93 +++++++++------------ src/components/LoginModal/index.tsx | 2 +- src/components/Modal/index.tsx | 49 ----------- src/components/QRCodeModal.tsx/index.tsx | 84 +++++++++++++++++++ src/pages/app/index.tsx | 56 +++++-------- 11 files changed, 227 insertions(+), 154 deletions(-) create mode 100644 __tests__/components/QRCodeModal.test.tsx delete mode 100644 src/components/Modal/index.tsx create mode 100644 src/components/QRCodeModal.tsx/index.tsx diff --git a/__tests__/components/LoginModal.test.tsx b/__tests__/components/LoginModal.test.tsx index 7e3360e..e999279 100644 --- a/__tests__/components/LoginModal.test.tsx +++ b/__tests__/components/LoginModal.test.tsx @@ -13,7 +13,7 @@ describe('LoginModal Component', () => { }} /> ); - const closeButton = screen.getByTestId('close-modal'); + const closeButton = screen.getByTestId('close-login-modal'); expect(closeButton).toBeInTheDocument(); }); diff --git a/__tests__/components/Navbar/Navbar.test.tsx b/__tests__/components/Navbar/Navbar.test.tsx index 6b1f5b3..64e418d 100644 --- a/__tests__/components/Navbar/Navbar.test.tsx +++ b/__tests__/components/Navbar/Navbar.test.tsx @@ -94,7 +94,7 @@ describe('Navbar', () => { const originalIsLoggedIn = screen.getByText('Sign In'); fireEvent.click(originalIsLoggedIn); - const closeButton = screen.getByTestId('close-modal'); + const closeButton = screen.getByTestId('close-login-modal'); fireEvent.click(closeButton); const modal = screen.queryByText('Sign to your account'); @@ -130,7 +130,7 @@ describe('Navbar', () => { const originalIsLoggedIn = screen.getByText('Sign In'); fireEvent.click(originalIsLoggedIn); - const closeButton = screen.getByTestId('close-modal'); + const closeButton = screen.getByTestId('close-login-modal'); fireEvent.click(closeButton); expect(mockSetShowLoginModal).toHaveBeenCalled(); diff --git a/__tests__/components/QRCodeModal.test.tsx b/__tests__/components/QRCodeModal.test.tsx new file mode 100644 index 0000000..9ab718e --- /dev/null +++ b/__tests__/components/QRCodeModal.test.tsx @@ -0,0 +1,64 @@ +import { fireEvent, render, screen } from '@testing-library/react'; + +import QRCodeModal from '@/components/QRCodeModal'; + +describe('QRCodeModal Component', () => { + const onClose = jest.fn(); + + test('renders the QRCodeModal component', () => { + render( + { + onClose(); + }} + shortUrl="https://www.rds.com" + /> + ); + const closeButton = screen.getByTestId('close-qrcode-modal'); + expect(closeButton).toBeInTheDocument(); + const downloadButton = screen.getByTestId('download-qr-code'); + expect(downloadButton).toBeInTheDocument(); + const qrcodeCanvas = screen.getByTestId('qrcode'); + expect(qrcodeCanvas).toBeInTheDocument(); + }); + + test('closes the modal when clicking outside the modal', () => { + render( + { + onClose(); + }} + shortUrl="https://www.rds.com" + /> + ); + const modal = screen.getByTestId('qrcode-modal'); + expect(modal).toBeInTheDocument(); + const body = document.querySelector('body'); + fireEvent.mouseDown(body as HTMLElement); + expect(onClose).toHaveBeenCalledTimes(1); + }); + + test('download image by clicking download button', () => { + render( + { + onClose(); + }} + shortUrl="https://www.rds.com" + /> + ); + + const downloadButton = screen.getByTestId('download-qr-code'); + expect(downloadButton).toBeInTheDocument(); + + HTMLCanvasElement.prototype.toDataURL = jest.fn(() => 'data:image/png;base64,abcd1234'); + document.body.appendChild = jest.fn(); + document.body.removeChild = jest.fn(); + + fireEvent.click(downloadButton); + + expect(HTMLCanvasElement.prototype.toDataURL).toHaveBeenCalledWith('image/png'); + expect(document.body.appendChild).toHaveBeenCalled(); + expect(document.body.removeChild).toHaveBeenCalled(); + }); +}); diff --git a/__tests__/pages/app.test.tsx b/__tests__/pages/app.test.tsx index 0026ad2..4b62e5d 100644 --- a/__tests__/pages/app.test.tsx +++ b/__tests__/pages/app.test.tsx @@ -110,7 +110,7 @@ describe('App Component', () => { const generateButton = screen.getByText('Shorten'); fireEvent.change(urlInput, { target: { value: 'https://www.longurl.com' } }); fireEvent.click(generateButton); - const closeButton = await screen.findByTestId('close-modal'); + const closeButton = await screen.findByTestId('close-login-modal'); fireEvent.click(closeButton); const loginModal = screen.queryByText('Log in to generate short links'); expect(loginModal).not.toBeInTheDocument(); diff --git a/__tests__/pages/dashboard.test.tsx b/__tests__/pages/dashboard.test.tsx index 60bf31b..fe11aa0 100644 --- a/__tests__/pages/dashboard.test.tsx +++ b/__tests__/pages/dashboard.test.tsx @@ -82,7 +82,7 @@ describe('Dashboard', () => { ); expect(screen.getByTestId('login-modal')).toBeInTheDocument(); expect(screen.getByText('Login to view your URLs and create new ones')).toBeInTheDocument(); - const closeButton = screen.getByTestId('close-modal'); + const closeButton = screen.getByTestId('close-login-modal'); closeButton.click(); }); diff --git a/src/components/App/InputSection.tsx b/src/components/App/InputSection.tsx index f7f24e2..dedb2af 100644 --- a/src/components/App/InputSection.tsx +++ b/src/components/App/InputSection.tsx @@ -10,28 +10,25 @@ interface InputSectionProps { const InputSection: React.FC = ({ url, setUrl, handleUrl }) => (
{ e.preventDefault(); handleUrl(); }} data-testid="input-section" > -

- Shorten Your URL +

+ Enter a URL to shorten

-

- Perfect Links Every Time -

- -

Ready to shorten your URL? Enter your URL below

- -
-
+
+
+ ) => setUrl(e.target.value)} value={url} placeholder="Enter the URL" @@ -40,7 +37,7 @@ const InputSection: React.FC = ({ url, setUrl, handleUrl }) =
-
+ + {originalUrl} + + + +
{shortUrl.replace(removeProtocol, '')} -
+
- + +   + +
+ {showQRCodeModal && setShowQRCodeModal(false)} />} ); }; diff --git a/src/components/LoginModal/index.tsx b/src/components/LoginModal/index.tsx index 9b8dcbb..e2f5e17 100644 --- a/src/components/LoginModal/index.tsx +++ b/src/components/LoginModal/index.tsx @@ -38,7 +38,7 @@ const LoginModal: React.FC = ({ onClose, children }) => { ref={modalRef} className="bg-gray-800 p-8 rounded-md w-[330px] relative flex flex-col justify-center items-center shadow-lg" > -

Please log in

diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx deleted file mode 100644 index acb0509..0000000 --- a/src/components/Modal/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import { IoCloseSharp } from 'react-icons/io5'; - -interface ModalProps { - onClose: () => void; - children?: React.ReactNode; - title?: string; - width?: string; - height?: string; -} - -const Modal: React.FC = ({ onClose, children, title, width = '330px', height = 'auto' }) => { - const modalRef = useRef(null); - - const handleClickOutside = (event: MouseEvent) => { - if (modalRef.current && !modalRef.current.contains(event.target as Node)) { - onClose(); - } - }; - - useEffect(() => { - document.addEventListener('mousedown', handleClickOutside); - - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [onClose]); - - return ( - -
- - {title &&

{title}

} - {children} -
-
- ); -}; - -export default Modal; diff --git a/src/components/QRCodeModal.tsx/index.tsx b/src/components/QRCodeModal.tsx/index.tsx new file mode 100644 index 0000000..3474302 --- /dev/null +++ b/src/components/QRCodeModal.tsx/index.tsx @@ -0,0 +1,84 @@ +import QRCode from 'qrcode.react'; +import React, { useEffect, useRef } from 'react'; +import { FcDownload } from 'react-icons/fc'; +import { IoCloseSharp } from 'react-icons/io5'; + +import Button from '@/components/Button'; +const RDSIcon = '_next/image?url=%2Frds.png&w=64&q=75'; + +interface QRCodeModalProps { + shortUrl: string; + onClose: () => void; +} + +const QRCodeModal: React.FC = ({ shortUrl, onClose }) => { + const modalRef = useRef(null); + + const handleClickOutside = (event: MouseEvent) => { + if (modalRef.current && !modalRef.current.contains(event.target as Node)) { + onClose(); + } + }; + + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [onClose]); + + const downloadQRCode = () => { + const canvas = document.getElementById('qr-code') as HTMLCanvasElement; + if (canvas) { + const pngUrl = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); + const downloadLink = document.createElement('a'); + downloadLink.href = pngUrl; + downloadLink.download = `${shortUrl.split('/').pop()}.png`; + document.body.appendChild(downloadLink); + downloadLink.click(); + document.body.removeChild(downloadLink); + } + }; + + return ( + +
+ + + +
+
+ ); +}; + +export default QRCodeModal; diff --git a/src/pages/app/index.tsx b/src/pages/app/index.tsx index 043f4c6..d04bd45 100644 --- a/src/pages/app/index.tsx +++ b/src/pages/app/index.tsx @@ -2,11 +2,10 @@ import React, { useEffect, useState } from 'react'; import InputSection from '@/components/App/InputSection'; import OutputSection from '@/components/App/OutputSection'; -import SignInWithGoogleIcon from '@/components/icons/signWithGoogle'; import Layout from '@/components/Layout'; -import Modal from '@/components/Modal'; +import LoginModal from '@/components/LoginModal'; import Toast from '@/components/Toast'; -import { TINY_API_GOOGLE_LOGIN, TINY_SITE } from '@/constants/url'; +import { TINY_SITE } from '@/constants/url'; import useAuthenticated from '@/hooks/useAuthenticated'; import useToast from '@/hooks/useToast'; import { useShortenUrlMutation } from '@/services/api'; @@ -16,8 +15,8 @@ import validateUrl from '@/utils/validateUrl'; const App = () => { const [url, setUrl] = useState(''); const [shortUrl, setShortUrl] = useState(''); + const [showInputBox, setShowInputBox] = useState(true); const [showLoginModal, setShowLoginModal] = useState(false); - const [showOutputModal, setShowOutputModal] = useState(false); const { showToast, toasts } = useToast(); const { isLoggedIn, userData } = useAuthenticated(); @@ -25,6 +24,7 @@ const App = () => { useEffect(() => { const localUrl = localStorage.getItem('url'); + if (isLoggedIn && localUrl) { setUrl(localUrl); generateShortUrl(localUrl); @@ -34,14 +34,16 @@ const App = () => { const generateShortUrl = async (url: string) => { if (!validateUrl(url, showToast)) return; + try { const response = await shortenUrlMutation.mutateAsync({ originalUrl: url, userData: userData, }); + const fullShortUrl = `${TINY_SITE}/${response.shortUrl}`; setShortUrl(fullShortUrl); - setShowOutputModal(true); + setShowInputBox(false); } catch (e) { const error = e as ErrorResponse; if (error.response && error.response.data && error.response.data.message) { @@ -63,7 +65,7 @@ const App = () => { const createNewHandler = () => { setUrl(''); setShortUrl(''); - setShowOutputModal(false); + setShowInputBox(true); }; const handleUrl = () => { @@ -80,33 +82,10 @@ const App = () => { return (
-
- -
- {toasts.map((toast) => ( - - ))} - {showLoginModal && ( - setShowLoginModal(false)} title="Please log in"> -

Log in to generate short links

- - - -
- )} - {showOutputModal && ( - { - setShowOutputModal(false); - setUrl(''); - }} - width="550px" - height="560px" - > +
+ {showInputBox ? ( + + ) : ( { handleCopyUrl={handleCopyUrl} handleCreateNew={createNewHandler} /> - + )} +
+ {toasts.map((toast) => ( + + ))} + {showLoginModal && ( + setShowLoginModal(false)} + children={

Log in to generate short links

} + /> )}