From 2d7a2d1c3a5b50eb23e4c9f7d5f3cfb8dea44cdf Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Mon, 20 Apr 2026 18:57:42 +0530 Subject: [PATCH 01/15] feat(merge): display file size and page count in PdfCard --- .gitignore | 4 ++++ src/components/ui/AnimatedBackground.jsx | 1 + src/pages/Home/components/Features.jsx | 2 +- src/pages/Home/components/Hero.jsx | 1 + src/pages/Home/components/ToolsGrid.jsx | 1 + src/pages/ImageToPdf/ImageToPdf.jsx | 1 + src/pages/Merge/Merge.jsx | 4 ++-- 7 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a547bf3..6604d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ dist-ssr *.njsproj *.sln *.sw? +# Environment files +.env +.env.local +*.local \ No newline at end of file diff --git a/src/components/ui/AnimatedBackground.jsx b/src/components/ui/AnimatedBackground.jsx index fa706d5..f58c0c8 100644 --- a/src/components/ui/AnimatedBackground.jsx +++ b/src/components/ui/AnimatedBackground.jsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react'; +import { motion } from "framer-motion"; export function AnimatedBackground() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); diff --git a/src/pages/Home/components/Features.jsx b/src/pages/Home/components/Features.jsx index 8f0615a..b909ba5 100644 --- a/src/pages/Home/components/Features.jsx +++ b/src/pages/Home/components/Features.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { Zap, Shield, FileCheck } from 'lucide-react'; - +import { motion } from "framer-motion"; export function Features() { const features = [ { diff --git a/src/pages/Home/components/Hero.jsx b/src/pages/Home/components/Hero.jsx index 399fe38..f82b4c5 100644 --- a/src/pages/Home/components/Hero.jsx +++ b/src/pages/Home/components/Hero.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { ShieldCheck } from 'lucide-react'; +import { motion } from "framer-motion"; export function Hero() { const container = { diff --git a/src/pages/Home/components/ToolsGrid.jsx b/src/pages/Home/components/ToolsGrid.jsx index 4210ec9..4c40333 100644 --- a/src/pages/Home/components/ToolsGrid.jsx +++ b/src/pages/Home/components/ToolsGrid.jsx @@ -1,5 +1,6 @@ import React from "react"; import { Link } from "react-router-dom"; +import { motion } from "framer-motion"; import { Layers, SplitSquareHorizontal, diff --git a/src/pages/ImageToPdf/ImageToPdf.jsx b/src/pages/ImageToPdf/ImageToPdf.jsx index 199eac2..4152b1d 100644 --- a/src/pages/ImageToPdf/ImageToPdf.jsx +++ b/src/pages/ImageToPdf/ImageToPdf.jsx @@ -10,6 +10,7 @@ import { formatFileSize } from "../../utils/formatters"; import { useSubscription } from "../../hooks/useSubscription"; import { FREE_LIMITS } from "../../config/limits"; + let _uid = 0; function makeItem(file) { const url = URL.createObjectURL(file); diff --git a/src/pages/Merge/Merge.jsx b/src/pages/Merge/Merge.jsx index 63cdd35..9392647 100644 --- a/src/pages/Merge/Merge.jsx +++ b/src/pages/Merge/Merge.jsx @@ -112,9 +112,9 @@ function PdfCard({ item, onRemove, onPreview, onDragStart, onDragEnter, onDragEn {/* Name + size */} -
+

{item.name}

-

{formatFileSize(item.size)}

+

{formatFileSize(item.size)}{item.numPages && ` . ${item.numPages} pages `}

