From 377d5d763e7bc7c2916397ba53fdf8c1b18a9fb3 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Sat, 2 Mar 2024 04:05:46 +0600 Subject: [PATCH] fix: download image button --- .../GenerateRoadmap/GenerateRoadmap.tsx | 88 ++++++++----------- .../GenerateRoadmap/RoadmapSearch.tsx | 20 +++-- src/helper/download-image.ts | 32 +++++++ src/pages/ai/index.astro | 2 + 4 files changed, 87 insertions(+), 55 deletions(-) diff --git a/src/components/GenerateRoadmap/GenerateRoadmap.tsx b/src/components/GenerateRoadmap/GenerateRoadmap.tsx index a5fcd7d89..9da07761a 100644 --- a/src/components/GenerateRoadmap/GenerateRoadmap.tsx +++ b/src/components/GenerateRoadmap/GenerateRoadmap.tsx @@ -1,19 +1,24 @@ import { useEffect, useRef, useState, type FormEvent } from 'react'; -import fp from '@fingerprintjs/fingerprintjs'; import './GenerateRoadmap.css'; import { useToast } from '../../hooks/use-toast'; import { generateAIRoadmapFromText } from '../../../editor/utils/roadmap-generator'; import { renderFlowJSON } from '../../../editor/renderer/renderer'; import { replaceChildren } from '../../lib/dom'; import { readAIRoadmapStream } from '../../helper/read-stream'; -import { removeAuthToken } from '../../lib/jwt'; +import { isLoggedIn, removeAuthToken } from '../../lib/jwt'; import { RoadmapSearch } from './RoadmapSearch.tsx'; import { Spinner } from '../ReactIcons/Spinner.tsx'; import { Download, PenSquare, Wand } from 'lucide-react'; import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx'; import { httpGet, httpPost } from '../../lib/http.ts'; import { pageProgressMessage } from '../../stores/page.ts'; -import { getUrlParams, setUrlParams } from '../../lib/browser.ts'; +import { + deleteUrlParam, + getUrlParams, + setUrlParams, +} from '../../lib/browser.ts'; +import { downloadGeneratedRoadmapImage } from '../../helper/download-image.ts'; +import { showLoginPopup } from '../../lib/popup.ts'; const ROADMAP_ID_REGEX = new RegExp('@ROADMAPID:(\\w+)@'); @@ -31,6 +36,14 @@ export function GenerateRoadmap() { const [roadmapLimit, setRoadmapLimit] = useState(0); const [roadmapLimitUsed, setRoadmapLimitUsed] = useState(0); + const renderRoadmap = async (roadmap: string) => { + const { nodes, edges } = generateAIRoadmapFromText(roadmap); + const svg = await renderFlowJSON({ nodes, edges }); + if (roadmapContainerRef?.current) { + replaceChildren(roadmapContainerRef?.current, svg); + } + }; + const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setIsLoading(true); @@ -48,11 +61,7 @@ export function GenerateRoadmap() { return; } - const fingerprintPromise = await fp.load({ - debug: import.meta.env.DEV, - }); - - const fingerprint = await fingerprintPromise.get(); + deleteUrlParam('id'); const response = await fetch( `${import.meta.env.PUBLIC_API_URL}/v1-generate-ai-roadmap`, @@ -60,7 +69,6 @@ export function GenerateRoadmap() { method: 'POST', headers: { 'Content-Type': 'application/json', - fp: fingerprint.visitorId, }, credentials: 'include', body: JSON.stringify({ topic: roadmapTopic }), @@ -99,11 +107,7 @@ export function GenerateRoadmap() { result = result.replace(ROADMAP_ID_REGEX, ''); } - const { nodes, edges } = generateAIRoadmapFromText(result); - const svg = await renderFlowJSON({ nodes, edges }); - if (roadmapContainerRef?.current) { - replaceChildren(roadmapContainerRef?.current, svg); - } + await renderRoadmap(result); }, onStreamEnd: async (result) => { result = result.replace(ROADMAP_ID_REGEX, ''); @@ -116,6 +120,11 @@ export function GenerateRoadmap() { }; const editGeneratedRoadmap = async () => { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + pageProgressMessage.set('Redirecting to Editor'); const { nodes, edges } = generateAIRoadmapFromText(generatedRoadmap); @@ -158,30 +167,8 @@ export function GenerateRoadmap() { return; } - // Append a watermark to the bottom right of the image - const watermark = document.createElement('div'); - watermark.className = 'flex justify-end absolute bottom-4 right-4 gap-2'; - watermark.innerHTML = ` - - roadmap.sh - - `; - node.insertAdjacentElement('afterbegin', watermark); - try { - const domtoimage = (await import('dom-to-image')).default; - const dataUrl = await domtoimage.toJpeg(node, { - bgcolor: 'white', - quality: 1, - }); - node?.removeChild(watermark); - const link = document.createElement('a'); - link.download = `${roadmapTopic}-roadmap.jpg`; - link.href = dataUrl; - link.click(); - + await downloadGeneratedRoadmapImage(roadmapTopic, node); pageProgressMessage.set(''); } catch (error) { console.error(error); @@ -210,7 +197,6 @@ export function GenerateRoadmap() { }; const loadAIRoadmap = async (roadmapId: string) => { - setIsLoading(true); pageProgressMessage.set('Loading Roadmap'); const { response, error } = await httpGet<{ @@ -225,12 +211,7 @@ export function GenerateRoadmap() { } const { topic, data } = response; - - const { nodes, edges } = generateAIRoadmapFromText(data); - const svg = await renderFlowJSON({ nodes, edges }); - if (roadmapContainerRef?.current) { - replaceChildren(roadmapContainerRef?.current, svg); - } + await renderRoadmap(data); setRoadmapTopic(topic); setGeneratedRoadmap(data); @@ -246,8 +227,7 @@ export function GenerateRoadmap() { } setHasSubmitted(true); - loadAIRoadmap(roadmapId).then(() => { - setIsLoading(false); + loadAIRoadmap(roadmapId).finally(() => { pageProgressMessage.set(''); }); }, [roadmapId]); @@ -279,10 +259,18 @@ export function GenerateRoadmap() {
- {roadmapLimitUsed} of {roadmapLimit} roadmaps generated{' '} - + {roadmapLimitUsed} of {roadmapLimit} roadmaps generated + {!isLoggedIn() && ( + <> + {' '} + + + )}
You have generated{' '} - {limitUsed} of ${limit} + {limitUsed} of {limit} {' '} - roadmaps today.{' '} - + roadmaps today. + {!isLoggedIn && ( + <> + {' '} + + + )}

