diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c378fe3..6b25408 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -35,7 +35,6 @@ "next-themes": "^0.4.6", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-google-recaptcha": "^3.1.0", "react-router-dom": "^6.28.0", "tailwind-merge": "^3.2.0" }, @@ -49,7 +48,6 @@ "@types/node": "^25.0.3", "@types/react": "^18.3.18", "@types/react-dom": "^18.3.5", - "@types/react-google-recaptcha": "^2.1.9", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "eslint": "^9.17.0", @@ -3462,15 +3460,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/react-google-recaptcha": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", - "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/whatwg-mimetype": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", @@ -4732,19 +4721,6 @@ "node": ">=8" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5336,14 +5312,6 @@ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -5513,21 +5481,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5549,18 +5502,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-async-script": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", - "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", - "dependencies": { - "hoist-non-react-statics": "^3.3.0", - "prop-types": "^15.5.0" - }, - "peerDependencies": { - "react": ">=16.4.1" - } - }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -5574,18 +5515,6 @@ "react": "^18.3.1" } }, - "node_modules/react-google-recaptcha": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", - "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", - "dependencies": { - "prop-types": "^15.5.0", - "react-async-script": "^1.2.0" - }, - "peerDependencies": { - "react": ">=16.4.1" - } - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 624051e..5473c98 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,7 +39,6 @@ "next-themes": "^0.4.6", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-google-recaptcha": "^3.1.0", "react-router-dom": "^6.28.0", "tailwind-merge": "^3.2.0" }, @@ -53,7 +52,6 @@ "@types/node": "^25.0.3", "@types/react": "^18.3.18", "@types/react-dom": "^18.3.5", - "@types/react-google-recaptcha": "^2.1.9", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "eslint": "^9.17.0", diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 4ae4518..7fbd63c 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -96,10 +96,6 @@ export async function translateFile(request: TranslateRequest): Promise(null); const [loadingEstimate, setLoadingEstimate] = useState(false); const [isDragging, setIsDragging] = useState(false); - const [recaptchaToken, setRecaptchaToken] = useState(null); - const recaptchaRef = useRef(null); const containerRef = useRef(null); const { status, error, filename, progress, translate, downloadResult, reset } = useTranslate(); @@ -88,11 +86,6 @@ export function TranslateForm() { if (status !== 'idle') { reset(); } - // Reset reCAPTCHA when file changes - if (fileInfo !== selectedFile) { - recaptchaRef.current?.reset(); - setRecaptchaToken(null); - } }, [status, reset, selectedFile]); // Handle drag and drop @@ -136,30 +129,10 @@ export function TranslateForm() { }, [handleFileSelect]); const isTranslating = status === 'uploading' || status === 'translating'; - const recaptchaSiteKey = import.meta.env.VITE_RECAPTCHA_SITE_KEY || ''; - // reCAPTCHA is required only if site key is configured - const recaptchaRequired = !!recaptchaSiteKey; const handleTranslate = useCallback(async () => { if (!selectedFile || !targetLanguage) return; - // If reCAPTCHA is configured, execute it first (invisible mode) - if (recaptchaRequired && !recaptchaToken) { - try { - if (recaptchaRef.current) { - recaptchaRef.current.execute(); - return; // Wait for onChange callback to proceed - } else { - // reCAPTCHA ref not available, proceed without it (fallback) - console.warn('reCAPTCHA ref not available, proceeding without verification'); - } - } catch (error) { - console.error('reCAPTCHA execution error:', error); - // Continue without reCAPTCHA on error - } - } - - // Proceed with translation (token already obtained from reCAPTCHA onChange, or no reCAPTCHA) await translate({ file: selectedFile.file, targetLanguage, @@ -168,35 +141,13 @@ export function TranslateForm() { sheets: selectedSheets.length > 0 && selectedSheets.length < sheets.length ? selectedSheets : undefined, - recaptchaToken: recaptchaToken || undefined, }); - }, [selectedFile, targetLanguage, sourceLanguage, context, selectedSheets, sheets.length, recaptchaToken, recaptchaRequired, translate]); - - // Handle reCAPTCHA token received (for invisible mode) - const handleRecaptchaChange = useCallback((token: string | null) => { - setRecaptchaToken(token); - // If we have a token and form is ready, proceed with translation - if (token && selectedFile && targetLanguage) { - translate({ - file: selectedFile.file, - targetLanguage, - sourceLanguage: sourceLanguage || undefined, - context: context || undefined, - sheets: selectedSheets.length > 0 && selectedSheets.length < sheets.length - ? selectedSheets - : undefined, - recaptchaToken: token, - }); - } }, [selectedFile, targetLanguage, sourceLanguage, context, selectedSheets, sheets.length, translate]); const handleRetry = useCallback(() => { reset(); - recaptchaRef.current?.reset(); - setRecaptchaToken(null); }, [reset]); - // For invisible reCAPTCHA, button is enabled when form is ready (reCAPTCHA executes on click) const canTranslate = selectedFile && targetLanguage && !isTranslating; return ( @@ -369,17 +320,6 @@ export function TranslateForm() { )} - {/* Invisible reCAPTCHA - hidden but always rendered when site key is available */} - {recaptchaSiteKey && ( -
- -
- )} - {/* Translate Button */}