{/* Remove */} From 04bcf9e3851beded2f1e5f243e929661b6c438f0 Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Mon, 20 Apr 2026 19:33:29 +0530 Subject: [PATCH 02/15] fix(lint): remove unused motion imports --- src/components/ui/AnimatedBackground.jsx | 2 +- src/pages/Home/components/Features.jsx | 2 +- src/pages/Home/components/Hero.jsx | 2 +- src/pages/Home/components/ToolsGrid.jsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ui/AnimatedBackground.jsx b/src/components/ui/AnimatedBackground.jsx index 59194b9..9904127 100644 --- a/src/components/ui/AnimatedBackground.jsx +++ b/src/components/ui/AnimatedBackground.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { motion } from "framer-motion"; + export function AnimatedBackground() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); diff --git a/src/pages/Home/components/Features.jsx b/src/pages/Home/components/Features.jsx index fc20bf9..70f4817 100644 --- a/src/pages/Home/components/Features.jsx +++ b/src/pages/Home/components/Features.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { Zap, Shield, FileCheck } from 'lucide-react'; -import { motion } from "framer-motion"; + export function Features() { const features = [ { diff --git a/src/pages/Home/components/Hero.jsx b/src/pages/Home/components/Hero.jsx index 58076ba..7ad0b93 100644 --- a/src/pages/Home/components/Hero.jsx +++ b/src/pages/Home/components/Hero.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { ShieldCheck } from 'lucide-react'; -import { motion } from "framer-motion"; + export function Hero() { const container = { diff --git a/src/pages/Home/components/ToolsGrid.jsx b/src/pages/Home/components/ToolsGrid.jsx index 374de76..26be11c 100644 --- a/src/pages/Home/components/ToolsGrid.jsx +++ b/src/pages/Home/components/ToolsGrid.jsx @@ -1,6 +1,6 @@ import React from "react"; import { Link } from "react-router-dom"; -import { motion } from "framer-motion"; + import { Layers, SplitSquareHorizontal, From 16d849813c4f073216354eba05c6becb69608c99 Mon Sep 17 00:00:00 2001 From: Srashti Chauhan Date: Mon, 20 Apr 2026 20:54:36 +0530 Subject: [PATCH 03/15] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/pages/Merge/Merge.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Merge/Merge.jsx b/src/pages/Merge/Merge.jsx index 9392647..4326fbf 100644 --- a/src/pages/Merge/Merge.jsx +++ b/src/pages/Merge/Merge.jsx @@ -114,7 +114,7 @@ function PdfCard({ item, onRemove, onPreview, onDragStart, onDragEnter, onDragEn {/* Name + size */}

{item.name}

-

{formatFileSize(item.size)}{item.numPages && ` . ${item.numPages} pages `}

+

{formatFileSize(item.size)}{item.numPages != null && ` · ${item.numPages} pages`}

{/* Remove */} From f9de56f3b2672443271cd691fe6109e022e324bc Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Tue, 21 Apr 2026 00:32:34 +0530 Subject: [PATCH 04/15] fix: restore framer-motion imports where required --- src/components/ui/AnimatedBackground.jsx | 2 +- src/pages/Home/components/Features.jsx | 1 + src/pages/Home/components/Hero.jsx | 2 +- src/pages/Home/components/ToolsGrid.jsx | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/ui/AnimatedBackground.jsx b/src/components/ui/AnimatedBackground.jsx index 9904127..40860c8 100644 --- a/src/components/ui/AnimatedBackground.jsx +++ b/src/components/ui/AnimatedBackground.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; - +import { motion as Motion } from "framer-motion"; export function AnimatedBackground() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); diff --git a/src/pages/Home/components/Features.jsx b/src/pages/Home/components/Features.jsx index 70f4817..a86bc1c 100644 --- a/src/pages/Home/components/Features.jsx +++ b/src/pages/Home/components/Features.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { Zap, Shield, FileCheck } from 'lucide-react'; +import { motion as Motion } from "framer-motion"; export function Features() { const features = [ diff --git a/src/pages/Home/components/Hero.jsx b/src/pages/Home/components/Hero.jsx index 7ad0b93..11b26fc 100644 --- a/src/pages/Home/components/Hero.jsx +++ b/src/pages/Home/components/Hero.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { ShieldCheck } from 'lucide-react'; - +import { motion as Motion } from "framer-motion"; export function Hero() { const container = { diff --git a/src/pages/Home/components/ToolsGrid.jsx b/src/pages/Home/components/ToolsGrid.jsx index 26be11c..0a53ddf 100644 --- a/src/pages/Home/components/ToolsGrid.jsx +++ b/src/pages/Home/components/ToolsGrid.jsx @@ -1,5 +1,6 @@ import React from "react"; import { Link } from "react-router-dom"; +import { motion as Motion } from "framer-motion"; import { Layers, From 4d8479cab45b38d17c4571942a2a29b7d917e96e Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Tue, 21 Apr 2026 00:52:07 +0530 Subject: [PATCH 05/15] fix: address review comments (remove gitignore changes and fix imports) --- .gitignore | 4 ---- src/components/ui/AnimatedBackground.jsx | 2 +- src/pages/Home/components/Features.jsx | 2 +- src/pages/Home/components/Hero.jsx | 2 +- src/pages/Home/components/ToolsGrid.jsx | 2 +- 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 6604d6b..a547bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,3 @@ dist-ssr *.njsproj *.sln *.sw? -# Environment files -.env -.env.local -*.local \ No newline at end of file diff --git a/src/components/ui/AnimatedBackground.jsx b/src/components/ui/AnimatedBackground.jsx index 40860c8..a0dda92 100644 --- a/src/components/ui/AnimatedBackground.jsx +++ b/src/components/ui/AnimatedBackground.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { motion as Motion } from "framer-motion"; +import { motion as Motion } from 'framer-motion'; export function AnimatedBackground() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); diff --git a/src/pages/Home/components/Features.jsx b/src/pages/Home/components/Features.jsx index a86bc1c..06998fa 100644 --- a/src/pages/Home/components/Features.jsx +++ b/src/pages/Home/components/Features.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { Zap, Shield, FileCheck } from 'lucide-react'; -import { motion as Motion } from "framer-motion"; +import { motion as Motion } from 'framer-motion'; export function Features() { const features = [ diff --git a/src/pages/Home/components/Hero.jsx b/src/pages/Home/components/Hero.jsx index 11b26fc..509a054 100644 --- a/src/pages/Home/components/Hero.jsx +++ b/src/pages/Home/components/Hero.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { ShieldCheck } from 'lucide-react'; -import { motion as Motion } from "framer-motion"; +import { motion as Motion } from 'framer-motion'; export function Hero() { const container = { diff --git a/src/pages/Home/components/ToolsGrid.jsx b/src/pages/Home/components/ToolsGrid.jsx index 0a53ddf..e840e52 100644 --- a/src/pages/Home/components/ToolsGrid.jsx +++ b/src/pages/Home/components/ToolsGrid.jsx @@ -1,6 +1,6 @@ import React from "react"; import { Link } from "react-router-dom"; -import { motion as Motion } from "framer-motion"; +import { motion as Motion } from 'framer-motion'; import { Layers, From 678fe1b1b4220093eb6124aedb022adbf3b1044e Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Tue, 21 Apr 2026 01:24:12 +0530 Subject: [PATCH 06/15] fix: restore FREE_LIMITS import and clean unnecessary changes --- src/pages/ImageToPdf/ImageToPdf.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/ImageToPdf/ImageToPdf.jsx b/src/pages/ImageToPdf/ImageToPdf.jsx index 752469e..71200a9 100644 --- a/src/pages/ImageToPdf/ImageToPdf.jsx +++ b/src/pages/ImageToPdf/ImageToPdf.jsx @@ -8,9 +8,7 @@ import { Dropzone } from "../../components/pdf/Dropzone"; import { imageToPdf } from "../../services/pdf.service"; import { formatFileSize } from "../../utils/formatters"; import { useSubscription } from "../../hooks/useSubscription"; -import { FREE_LIMITS } from "../../config/limits"; - - +import { FREE_LIMITS } from '../../config/limits'; let _uid = 0; function makeItem(file) { const url = URL.createObjectURL(file); From 0957a70e5f0e4cd9979afb38ffed88966b52d2b1 Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Wed, 22 Apr 2026 22:18:33 +0530 Subject: [PATCH 07/15] chore: finalize metadata updates and fixes --- src/pages/PageNumbers/PageNumbers.jsx | 2 +- src/pages/Watermark/Watermark.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/PageNumbers/PageNumbers.jsx b/src/pages/PageNumbers/PageNumbers.jsx index f5a900a..2b3be37 100644 --- a/src/pages/PageNumbers/PageNumbers.jsx +++ b/src/pages/PageNumbers/PageNumbers.jsx @@ -127,7 +127,7 @@ export function PageNumbers() {

{file.name}

-

{formatFileSize(file.size)}

+

{formatFileSize(file.size)} • PDF

- {/* Name + size */} -
-

{item.name}

-

{formatFileSize(item.size)}{item.numPages != null && ` · ${item.numPages} pages`}

+ {/* File Info */} +
+ + {/* File name */} +

+ {item.name} +

+ + {/* Metadata */} +

+ {formatFileSize(item.size)} + {item.numPages != null && ` • ${item.numPages} pages`} +

+
{/* Remove */} From 2aefcdf49e611ed60dfa3d800ce000dbf5aa86ef Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Thu, 30 Apr 2026 00:51:24 +0530 Subject: [PATCH 11/15] fix: remove console log and lint issues in watermark tool --- src/pages/Watermark/Watermark.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Watermark/Watermark.jsx b/src/pages/Watermark/Watermark.jsx index bd5b530..bdd1429 100644 --- a/src/pages/Watermark/Watermark.jsx +++ b/src/pages/Watermark/Watermark.jsx @@ -102,7 +102,7 @@ export function Watermark() { setFile(selectedFile); const count = await getPdfPageCount(selectedFile); - console.log("Page count:", count); + setPageCount(count); setPreviewUrl(null); }; From 629b2151d082a9584b2f87baf3d3acbe00f2dc74 Mon Sep 17 00:00:00 2001 From: SrashtiChauhan Date: Thu, 30 Apr 2026 00:59:45 +0530 Subject: [PATCH 12/15] fix: add missing getPdfPageCount import in watermark tool --- eslint | 0 quickpdf@0.0.0 | 0 src/pages/Watermark/Watermark.jsx | 324 +++++++++++++++--------------- 3 files changed, 157 insertions(+), 167 deletions(-) create mode 100644 eslint create mode 100644 quickpdf@0.0.0 diff --git a/eslint b/eslint new file mode 100644 index 0000000..e69de29 diff --git a/quickpdf@0.0.0 b/quickpdf@0.0.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/Watermark/Watermark.jsx b/src/pages/Watermark/Watermark.jsx index bdd1429..edc2a85 100644 --- a/src/pages/Watermark/Watermark.jsx +++ b/src/pages/Watermark/Watermark.jsx @@ -1,6 +1,6 @@ -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect } from "react"; import { useFileStore } from "../../hooks/useFileStore"; -import { Stamp, X, Download, Loader2, Settings2 } from "lucide-react"; +import { Stamp, X, Download, Loader2 } from "lucide-react"; import { Button } from "../../components/ui/Button"; import { UpgradeButton } from "../../components/ui/UpgradeButton"; import { addWatermark, getPdfPageCount } from "../../services/pdf.service"; @@ -8,13 +8,14 @@ import { Dropzone } from "../../components/pdf/Dropzone"; import { formatFileSize } from "../../utils/formatters"; import { useSubscription } from "../../hooks/useSubscription"; import { FREE_LIMITS, mbToBytes } from "../../config/limits"; -import { getPdfPageCount } from "../../services/pdf.service"; + export function Watermark() { const [file, setFile] = useFileStore("Watermark_file", null); const [watermarkText, setWatermarkText] = useState("CONFIDENTIAL"); const [isProcessing, setIsProcessing] = useState(false); + const [error, setError] = useState(null); const [originalPreviewUrl, setOriginalPreviewUrl] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const [pageCount, setPageCount] = useState(0); @@ -26,68 +27,41 @@ export function Watermark() { isWalletConnected, } = useSubscription(); - // 1. Fetch Page Count ONLY when a file exists useEffect(() => { - if (!file) return; // Just exit, don't set state here - - const fetchPageCount = async () => { - try { - const count = await getPdfPageCount(file); - setPageCount(count); - } catch (err) { - console.error("Failed to get page count:", err); + return () => { + if (originalPreviewUrl) { + URL.revokeObjectURL(originalPreviewUrl); + } + if (previewUrl) { + URL.revokeObjectURL(previewUrl); } }; + }, [originalPreviewUrl, previewUrl]); - fetchPageCount(); - }, [file]); - + // Recreate original preview URL when file is loaded from storage but preview is missing useEffect(() => { - if (!file || !watermarkText.trim()) { - const t = setTimeout(() => setPreviewUrl(null), 0); - return () => clearTimeout(t); - } - - const timer = setTimeout(async () => { - try { - setIsProcessing(true); - const blob = await addWatermark(file, watermarkText, options); - const url = URL.createObjectURL(blob); - - if (lastUrlRef.current) URL.revokeObjectURL(lastUrlRef.current); - lastUrlRef.current = url; - setPreviewUrl(url); - } catch (err) { - console.error("Preview failed", err); - } finally { - setIsProcessing(false); - } - }, 500); + if (!file || previewUrl || originalPreviewUrl) return; - return () => clearTimeout(timer); - }, [file, watermarkText, options]); + const originalUrl = file.url || URL.createObjectURL(file); + queueMicrotask(() => setOriginalPreviewUrl(originalUrl)); - // 3. Handle cleanup on unmount - useEffect(() => { return () => { - if (originalPreviewUrl) URL.revokeObjectURL(originalPreviewUrl); - if (lastUrlRef.current) URL.revokeObjectURL(lastUrlRef.current); + if (!file.url) { + URL.revokeObjectURL(originalUrl); + } }; - }, [originalPreviewUrl]); + }, [file, previewUrl, originalPreviewUrl]); + + const fileTooLarge = + !isPremium && + file && + file.size > mbToBytes(FREE_LIMITS.watermark.maxFileSizeMb); - // 4. Initialize original preview - useEffect(() => { - if (!file || originalPreviewUrl) return; - const url = file.url || URL.createObjectURL(file); - const t = setTimeout(() => setOriginalPreviewUrl(url), 0); - return () => clearTimeout(t); - }, [file, originalPreviewUrl]); - - // Subscription & Lock Logic - const fileTooLarge = !isPremium && file && file.size > mbToBytes(FREE_LIMITS.watermark.maxFileSizeMb); const isLocked = hasReachedGlobalLimit || fileTooLarge; const lockReason = hasReachedGlobalLimit ? "global" : "size"; - const lockLabel = fileTooLarge ? `${FREE_LIMITS.watermark.maxFileSizeMb} MB` : undefined; + const lockLabel = fileTooLarge + ? `${FREE_LIMITS.watermark.maxFileSizeMb} MB` + : undefined; const handleFileSelected = async (selectedFiles) => { const selectedFile = selectedFiles[0]; @@ -114,19 +88,17 @@ export function Watermark() { setIsProcessing(true); setError(null); - const updateOption = (key, value) => { - setOptions(prev => ({ ...prev, [key]: value })); - }; + const watermarkedBlob = await addWatermark(file, watermarkText); + const url = URL.createObjectURL(watermarkedBlob); - const handleDownload = async () => { - if (!previewUrl) return; - await incrementUsage(); - const link = document.createElement("a"); - link.href = previewUrl; - link.download = `QuickPDF_Watermarked_${Date.now()}.pdf`; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); + setPreviewUrl(url); + await incrementUsage(); + } catch { + setError("Could not read the PDF file. It might be corrupted or encrypted."); + setFile(null); + } finally { + setIsProcessing(false); + } }; function clearFile() { setFile(null); @@ -136,34 +108,49 @@ export function Watermark() { } return ( -
+
-

Add Watermark

-

Secure browser-based watermarking.

+ +

+ Add Watermark +

+ +

+ Stamp text across your document securely in your browser. + {!isPremium && ( + + Free tier: files up to{" "} + {FREE_LIMITS.watermark.maxFileSizeMb} MB + + )} +

-
+
- {!file ? ( - - ) : ( -
-
-
- {file.name} -
- {formatFileSize(file.size)} - - {pageCount} {pageCount === 1 ? 'page' : 'pages'} -
-
- -
+ {error && ( +
+ {error} +
+ )} + + {!file ? ( + + ) : ( +
+
+
+ + {file.name} + {formatFileSize(file.size)} • {pageCount} pages @@ -175,106 +162,109 @@ export function Watermark() {
-
-
- -

Style & Position

-
- -
- - -
- -
-
- - updateOption("fontSize", parseInt(e.target.value))} className="w-full h-1.5 bg-zinc-800 rounded-lg appearance-none cursor-pointer accent-white" /> -
-
- - updateOption("opacity", parseFloat(e.target.value))} className="w-full h-1.5 bg-zinc-800 rounded-lg appearance-none cursor-pointer accent-white" /> -
-
- -
- - updateOption("rotation", parseInt(e.target.value))} className="w-full h-1.5 bg-zinc-800 rounded-lg appearance-none cursor-pointer accent-white" /> -
- -
-
- - updateOption("offsetX", parseInt(e.target.value) || 0)} - className="w-full h-10 px-3 bg-black border border-white/10 text-white rounded-lg outline-none focus:ring-1 focus:ring-white/20" - /> -
-
- - updateOption("offsetY", parseInt(e.target.value) || 0)} - className="w-full h-10 px-3 bg-black border border-white/10 text-white rounded-lg outline-none focus:ring-1 focus:ring-white/20" - /> -
-
-
+
- )} -
- {file && ( -
-

- {isProcessing ? "Updating Preview..." : previewUrl ? "Preview with Watermark" : "Original PDF"} -

-