diff --git a/src/helper/download-image.ts b/src/helper/download-image.ts index 193128cea..db598a49d 100644 --- a/src/helper/download-image.ts +++ b/src/helper/download-image.ts @@ -34,3 +34,35 @@ export async function downloadImage({ alert('Error downloading image'); } } + +export async function downloadGeneratedRoadmapImage( + name: string, + node: HTMLElement, +) { + // Append a watermark to the bottom right of the image + const watermark = document.createElement('div'); + watermark.className = 'flex justify-end absolute top-4 right-4 gap-2'; + watermark.innerHTML = ` + + roadmap.sh + + `; + node.insertAdjacentElement('afterbegin', watermark); + + const domtoimage = (await import('dom-to-image')).default; + if (!domtoimage) { + throw new Error('Unable to download image'); + } + + const dataUrl = await domtoimage.toJpeg(node, { + bgcolor: 'white', + quality: 1, + }); + node?.removeChild(watermark); + const link = document.createElement('a'); + link.download = `${name}-roadmap.jpg`; + link.href = dataUrl; + link.click(); +} diff --git a/src/pages/ai/index.astro b/src/pages/ai/index.astro index 9e91c4c36..149e2064a 100644 --- a/src/pages/ai/index.astro +++ b/src/pages/ai/index.astro @@ -1,8 +1,10 @@ --- +import LoginPopup from '../../components/AuthenticationFlow/LoginPopup.astro'; import { GenerateRoadmap } from '../../components/GenerateRoadmap/GenerateRoadmap'; import AccountLayout from '../../layouts/AccountLayout.astro'; --- +