diff --git a/ecosystem.config.js b/ecosystem.config.js deleted file mode 100644 index 8547d518b..000000000 --- a/ecosystem.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - apps: [{ - name: 'internxt-website', - script: './node_modules/.bin/next start', - env: { - NODE_ENV: 'production', - }, - }], -}; diff --git a/knip.json b/knip.json new file mode 100644 index 000000000..4651583e5 --- /dev/null +++ b/knip.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema.json", + "tags": [ + "-lintignore" + ] +} diff --git a/next-env.d.ts b/next-env.d.ts index 0c7fad710..2d5420eba 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,7 +1,7 @@ /// /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/package.json b/package.json index 911fcd64d..40c4412a5 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "cypress:run": "cypress run --browser chrome", "lint": "eslint --quiet './**/*.{js,ts,tsx}'", "add:npmrc": "echo \"registry=https://registry.yarnpkg.com/\" >> .npmrc && echo \"@internxt:registry=https://npm.pkg.github.com\" >> .npmrc && echo \"//npm.pkg.github.com/:_authToken=$NPM_TOKEN\" >> .npmrc && echo \"always-auth=true\" >> .npmrc", - "vercel:install": "yarn run add:npmrc && yarn install" + "vercel:install": "yarn run add:npmrc && yarn install", + "knip": "knip" }, "dependencies": { "@cemalgnlts/mailjs": "^3.0.1", @@ -33,13 +34,10 @@ "@sendgrid/mail": "^8.1.0", "@stripe/react-stripe-js": "^2.7.3", "@stripe/stripe-js": "^4.1.0", - "@types/offscreencanvas": "^2019.7.3", - "aos": "^2.3.4", "autoprefixer": "^10.0.2", "axios": "^1.18.0", "browser-image-compression": "^2.0.2", "bytes": "^3.1.0", - "clamscan": "^2.0.1", "cookies": "^0.8.0", "dgram": "^1.0.1", "docx": "^9.5.1", @@ -48,7 +46,6 @@ "eslint-config-next": "13", "exifr": "^7.1.3", "hamburger-react": "^2.4.1", - "html-entities": "^2.6.0", "jsonwebtoken": "^9.0.0", "jspdf": "^4.2.1", "jszip": "^3.10.1", @@ -85,25 +82,22 @@ "devDependencies": { "@cypress/code-coverage": "^3.14.7", "@svgr/webpack": "^6.5.1", - "@types/browser-image-compression": "^1.0.13", "@types/jest": "^29.4.0", "@types/memory-cache": "^0.2.1", - "@types/node": "^15.0.1", + "@types/node": "^26.1.2", "@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/parser": "^4.22.0", - "babel-eslint": "^10.1.0", - "babel-plugin-istanbul": "^7.0.1", "cypress": "^13.12.0", "eslint": "^7.32.0", "eslint-config-prettier": "^9.1.0", + "knip": "^6.30.0", "next-unused": "^0.0.6", "postcss": "8.5.18", - "prettier": "2.7.1", "prettier-plugin-tailwindcss": "0.1.13", "reset-css": "5.0.1", "sass": "1.41.0", "tailwindcss": "^3.4.10", - "typescript": "^4.1.5" + "typescript": "^5.9.3" }, "browser": { "child_process": false diff --git a/public/cookiebanner.style.css b/public/cookiebanner.style.css deleted file mode 100644 index 1c8f36f2c..000000000 --- a/public/cookiebanner.style.css +++ /dev/null @@ -1 +0,0 @@ -@import url(https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap);:root{--cookieBannerLight:#ffffff;--cookieBannerDark:#393d4d}#cookieBanner *{margin:0;padding:0;text-decoration:none;list-style:none;font-family:Poppins,sans-serif;-webkit-box-sizing:border-box;box-sizing:border-box}#cookieBanner a,#cookieBanner button{cursor:pointer;color:inherit;font-family:inherit}#cookieBanner button{outline:0;border:none;-moz-appearance:none;appearance:none;-webkit-appearance:none;appearance:none}#cookieBanner em,#cookieBanner strong{font-weight:700;font-family:inherit}#cookieBanner a:hover{text-decoration:none;cursor:pointer}#cookieBanner a:focus,#cookieBanner input:focus{outline:0;list-style:none}#cookieBanner.light{background-color:#fff;background-color:var(--cookieBannerLight);color:#393d4d;color:var(--cookieBannerDark)}#cookieBanner.light p,#cookieBanner.light ul{color:#393d4d;color:var(--cookieBannerDark)}#cookieBanner.light h5{color:var(--cookieBannerDark)}#cookieBanner.light button#cookieReject{background:#fff;background:var(--cookieBannerLight)}#cookieBanner.dark{background-color:#393d4d;background-color:var(--cookieBannerDark);color:#fff;color:var(--cookieBannerLight)}#cookieBanner.dark p,#cookieBanner.dark ul{color:#fff;color:var(--cookieBannerLight)}#cookieBanner.dark h5{color:#fff;color:var(--cookieBannerLight)}#cookieBanner.dark button#cookieReject{background:0 0;color:#fff;color:var(--cookieBannerLight);border:1px solid #fff;border:1px solid var(--cookieBannerLight)}#cookieBanner{-webkit-box-sizing:border-box;box-sizing:border-box;position:fixed;padding:20px;border-radius:10px;-webkit-box-shadow:0 6px 6px rgba(0,0,0,.25);box-shadow:0 6px 6px rgba(0,0,0,.25);font-family:inherit;z-index:999997}#cookieBanner #closeIcon{width:20px;height:20px;cursor:pointer;color:#bfb9b9;overflow:hidden;opacity:.85;z-index:999999;position:absolute;top:4px;right:4px}#cookieBanner svg{display:block}#cookieBanner.display-left{left:30px;bottom:30px;max-width:395px}#cookieBanner.display-right{right:30px;bottom:30px;max-width:395px}#cookieBanner.display-top{top:30px;width:800px;left:50%;margin-left:-400px}#cookieBanner.display-bottom{bottom:30px;width:800px;left:50%;margin-left:-400px}#cookieBanner.display-bottom .content-wrap,#cookieBanner.display-top .content-wrap{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}#cookieBanner.display-bottom .msg-wrap,#cookieBanner.display-top .msg-wrap{max-width:65%;width:100%}#cookieBanner.display-bottom .msg-wrap,#cookieBanner.display-top .msg-wrap{margin-bottom:0}#cookieBanner.display-bottom #cookieSettings,#cookieBanner.display-top #cookieSettings{margin-bottom:0}#cookieBanner.display-bottom #cookieTypes,#cookieBanner.display-top #cookieTypes{margin-top:20px}#cookieBanner .btn-wrap{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;font-weight:700;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin:0 -5px 0 -5px;-ms-flex-wrap:wrap;flex-wrap:wrap}#cookieBanner .btn-wrap button{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;padding:0 7px;margin:0 5px 10px 5px;border-radius:20px;cursor:pointer;white-space:nowrap;min-width:130px;line-height:36px;border:none;font-family:inherit;font-size:16px;-webkit-transition:-webkit-box-shadow .3s;transition:-webkit-box-shadow .3s;-o-transition:box-shadow .3s;transition:box-shadow .3s;transition:box-shadow .3s,-webkit-box-shadow .3s}#cookieBanner .btn-wrap button:hover{-webkit-transition:-webkit-box-shadow .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:-webkit-box-shadow .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);-o-transition:box-shadow .4s cubic-bezier(.25,.8,.25,1),transform .4s cubic-bezier(.25,.8,.25,1);transition:box-shadow .4s cubic-bezier(.25,.8,.25,1),transform .4s cubic-bezier(.25,.8,.25,1);transition:box-shadow .4s cubic-bezier(.25,.8,.25,1),transform .4s cubic-bezier(.25,.8,.25,1),-webkit-box-shadow .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,.3);box-shadow:0 2px 5px 0 rgba(0,0,0,.3);-webkit-transform:translate3d(0,-1px,0);transform:translate3d(0,-1px,0)}#cookieBanner #cookieSettings{font-size:12px;font-weight:700;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;text-transform:uppercase;cursor:pointer;font-weight:400;margin-bottom:20px}#cookieBanner #cookieSettings svg{vertical-align:middle;margin-right:8px}#cookieBanner h4{font-family:inherit;font-weight:700;font-size:18px}#cookieBanner .title-wrap{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:10px}#cookieBanner .title-wrap svg{margin-right:10px}#cookieBanner h5{font-family:inherit;font-weight:700;font-size:12px;margin-bottom:10px;text-transform:uppercase}#cookieBanner p,#cookieBanner ul{font-size:14px;margin-bottom:20px}#cookieBanner p:last-child{margin-bottom:0;text-align:left}#cookieBanner li{width:49%;display:inline-block}#cookieBanner a{text-decoration:none;font-size:14px;padding-bottom:2px;border-bottom:1px dotted rgba(255,255,255,.75);-webkit-transition:all .3s ease-in;-o-transition:all .3s ease-in;transition:all .3s ease-in}#cookieTypes label{text-transform:uppercase;font-size:13px}#cookieBanner button:disabled{opacity:.3}#cookieBanner input[type=checkbox]{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto;-webkit-font-smoothing:antialiased;text-rendering:optimizeSpeed;width:14px;height:14px;margin:4px 10px 0 0;display:block;float:left;position:relative;outline:0;border:none}#cookieBanner input[type=checkbox]:checked:after{background:#d3d3d3;content:"\2714";color:grey}#cookieBanner input[type=checkbox]:after{content:"";vertical-align:middle;text-align:center;line-height:13px;position:absolute;cursor:pointer;height:14px;width:14px;left:0;top:0;font-size:10px;background:#d3d3d3}#cookieBanner.display-bottom.full-width-true,#cookieBanner.display-top.full-width-true{width:100%;max-width:100%;left:auto;right:auto;bottom:auto;top:0;border-radius:0;margin:auto}#cookieBanner.display-bottom.full-width-true{bottom:0;top:auto;-webkit-box-shadow:0 -3px 3px rgb(0 0 0 / 25%);box-shadow:0 -3px 3px rgb(0 0 0 / 25%)}#cookieBanner.display-bottom.full-width-true .title-wrap,#cookieBanner.display-top.full-width-true .title-wrap{display:none}#cookieBanner.display-bottom.full-width-true .btn-wrap button,#cookieBanner.display-top.full-width-true .btn-wrap button{margin-bottom:10px}@media only screen and (max-width:800px){#cookieBanner.display-bottom,#cookieBanner.display-top{width:100%;max-width:100%;left:auto;right:auto;bottom:auto;top:0;border-radius:0;margin:auto}#cookieBanner.display-bottom{bottom:0;top:auto;-webkit-box-shadow:0 -3px 3px rgb(0 0 0 / 25%);box-shadow:0 -3px 3px rgb(0 0 0 / 25%)}#cookieBanner.display-bottom .btn-wrap button,#cookieBanner.display-top .btn-wrap button{margin-bottom:10px}#cookieBanner.display-bottom .msg-wrap,#cookieBanner.display-top .msg-wrap{margin-right:20px}}@media only screen and (max-width:600px){#cookieBanner.display-left,#cookieBanner.display-right{width:100%;max-width:100%;left:auto;right:auto;bottom:0;border-radius:0;-webkit-box-shadow:0 -3px 3px rgb(0 0 0 / 25%);box-shadow:0 -3px 3px rgb(0 0 0 / 25%)}#cookieBanner.display-bottom .content-wrap,#cookieBanner.display-top .content-wrap{display:block}#cookieBanner.display-bottom .msg-wrap,#cookieBanner.display-top .msg-wrap{max-width:100%}#cookieBanner.display-bottom #cookieSettings,#cookieBanner.display-top #cookieSettings{margin-bottom:20px}} \ No newline at end of file diff --git a/public/js/analyticsSnippet.js b/public/js/analyticsSnippet.js deleted file mode 100644 index ac2aaf1ab..000000000 --- a/public/js/analyticsSnippet.js +++ /dev/null @@ -1,54 +0,0 @@ -!function () { - var analytics = window.analytics = window.analytics || []; - if (!analytics.initialize) - if (analytics.invoked) - window.console && console.error && console.error("Segment snippet included twice."); - else { - analytics.invoked = !0; - analytics.methods = [ - "trackSubmit", - "trackClick", - "trackLink", - "trackForm", - "pageview", - "identify", - "reset", - "group", - "track", - "ready", - "alias", - "debug", - "page", - "once", - "off", - "on", - "addSourceMiddleware", - "addIntegrationMiddleware", - "setAnonymousId", - "addDestinationMiddleware" - ]; - analytics.factory = function (e) { - return function () { - var t = Array.prototype.slice.call(arguments); - t.unshift(e); analytics.push(t); - return analytics - } - }; - for (var e = 0; e < analytics.methods.length; e++) { - var key = analytics.methods[e]; - analytics[key] = analytics.factory(key) - } - analytics.load = function (key, e) { - var t = document.createElement("script"); - t.type = "text/javascript"; - t.async = !0; - t.src = "https://drive.internxt.com/js/website.js"; - var n = document.getElementsByTagName("script")[0]; - n.parentNode.insertBefore(t, n); - analytics._loadOptions = e - }; - analytics._writeKey = "uEUiW7CGVHP8WDeA4UtK0hEgVZsmPFtb"; - analytics.SNIPPET_VERSION = "4.15.3"; - analytics.load("uEUiW7CGVHP8WDeA4UtK0hEgVZsmPFtb"); - } -}(); \ No newline at end of file diff --git a/public/js/cookiebanner.script.js b/public/js/cookiebanner.script.js deleted file mode 100644 index 5530678fa..000000000 --- a/public/js/cookiebanner.script.js +++ /dev/null @@ -1,459 +0,0 @@ -'use strict'; - -var supportedLangs = ['en', 'es', 'fr', 'de', 'it', 'ru', 'zh', 'zh-tw']; -var userLang = (navigator.language || navigator.userLanguage).toLowerCase(); -var lang = supportedLangs.includes(userLang) ? userLang : userLang.substring(0, 2); -if (!supportedLangs.includes(lang)) lang = 'en'; - -var translations = { - en: { - title: 'Cookie Consent', - description: - 'This website uses its own and third-party cookies for strictly functional purposes, allowing navigation on the web, as well as for analytical purposes.', - acceptBtnLabel: 'Accept', - declineInfoBtnLabel: 'Reject', - settingsBtnLabel: 'Customize', - moreInfoBtnLabel: 'Privacy Policy', - cookieTypesTitle: 'Select cookies to accept', - necessaryCookieTypeLabel: 'Necessary', - necessaryCookieTypeDesc: - 'These cookies are necessary for the website to function and cannot be switched off in our systems.', - analyticsType: 'Analytics', - analyticsDesc: - 'Analytics cookies allow us to count visits and traffic sources, so we can measure and improve the performance of our site.', - marketingType: 'Marketing', - marketingDesc: - 'Marketing cookies are used to track visitors across websites for advertising and email marketing purposes.', - }, - es: { - title: 'Consentimiento de Cookies', - description: - 'Este sitio web utiliza cookies propias y de terceros para fines estrictamente funcionales, permitiendo la navegación en la web, así como para fines analíticos.', - acceptBtnLabel: 'Aceptar', - declineInfoBtnLabel: 'Rechazar', - settingsBtnLabel: 'Personalizar', - moreInfoBtnLabel: 'Política de privacidad', - cookieTypesTitle: 'Selecciona las cookies a aceptar', - necessaryCookieTypeLabel: 'Necesarias', - necessaryCookieTypeDesc: - 'Estas cookies son necesarias para que el sitio web funcione y no se pueden desactivar en nuestros sistemas.', - analyticsType: 'Analíticas', - analyticsDesc: - 'Las cookies analíticas nos permiten contar las visitas y fuentes de tráfico para medir y mejorar el rendimiento de nuestro sitio.', - marketingType: 'Marketing', - marketingDesc: - 'Las cookies de marketing se utilizan para rastrear visitantes en sitios web con fines publicitarios y de email marketing.', - }, - fr: { - title: 'Consentement aux Cookies', - description: - "Ce site web utilise ses propres cookies et ceux de tiers à des fins strictement fonctionnelles, permettant la navigation sur le web, ainsi qu'à des fins analytiques.", - acceptBtnLabel: 'Accepter', - declineInfoBtnLabel: 'Rejeter', - settingsBtnLabel: 'Personnaliser', - moreInfoBtnLabel: 'Politique de confidentialité', - cookieTypesTitle: 'Sélectionner les cookies à accepter', - necessaryCookieTypeLabel: 'Nécessaires', - necessaryCookieTypeDesc: - 'Ces cookies sont nécessaires au fonctionnement du site web et ne peuvent pas être désactivés dans nos systèmes.', - analyticsType: 'Analytiques', - analyticsDesc: - 'Les cookies analytiques nous permettent de compter les visites et les sources de trafic pour mesurer et améliorer les performances de notre site.', - marketingType: 'Marketing', - marketingDesc: - 'Les cookies marketing sont utilisés pour suivre les visiteurs sur les sites web à des fins publicitaires et de marketing par email.', - }, - de: { - title: 'Cookie-Einwilligung', - description: - 'Diese Website verwendet eigene Cookies und Cookies von Drittanbietern zu rein funktionalen Zwecken, um die Navigation auf der Website zu ermöglichen, sowie zu Analysezwecken.', - acceptBtnLabel: 'Akzeptieren', - declineInfoBtnLabel: 'Ablehnen', - settingsBtnLabel: 'Anpassen', - moreInfoBtnLabel: 'Datenschutzrichtlinie', - cookieTypesTitle: 'Cookies zum Akzeptieren auswählen', - necessaryCookieTypeLabel: 'Notwendig', - necessaryCookieTypeDesc: - 'Diese Cookies sind für die Funktion der Website erforderlich und können in unseren Systemen nicht deaktiviert werden.', - analyticsType: 'Analytik', - analyticsDesc: - 'Analytik-Cookies ermöglichen es uns, Besuche und Verkehrsquellen zu zählen, damit wir die Leistung unserer Website messen und verbessern können.', - marketingType: 'Marketing', - marketingDesc: - 'Marketing-Cookies werden verwendet, um Besucher auf Websites für Werbe- und E-Mail-Marketing-Zwecke zu verfolgen.', - }, - it: { - title: 'Consenso ai Cookie', - description: - 'Questo sito web utilizza cookie propri e di terze parti per scopi strettamente funzionali, consentendo la navigazione sul web, nonché per scopi analitici.', - acceptBtnLabel: 'Accetta', - declineInfoBtnLabel: 'Rifiuta', - settingsBtnLabel: 'Personalizza', - moreInfoBtnLabel: 'Informativa sulla privacy', - cookieTypesTitle: 'Seleziona i cookie da accettare', - necessaryCookieTypeLabel: 'Necessari', - necessaryCookieTypeDesc: - 'Questi cookie sono necessari per il funzionamento del sito web e non possono essere disattivati nei nostri sistemi.', - analyticsType: 'Analitici', - analyticsDesc: - 'I cookie analitici ci consentono di contare le visite e le fonti di traffico per misurare e migliorare le prestazioni del nostro sito.', - marketingType: 'Marketing', - marketingDesc: - 'I cookie di marketing vengono utilizzati per tracciare i visitatori sui siti web a scopi pubblicitari e di email marketing.', - }, - ru: { - title: 'Согласие на использование файлов cookie', - description: - 'Этот веб-сайт использует собственные файлы cookie и файлы cookie третьих лиц для строго функциональных целей, обеспечивая навигацию по сайту, а также в аналитических целях.', - acceptBtnLabel: 'Принять', - declineInfoBtnLabel: 'Отклонить', - settingsBtnLabel: 'Настроить', - moreInfoBtnLabel: 'Политика конфиденциальности', - cookieTypesTitle: 'Выберите файлы cookie для принятия', - necessaryCookieTypeLabel: 'Необходимые', - necessaryCookieTypeDesc: - 'Эти файлы cookie необходимы для работы веб-сайта и не могут быть отключены в наших системах.', - analyticsType: 'Аналитические', - analyticsDesc: - 'Аналитические файлы cookie позволяют нам подсчитывать посещения и источники трафика, чтобы мы могли измерять и улучшать производительность нашего сайта.', - marketingType: 'Маркетинговые', - marketingDesc: - 'Маркетинговые файлы cookie используются для отслеживания посетителей на веб-сайтах в рекламных целях и целях email-маркетинга.', - }, - zh: { - title: 'Cookie 同意声明', - description: '本网站使用自有和第三方 Cookie,用于严格的功能目的,允许在网络上导航,以及用于分析目的。', - acceptBtnLabel: '接受', - declineInfoBtnLabel: '拒绝', - settingsBtnLabel: '自定义', - moreInfoBtnLabel: '隐私政策', - cookieTypesTitle: '选择要接受的 Cookie', - necessaryCookieTypeLabel: '必需', - necessaryCookieTypeDesc: '这些 Cookie 是网站运行所必需的,无法在我们的系统中关闭。', - analyticsType: '分析', - analyticsDesc: '分析 Cookie 使我们能够统计访问量和流量来源,以便我们可以衡量和改进我们网站的性能。', - marketingType: '营销', - marketingDesc: '营销 Cookie 用于跟踪网站访问者,以进行广告和电子邮件营销。', - }, - 'zh-tw': { - title: 'Cookie 同意聲明', - description: '本網站使用自有和第三方 Cookie,用於嚴格的功能目的,允許在網路上導航,以及用於分析目的。', - acceptBtnLabel: '接受', - declineInfoBtnLabel: '拒絕', - settingsBtnLabel: '自訂', - moreInfoBtnLabel: '隱私權政策', - cookieTypesTitle: '選擇要接受的 Cookie', - necessaryCookieTypeLabel: '必需', - necessaryCookieTypeDesc: '這些 Cookie 是網站運作所必需的,無法在我們的系統中關閉。', - analyticsType: '分析', - analyticsDesc: '分析 Cookie 使我們能夠統計訪問量和流量來源,以便我們可以衡量和改進我們網站的效能。', - marketingType: '行銷', - marketingDesc: '行銷 Cookie 用於追蹤網站訪客,以進行廣告和電子郵件行銷。', - }, -}; - -var t = translations[lang]; - -var headerScripts = [ - { - title: 'Google Analytics', - type: 'analytics', - value: - "\n\n", - }, - { - title: 'Klaviyo', - type: 'marketing', - value: - '', - }, -]; - -var config = { - primaryColor: '#0864fc', - darkColor: '#3b3e4a', - lightColor: '#ffffff', - themeMode: 'light', - showSettingsBtn: true, - showCloseIcon: false, - showDeclineBtn: true, - fullWidth: false, - displayPosition: 'left', - settingsBtnLabel: t.settingsBtnLabel, - delay: 2000, - expires: 365, - title: t.title, - description: t.description, - acceptBtnLabel: t.acceptBtnLabel, - declineInfoBtnLabel: t.declineInfoBtnLabel, - moreInfoBtnLink: '/' + lang + '/legal', - moreInfoBtnLabel: t.moreInfoBtnLabel, - cookieTypesTitle: t.cookieTypesTitle, - necessaryCookieTypeLabel: t.necessaryCookieTypeLabel, - necessaryCookieTypeDesc: t.necessaryCookieTypeDesc, - cookieTypes: [ - { - type: t.analyticsType, - value: 'analytics', - description: t.analyticsDesc, - }, - { - type: t.marketingType, - value: 'marketing', - description: t.marketingDesc, - }, - ], -}; - -function _slicedToArray(e, c) { - return _arrayWithHoles(e) || _iterableToArrayLimit(e, c) || _unsupportedIterableToArray(e, c) || _nonIterableRest(); -} -function _nonIterableRest() { - throw new TypeError( - 'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.', - ); -} -function _unsupportedIterableToArray(e, c) { - if (e) { - if ('string' == typeof e) return _arrayLikeToArray(e, c); - var i = Object.prototype.toString.call(e).slice(8, -1); - return ( - 'Object' === i && e.constructor && (i = e.constructor.name), - 'Map' === i || 'Set' === i - ? Array.from(e) - : 'Arguments' === i || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i) - ? _arrayLikeToArray(e, c) - : void 0 - ); - } -} -function _arrayLikeToArray(e, c) { - (null == c || c > e.length) && (c = e.length); - for (var i = 0, r = Array(c); c > i; i++) r[i] = e[i]; - return r; -} -function _iterableToArrayLimit(e, c) { - var i = null == e ? null : ('undefined' != typeof Symbol && e[Symbol.iterator]) || e['@@iterator']; - if (null != i) { - var r, - t, - o = [], - n = !0, - l = !1; - try { - for (i = i.call(e); !(n = (r = i.next()).done) && (o.push(r.value), !c || o.length !== c); n = !0); - } catch (a) { - (l = !0), (t = a); - } finally { - try { - n || null == i['return'] || i['return'](); - } finally { - if (l) throw t; - } - } - return o; - } -} -function _arrayWithHoles(e) { - return Array.isArray(e) ? e : void 0; -} -function appendScriptInHead(e) { - headerScripts.forEach(function (c) { - c.type === e && $('head').append(c.value); - }); -} -var injectScripts = function () { - appendScriptInHead('analytics'); - appendScriptInHead('marketing'); - appendScriptInHead('preferences'); - - window.dataLayer = window.dataLayer || []; - function gtag(){window.dataLayer.push(arguments);} - var prefsStr = document.cookie.split(';').reduce(function(acc, c) { - var parts = c.split('=').map(function(p) { return p.trim(); }); - if (parts[0] && parts[1]) acc[parts[0]] = decodeURIComponent(parts[1]); - return acc; - }, {})['cookieConsentPrefs'] || null; - var prefs = prefsStr ? JSON.parse(prefsStr) : []; - var isAnalytics = prefs.indexOf('analytics') !== -1; - var isMarketing = prefs.indexOf('marketing') !== -1; - - gtag('consent', 'update', { - 'analytics_storage': isAnalytics ? 'granted' : 'denied', - 'ad_storage': isMarketing ? 'granted' : 'denied', - 'ad_user_data': isMarketing ? 'granted' : 'denied', - 'ad_personalization': isMarketing ? 'granted' : 'denied' - }); -}; - -!(function (e) { - var c = this; - e.fn.cookieBanner = function () { - e(':root').css('--cookieBannerLight', config.lightColor), e(':root').css('--cookieBannerDark', config.darkColor); - var c = i('cookieConsent'); - if (c) injectScripts(); - else { - e('#cookieBanner').remove(); - var n = - '
  • '; - e.each(config.cookieTypes, function (e, c) { - if ('' !== c.type && '' !== c.value) { - var i = ''; - c.description !== !1 && (i = ' title="' + c.description + '"'), - (n += - '
  • '); - } - }); - var p = - '
    ' + - s + - '
    ' + - '

    ' + - config.title + - '

    ' + - config.description + - ' ' + - config.moreInfoBtnLabel + - '

    ' + - l + - config.settingsBtnLabel + - '
    '; - setTimeout(function () { - e('body').append(p), - e('#cookieBanner').hide().fadeIn('slow'), - config.showSettingsBtn || e('#cookieSettings').hide(), - config.showDeclineBtn || e('#cookieReject').hide(), - config.showCloseIcon || e('#closeIcon').hide(); - }, config.delay), - e('body').on('click', '#cookieAccept', function () { - r(!0, config.expires), e('input[name="gdprPrefItem"][data-compulsory="on"]').prop('checked', !0); - var c = []; - e.each(e('input[name="gdprPrefItem"]').serializeArray(), function (e, i) { - c.push(i.value); - }), - t('cookieConsentPrefs', encodeURIComponent(JSON.stringify(c)), { expires: o(365), path: '/' }), - injectScripts(); - }), - e('body').on('click', '#cookieSettings', function () { - e('input[name="gdprPrefItem"]:not(:disabled)').attr('data-compulsory', 'off').prop('checked', !0), - e('#cookieTypes').toggle('fast', function () { - e('#cookieSettings').prop('disabled', !1); - }); - }), - e('body').on('click', '#closeIcon', function () { - e('#cookieBanner').remove(); - }), - e('body').on('click', '#cookieReject', function () { - r(!1, config.expires), t('cookieConsentPrefs', '', { expires: o(-365), path: '/' }); - }); - } - }; - var i = function (e) { - return document.cookie.indexOf(e) > -1 ? !0 : !1; - }, - r = function (i, r) { - t('cookieConsent', i, { expires: o(r), path: '/' }), - e('#cookieBanner').fadeOut('fast', function () { - e(c).remove(); - }); - }, - t = function (e, c) { - var i = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}; - document.cookie = '' - .concat(e, '=') - .concat(c) - .concat( - Object.keys(i).reduce(function (e, c) { - return ( - e + - ';' - .concat( - c.replace(/([A-Z])/g, function (e) { - return '-' + e.toLowerCase(); - }), - '=', - ) - .concat(i[c]) - ); - }, ''), - ); - }, - o = function (e) { - var c = new Date(); - return c.setTime(c.getTime() + 24 * e * 60 * 60 * 1e3), c.toUTCString(); - }, - n = function (e) { - var c = document.cookie.split(';').reduce(function (e, c) { - var i = c.split('=').map(function (e) { - return e.trim(); - }), - r = _slicedToArray(i, 2), - t = r[0], - o = r[1]; - return t && o && (e[t] = decodeURIComponent(o)), e; - }, {}); - return e ? c[e] || !1 : c; - }, - l = - '', - s = - ''; - return (window.cookieBanner = { - init: function () { - e.fn.cookieBanner(); - }, - isAccepted: function () { - var e = n('cookieConsent'); - return JSON.parse(e); - }, - getPreferences: function () { - var e = n('cookieConsentPrefs'); - return JSON.parse(e); - }, - isPreferenceAccepted: function (e) { - var c = n('cookieConsent'), - i = n('cookieConsentPrefs'); - return (i = JSON.parse(i)), c === !1 ? !1 : i === !1 || -1 === i.indexOf(e) ? !1 : !0; - }, - }); -})(jQuery); diff --git a/public/js/drift.js b/public/js/drift.js deleted file mode 100644 index 55ea4cc9e..000000000 --- a/public/js/drift.js +++ /dev/null @@ -1,23 +0,0 @@ -"use strict"; -!function() { - var t = window.driftt = window.drift = window.driftt || []; - if (!t.init) { - if (t.invoked) return void (window.console && console.error && console.error("Drift snippet included twice.")); - t.invoked = !0, t.methods = [ "identify", "config", "track", "reset", "debug", "show", "ping", "page", "hide", "off", "on" ], - t.factory = function(e) { - return function() { - var n = Array.prototype.slice.call(arguments); - return n.unshift(e), t.push(n), t; - }; - }, t.methods.forEach(function(e) { - t[e] = t.factory(e); - }), t.load = function(t) { - var e = 3e5, n = Math.ceil(new Date() / e) * e, o = document.createElement("script"); - o.type = "text/javascript", o.async = !0, o.crossorigin = "anonymous", o.src = "https://js.driftt.com/include/" + n + "/" + t + ".js"; - var i = document.getElementsByTagName("script")[0]; - i.parentNode.insertBefore(o, i); - }; - } -}(); -drift.SNIPPET_VERSION = '0.3.1'; -drift.load('7bgvz2cd9ici'); \ No newline at end of file diff --git a/public/js/mailerlite.js b/public/js/mailerlite.js deleted file mode 100644 index f020a9095..000000000 --- a/public/js/mailerlite.js +++ /dev/null @@ -1,13 +0,0 @@ -(function (w, d, e, u, f, l, n) { - (w[f] = - w[f] || - function () { - (w[f].q = w[f].q || []).push(arguments); - }), - (l = d.createElement(e)), - (l.async = 1), - (l.src = u), - (n = d.getElementsByTagName(e)[0]), - n.parentNode.insertBefore(l, n); -})(window, document, 'script', 'https://assets.mailerlite.com/js/universal.js', 'ml'); -ml('account', '16439'); diff --git a/public/js/segment.js b/public/js/segment.js deleted file mode 100644 index c367cc824..000000000 --- a/public/js/segment.js +++ /dev/null @@ -1,3 +0,0 @@ -/* !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e ( -
    -
    - {/* Images */} -
    -
    -
    - Internxt headquarters -
    -
    - Internxt office -
    -
    - Internxt team -
    -
    - Team at Internxt -
    -
    -
    - - {/* Our values */} -
    -

    {textContent.values.title}

    - -
    -
    -
    -

    {textContent.values.items.achieve.title}

    -

    {textContent.values.items.achieve.description}

    -
    - -
    -

    {textContent.values.items.privacy.title}

    -

    {textContent.values.items.privacy.description}

    -
    -
    - -
    -
    -

    {textContent.values.items.family.title}

    -

    {textContent.values.items.family.description}

    -
    - -
    -

    {textContent.values.items.growth.title}

    -

    {textContent.values.items.growth.description}

    -
    -
    -
    -
    - - {/* Careers at Internxt */} -
    -

    {textContent.careers.title}

    - - {textContent.careers.link} - - - stain image -
    -
    -
    -); - -export default CompanySection; diff --git a/src/components/about/HeroSection2.tsx b/src/components/about/HeroSection2.tsx deleted file mode 100644 index 397303b5a..000000000 --- a/src/components/about/HeroSection2.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import React from 'react'; -import Image from "next/image"; - -const HeroSection2 = ({ textContent, lang }) => ( -
    -
    - {/* Main title */} -
    -

    - {textContent.title.line1}
    - - {lang === 'fr' ? textContent.title.line2.substring2 : textContent.title.line2.substring1} - {' '} - - {lang === 'fr' ? textContent.title.line2.substring1 : textContent.title.line2.substring2}{' '} - -
    - {textContent.title.line3.substring1}{' '} - {textContent.title.line3.substring2} -

    - -
    -
    -
    - - {textContent.figures.activeUsers.figure} - - + - - - {textContent.figures.activeUsers.caption} -
    - -
    - - {textContent.figures.awards.figure} - - + - - - {textContent.figures.awards.caption} -
    -
    - -

    - {textContent.description.line1}
    - {textContent.description.line2} -

    -
    - - {/* Recognitions */} -
    -

    {textContent.recognitions.title}

    - -
    -
    -
    - Forbes Logo -

    {textContent.recognitions.brands.forbes.caption1}

    -
    -
    -
    -
    - South Summit Logo -

    {textContent.recognitions.brands.southsummit.caption1}

    -
    -
    -
    -
    - TNW Logo -

    {textContent.recognitions.brands.tnw.caption1}

    -
    -
    -
    -
    - Startup Valencia Logo -

    - {textContent.recognitions.brands.startupvalencia.caption1} -

    -
    -
    -
    -
    - - stain-big logo -
    -
    -
    -); - -export default HeroSection2; diff --git a/src/components/affiliates/FloatingCtaSection.tsx b/src/components/affiliates/FloatingCtaSection.tsx deleted file mode 100644 index 873450e39..000000000 --- a/src/components/affiliates/FloatingCtaSection.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import Image from 'next/image'; -import { getImage } from '@/lib/getImage'; - -const CtaSection = ({ textContent }: { textContent: any }) => { - return ( -
    -
    -
    -

    {textContent.title}

    -
    - FloatingSection Icon -
    -
    -
    -
    - ); -}; - -export default CtaSection; diff --git a/src/components/affiliates/affiliates-partners-template/CtaSection.tsx b/src/components/affiliates/affiliates-partners-template/CtaSection.tsx deleted file mode 100644 index b11f981d9..000000000 --- a/src/components/affiliates/affiliates-partners-template/CtaSection.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { getImage } from '@/lib/getImage'; - -export const CtaSection = ({ textContent }) => { - const handleOnButtonClick = () => { - window.scrollTo({ - top: 0, - behavior: 'smooth', - }); - }; - - return ( -
    -
    -
    -

    {textContent.title}

    -

    {textContent.description}

    -
    - -
    -
    - ); -}; diff --git a/src/components/affiliates/affiliates-partners-template/DevicesSection.tsx b/src/components/affiliates/affiliates-partners-template/DevicesSection.tsx deleted file mode 100644 index 2b6bd7047..000000000 --- a/src/components/affiliates/affiliates-partners-template/DevicesSection.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { getImage } from '@/lib/getImage'; -import Image from 'next/image'; - -export const DevicesSection = ({ textContent }) => { - const handleOnButtonClick = () => { - window.scrollTo({ - top: 0, - behavior: 'smooth', - }); - }; - - return ( -
    -
    -
    -

    {textContent.title}

    - -
    -
    - Internxt secure cloud storage -
    -
    -
    - ); -}; diff --git a/src/components/affiliates/affiliates-partners-template/PriceCardsForAffiliatesParnters.tsx b/src/components/affiliates/affiliates-partners-template/PriceCardsForAffiliatesParnters.tsx deleted file mode 100644 index b600082d1..000000000 --- a/src/components/affiliates/affiliates-partners-template/PriceCardsForAffiliatesParnters.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { checkout } from '@/lib/auth'; -import { PromoCodeProps } from '@/lib/types'; -import styles from '@/components/black-friday/BF-HeroSection.module.scss'; -import { - ArrowsClockwise, - Broom, - CirclesThreePlus, - CodeBlock, - Database, - Detective, - Envelope, - Fingerprint, - Fire, - Gauge, - Gift, - Key, - LockSimple, - Password, - ShieldPlus, - VideoConference, -} from '@phosphor-icons/react'; -import React from 'react'; - -interface PriceCardsForAffiliatesPartnersProps { - storage: string; - popular: boolean; - currency: string; - priceBefore: string; - price: number; - planId: string; - currencyValue: string; - coupon: PromoCodeProps | undefined; -} - -export const PriceCardsForAffiliatesPartners = ({ - storage, - popular, - currency, - priceBefore, - price, - planId, - currencyValue, - coupon, -}: PriceCardsForAffiliatesPartnersProps) => { - const contentText = require(`@/assets/lang/en/priceCard.json`); - - function onCheckoutButtonClicked() { - checkout({ - planId: planId, - mode: 'payment', - planType: 'individual', - currency: currencyValue ?? 'eur', - promoCodeId: coupon?.name ?? undefined, - }); - } - - const iconsFeatures = [ - Database, - Key, - Gauge, - ShieldPlus, - ArrowsClockwise, - Password, - CirclesThreePlus, - LockSimple, - Fingerprint, - CodeBlock, - Broom, - Detective, - VideoConference, - Envelope, - ]; - - const planTypes = { - '1TB': contentText.productFeatures.planTypes.essentials, - '2TB': contentText.productFeatures.planTypes.pro, - '3TB': contentText.productFeatures.planTypes.premium, - '5TB': contentText.productFeatures.planTypes.ultimate, - }; - const cardLabel = planTypes[storage] || null; - - return ( -
    -
    -
    - {popular ? ( -
    - -

    {contentText.mostPopular}

    -
    - ) : null} -
    -

    {cardLabel}

    -
    -
    -
    -
    -

    - {currency} - {price} -

    -

    /

    -

    - {currency} - {priceBefore} -

    -
    - -

    {contentText.billingFrequencyLabel['lifetime']}

    -
    - -
    - -
    -
    - {contentText.productFeatures.individuals[storage].map((feature, index) => ( -
    - {React.createElement(iconsFeatures[index % iconsFeatures.length], { - size: 24, - className: 'text-primary', - })} - {feature} - {index > 8 ? ( - {contentText.commingSoon} - ) : null} -
    - ))} -
    -
    -
    - ); -}; diff --git a/src/components/affiliates/brave/ScrollableSection.tsx b/src/components/affiliates/brave/ScrollableSection.tsx deleted file mode 100644 index 0129634e3..000000000 --- a/src/components/affiliates/brave/ScrollableSection.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Devices, Eye, FolderLock, ShieldCheck } from '@phosphor-icons/react'; -import { Fragment, useState } from 'react'; -import ReactMarkdown from 'react-markdown'; -import RevealX from '@/components/components/RevealX'; - -const ScrollableSection = ({ textContent }) => { - const [cardIndex, setCardIndex] = useState(0); - - const cardElements = [ - { - icon: ShieldCheck, - title: textContent.elements[0].title, - description: textContent.elements[0].description, - }, - { - icon: FolderLock, - title: textContent.elements[1].title, - description: textContent.elements[1].description, - }, - { - icon: Devices, - title: textContent.elements[2].title, - description: textContent.elements[2].description, - }, - { - icon: Eye, - title: textContent.elements[3].title, - description: textContent.elements[3].description, - }, - ]; - - const DescriptionIcon = cardElements[cardIndex].icon; - - return ( -
    -
    -
    -

    {textContent.title}

    -
    -

    {textContent.description}

    -
    -
    -
    -
    -
    - {textContent.elements.map((info, index) => ( - - -
    - - ))} -
    - -
    -
    -
    - -

    {cardElements[cardIndex].title}

    - - {cardElements[cardIndex].description} - -
    -
    -
    -
    -
    -
    - {cardElements.map((info) => ( -
    - -
    -

    {info.title}

    - {info.description} -
    -
    - ))} -
    -
    - ); -}; - -export default ScrollableSection; diff --git a/src/components/affiliates/oneplan/FeaturesSectionForOneplan.tsx b/src/components/affiliates/oneplan/FeaturesSectionForOneplan.tsx deleted file mode 100644 index 27699d111..000000000 --- a/src/components/affiliates/oneplan/FeaturesSectionForOneplan.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { getImage } from '@/lib/getImage'; -import Image from 'next/image'; - -export const FeaturesSectionForOnePlan = ({ textContent }) => { - const handleOnButtonClick = () => { - window.scrollTo({ - top: 0, - behavior: 'smooth', - }); - }; - - return ( -
    -
    -
    -

    {textContent.title}

    - {textContent.description.map((text, index) => ( -

    - {text} -

    - ))} - - -
    -
    - Internxt secure cloud storage -
    -
    -
    - ); -}; diff --git a/src/components/ai-detector/BannersSection.tsx b/src/components/ai-detector/BannersSection.tsx deleted file mode 100644 index 5b35992e4..000000000 --- a/src/components/ai-detector/BannersSection.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import Image from "next/image"; -import { CaretRight } from '@phosphor-icons/react'; - -const BannersSection = ({ textContent, lang }) => { - return ( -
    -
    -
    -

    {textContent.title}

    -
    -
    -
    - Password checker image -

    {textContent.passwordCheckerBanner.title}

    - -
    -
    - Byte converter image -

    {textContent.byteConverterBanner.title}

    - -
    -
    -
    -
    - ); -}; - -export default BannersSection; diff --git a/src/components/ai-detector/CtaSection.tsx b/src/components/ai-detector/CtaSection.tsx deleted file mode 100644 index ff590473b..000000000 --- a/src/components/ai-detector/CtaSection.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import styles from '../../components/techradar-discount/Background.module.scss'; - -const CtaSection = ({ textContent }) => { - return ( -
    -
    -
    -

    {textContent.title}

    -

    {textContent.description}

    -
    - -
    -
    -
    - ); -}; - -export default CtaSection; diff --git a/src/components/ai-detector/FeatureSliderImg.tsx b/src/components/ai-detector/FeatureSliderImg.tsx deleted file mode 100644 index 6bf56c825..000000000 --- a/src/components/ai-detector/FeatureSliderImg.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import Image from 'next/image'; - -const FeaturesSliderImg = ({ textContent, cardInfo }) => { - return ( -
    -
    -
    -

    {textContent.title}

    -
    -

    {textContent.description}

    -
    -
    -
    - -
    - {cardInfo.map((info) => ( -
    - {info.image && ( -
    - {info.title} -
    - )} - -
    -

    {info.title}

    - {Array.isArray(info.description) ? ( - info.description.map((line, index) => ( -

    - {line} -

    - )) - ) : ( -

    {info.description}

    - )} -
    -
    - ))} -
    -
    - ); -}; - -export default FeaturesSliderImg; diff --git a/src/components/ai-detector/FeaturesSection.tsx b/src/components/ai-detector/FeaturesSection.tsx deleted file mode 100644 index f33833699..000000000 --- a/src/components/ai-detector/FeaturesSection.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import SignUpBanner from '../banners/SignUpBanner'; - -const FeaturesSection = ({ textContent, bannerText, lang }) => { - return ( -
    -
    -
    - -
    -
    -
    -

    {textContent.aiCheckerTitle}

    -

    {textContent.aiCheckerDescription}

    -
    - -
    -

    {textContent.aiDetectorTitle}

    -

    {textContent.aiDetectorDescription}

    -
    -
    -
    -
    - ); -}; - -export default FeaturesSection; diff --git a/src/components/ai-detector/HeroSection.tsx b/src/components/ai-detector/HeroSection.tsx deleted file mode 100644 index 812ef5676..000000000 --- a/src/components/ai-detector/HeroSection.tsx +++ /dev/null @@ -1,239 +0,0 @@ -import { useState, Fragment, createRef } from 'react'; -import { AiDetectorText } from '@/assets/types/aiDetector'; -import pdfToText from 'react-pdftotext'; - -interface HeroSectionProps { - textContent: AiDetectorText['HeroSection']; - lang: string; -} - -const MIN_CHARS = 250; -const MAX_CHARS = 15000; - -const HeroSection = ({ textContent }: HeroSectionProps): JSX.Element => { - const [text, setText] = useState(''); - const [detectionScore, setDetectionScore] = useState(null); - const [isScanning, setIsScanning] = useState(false); - const [error, setError] = useState(null); - const uploadFileRef = createRef(); - - const resetDetectionState = () => { - setDetectionScore(null); - setError(null); - }; - - const handleTextChange = (e: React.ChangeEvent) => { - setText(e.target.value); - resetDetectionState(); - }; - - const processPdfFile = async (file: File) => { - try { - const text = await pdfToText(file); - setText(text); - resetDetectionState(); - } catch (err) { - setError(textContent.error.fileReadError); - console.error('Error reading PDF:', err); - } - }; - - const processTextFile = (file: File) => { - const reader = new FileReader(); - reader.onload = (event) => { - const fileText = event.target?.result as string; - setText(fileText); - resetDetectionState(); - }; - reader.readAsText(file); - }; - - const isValidFileType = (file: File): boolean => { - return file.type === 'application/pdf' || file.type === 'text/plain' || file.name.endsWith('.txt'); - }; - - const handleFileUpload = async (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file) return; - - if (!isValidFileType(file)) { - setError(textContent.error.unsupportedFile); - return; - } - - try { - if (file.type === 'application/pdf') { - await processPdfFile(file); - } else { - processTextFile(file); - } - } catch (err) { - setError(textContent.error.fileReadError); - console.error('Error reading file:', err); - } - }; - - const processApiResponse = (result: any) => { - if (!result.success || !result.data) { - throw new Error('Invalid response format'); - } - - const aiPercentage = parseFloat(result.data.fakePercentage); - const humanPercentage = Math.round(100 - aiPercentage); - setDetectionScore(humanPercentage); - }; - - const handleScan = async () => { - if (text.length < MIN_CHARS) { - setError(textContent.error.minChars); - return; - } - - setIsScanning(true); - setError(null); - - try { - const response = await fetch('/api/ai-detector', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ input_text: text }), - }); - - if (!response.ok) { - throw new Error('API request failed'); - } - - const result = await response.json(); - processApiResponse(result); - } catch (err) { - setError(textContent.error.apiError); - console.error('Error:', err); - } finally { - setIsScanning(false); - } - }; - - const getProgressBarColor = (score: number): string => { - if (score > 60) return 'bg-green-1'; - if (score > 30) return 'bg-yellow'; - return 'bg-red'; - }; - - const renderDetectionResult = () => { - if (isScanning) { - return ( -
    -
    - Scanning... -
    - ); - } - - return ( - <> -
    - {detectionScore !== null ? {detectionScore}% : '%'} -
    - -
    - {detectionScore !== null && ( -
    - )} -
    - -
    - {detectionScore !== null && ( - {textContent.humanGeneratedText} - )} -
    - -
    - {detectionScore === null ? ( - textContent.detectionScore - ) : ( -
    - {detectionScore >= 50 ? textContent.likelyHumanText : textContent.likelyAiText} -
    - )} -
    - - ); - }; - - return ( -
    -
    -
    -

    {textContent.mainTitle}

    -
    - {textContent.subtitle &&

    {textContent.subtitle}

    } -
    -
    - -
    -
    -
    - -
    -