import React, { useState, useEffect, useRef } from "react"; import { useLocation, useNavigate, useParams } from "react-router-dom"; import Prism from "prismjs"; import styles from "./Editor.module.css"; import "../prism-themes/prism-gruvbox-dark.css"; import "../prism-themes/prism-line-numbers.css"; import { BASE_URL, URL_REGEX } from "../../utils/constants"; import Header from "../Header/Header"; import { generateAESKey, keyToString, stringToKey, encryptAES, decryptAES, } from "../../utils/encryption"; import Modal from "../Modal/Modal"; const Editor = () => { const { id } = useParams(); const navigate = useNavigate(); const location = useLocation(); const [text, setText] = useState(""); const [language, setLanguage] = useState("none"); const [openModal, setOpenModal] = useState(false); const textareaRef = useRef(null); const lineNumberRef = useRef(null); const queryParams = new URLSearchParams(location.search); const handleTextChange = (event) => { setText(event.target.value); }; const handleScroll = () => { if (textareaRef.current && lineNumberRef.current) { lineNumberRef.current.scrollTop = textareaRef.current.scrollTop; } }; const handleSaveClick = async () => { if (!text) { alert("Please enter some text!"); return; } if (URL_REGEX.test(text)) { const response = await fetch(`${BASE_URL}/bin`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ language, content: text, }), }); const data = await response.json(); if (response.ok) { navigator.clipboard .writeText(`${window.location.origin}/r/${data.id}`) .then( function () { alert("Short URL copied to clipboard!"); }, function () { try { document.execCommand("copy"); alert("Short URL copied to clipboard!"); } catch (err) { console.log("Oops, unable to copy"); } }, ); } navigate(`/${data.id}`); return; } setOpenModal(true); }; const handleSuccessClick = async () => { setOpenModal(false); const key = await generateAESKey(); const keyString = await keyToString(key); const { encrypted, iv } = await encryptAES(text, key); const encryptedBase64 = btoa( String.fromCharCode.apply(null, new Uint8Array(encrypted)), ); const ivBase64 = btoa(String.fromCharCode.apply(null, iv)); const response = await fetch(`${BASE_URL}/bin`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ language, content: encryptedBase64, iv: ivBase64, }), }); const data = await response.json(); if (response.ok) { navigator.clipboard .writeText(`${window.location.origin}/${data.id}?key=${keyString}`) .then( function () { navigator.clipboard.writeText( `${window.location.origin}/${data.id}?key=${keyString}`, ); alert("URL copied to clipboard!"); }, function () { try { document.execCommand("copy"); alert("URL copied to clipboard!"); } catch (err) { console.log("Oops, unable to copy"); } }, ); navigate(`/${data.id}?key=${keyString}`); } else { console.error(data); } }; const handleCancelClick = async () => { setOpenModal(false); const response = await fetch(`${BASE_URL}/bin`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ language, content: text, }), }); const data = await response.json(); if (response.ok) { navigator.clipboard .writeText(`${window.location.origin}/${data.id}`) .then( function () { navigator.clipboard.writeText( `${window.location.origin}/${data.id}`, ); alert("URL copied to clipboard!"); }, function () { try { document.execCommand("copy"); alert("URL copied to clip`board!"); } catch (err) { console.log("Oops, unable to copy"); } }, ); navigate(`/${data.id}`); } else { console.error(data); } }; const handleLanguageChange = (value) => { setLanguage(value); }; useEffect(() => { Prism.highlightAll(); }, [text, language]); useEffect(() => { const fetchData = async () => { const response = await fetch(`${BASE_URL}/bin/${id}`); const data = await response.json(); if (response.ok) { if (data.iv) { const keyString = queryParams.get("key"); const key = await stringToKey(keyString); const encrypted = new Uint8Array( atob(data.content) .split("") .map((char) => char.charCodeAt(0)), ).buffer; const ivArray = new Uint8Array( atob(data.iv) .split("") .map((char) => char.charCodeAt(0)), ); const decryptedContent = await decryptAES(encrypted, key, ivArray); setLanguage(data.language); setText(decryptedContent); } else { const isURL = URL_REGEX.test(data.content); if (isURL) { setText(`Your shortened URL: ${window.location.origin}/r/${id}`); } else { setLanguage(data.language); setText(data.content); } } } }; if (id) { fetchData(); } else { textareaRef.current.value = ""; setText(""); } }, [id]); return ( <>
{ handleSuccessClick(); }} onCancelClick={() => { handleCancelClick(); }} />
{!id && ( )}