diff --git a/messages/en.json b/messages/en.json deleted file mode 100644 index 3b44906..0000000 --- a/messages/en.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "common": { - "save": "Save", - "cancel": "Cancel", - "delete": "Delete", - "edit": "Edit", - "close": "Close", - "back": "Back", - "next": "Next", - "loading": "Loading...", - "submit": "Submit", - "retry": "Try again", - "ok": "OK" - }, - "appName": "wacrm", - "appTagline": "CRM Template for WhatsApp", - "nav": { - "dashboard": "Dashboard", - "inbox": "Inbox", - "contacts": "Contacts", - "pipelines": "Pipelines", - "broadcasts": "Broadcasts", - "automations": "Automations", - "flows": "Flows", - "settings": "Settings", - "beta": "Beta", - "betaFeatureAria": "Beta feature", - "unreadAria": "{count, plural, =1 {# unread conversation} other {# unread conversations}}", - "openMenu": "Open menu", - "closeMenu": "Close menu", - "primaryAria": "Primary", - "openAccountMenu": "Open account menu", - "avatarAlt": "Avatar", - "userFallback": "User", - "profile": "Profile", - "signOut": "Sign out" - }, - "roles": { - "owner": "Owner", - "admin": "Admin", - "agent": "Agent", - "viewer": "Viewer" - }, - "auth": { - "login": { - "title": "Welcome back", - "titleInvite": "Sign in to accept", - "subtitle": "Sign in to your account", - "subtitleInvite": "Sign in and we'll take you to the invitation.", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "passwordLabel": "Password", - "passwordPlaceholder": "Enter your password", - "forgotPassword": "Forgot password?", - "submit": "Sign in", - "submitting": "Signing in...", - "noAccount": "Don't have an account?", - "createAccount": "Create account" - }, - "signup": { - "title": "Create account", - "titleInvite": "Create account & join", - "subtitle": "Get started with CRM Template for WhatsApp", - "subtitleInvite": "Verify your email, then accept the invitation to join your team.", - "fullNameLabel": "Full name", - "fullNamePlaceholder": "John Doe", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "passwordLabel": "Password", - "passwordPlaceholder": "At least 6 characters", - "confirmPasswordLabel": "Confirm password", - "confirmPasswordPlaceholder": "Repeat your password", - "submit": "Create account", - "submitting": "Creating account...", - "haveAccount": "Already have an account?", - "signIn": "Sign in", - "passwordMismatch": "Passwords do not match", - "passwordTooShort": "Password must be at least 6 characters", - "checkEmailTitle": "Check your email", - "checkEmailBody": "We've sent a confirmation link to {email}. Please check your inbox and click the link to verify your account.", - "backToSignIn": "Back to sign in" - }, - "forgotPassword": { - "title": "Reset password", - "subtitle": "Enter your email and we'll send you a reset link", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "submit": "Send reset link", - "submitting": "Sending...", - "checkEmailTitle": "Check your email", - "checkEmailBody": "We've sent a password reset link to {email}. Please check your inbox.", - "backToSignIn": "Back to sign in" - } - }, - "join": { - "verifying": "Verifying invitation…", - "invitedToTitle": "You're invited to {accountName}", - "invitedAs": "You'll join as {role}. Link valid until {date, date, medium}.", - "acceptInvitation": "Accept invitation", - "accepting": "Accepting…", - "acceptFooter": "Accepting moves your login into {accountName}. Your empty personal account from signup will be cleaned up.", - "createAccountAndJoin": "Create account & join", - "alreadyHaveAccount": "I already have an account", - "conflictTitle": "Can't join {accountName} with this account", - "conflictBody": "To join {accountName}, sign out and sign up again with a different email address. The invite link stays valid as long as it hasn't expired.", - "staySignedIn": "Stay signed in", - "signOutAndRetry": "Sign out & use a different email", - "signingOut": "Signing out…", - "createNewAccountInstead": "Create a new account instead", - "signIn": "Sign in", - "tryAgain": "Try again", - "redeemConflictFallback": "You are already in another account. Sign in with a different email to join this one.", - "redeemFailedFallback": "Failed to accept invitation", - "redeemNetworkError": "Could not reach the server", - "signOutError": "Could not sign out. Try refreshing the page.", - "welcomeToast": "Welcome to the team", - "fail": { - "notFound": { - "title": "Invite not found", - "body": "This link doesn't match a valid invitation. Double-check the URL or ask the person who invited you to send a new one." - }, - "used": { - "title": "Invite already used", - "body": "This invitation has already been accepted. If that wasn't you, ask the account admin to send a fresh link." - }, - "expired": { - "title": "Invite expired", - "body": "This invitation has expired. Ask the account admin to send a new one — they take a few seconds to generate." - }, - "serverError": { - "title": "Something went wrong", - "body": "We couldn't verify this invitation right now. Try refreshing the page in a moment." - } - } - }, - "localeSwitcher": { - "label": "Language", - "ariaLabel": "Change language", - "locales": { - "en": "English", - "es": "Español", - "lt": "Lietuvių" - } - } -} diff --git a/messages/es.json b/messages/es.json deleted file mode 100644 index 3b44906..0000000 --- a/messages/es.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "common": { - "save": "Save", - "cancel": "Cancel", - "delete": "Delete", - "edit": "Edit", - "close": "Close", - "back": "Back", - "next": "Next", - "loading": "Loading...", - "submit": "Submit", - "retry": "Try again", - "ok": "OK" - }, - "appName": "wacrm", - "appTagline": "CRM Template for WhatsApp", - "nav": { - "dashboard": "Dashboard", - "inbox": "Inbox", - "contacts": "Contacts", - "pipelines": "Pipelines", - "broadcasts": "Broadcasts", - "automations": "Automations", - "flows": "Flows", - "settings": "Settings", - "beta": "Beta", - "betaFeatureAria": "Beta feature", - "unreadAria": "{count, plural, =1 {# unread conversation} other {# unread conversations}}", - "openMenu": "Open menu", - "closeMenu": "Close menu", - "primaryAria": "Primary", - "openAccountMenu": "Open account menu", - "avatarAlt": "Avatar", - "userFallback": "User", - "profile": "Profile", - "signOut": "Sign out" - }, - "roles": { - "owner": "Owner", - "admin": "Admin", - "agent": "Agent", - "viewer": "Viewer" - }, - "auth": { - "login": { - "title": "Welcome back", - "titleInvite": "Sign in to accept", - "subtitle": "Sign in to your account", - "subtitleInvite": "Sign in and we'll take you to the invitation.", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "passwordLabel": "Password", - "passwordPlaceholder": "Enter your password", - "forgotPassword": "Forgot password?", - "submit": "Sign in", - "submitting": "Signing in...", - "noAccount": "Don't have an account?", - "createAccount": "Create account" - }, - "signup": { - "title": "Create account", - "titleInvite": "Create account & join", - "subtitle": "Get started with CRM Template for WhatsApp", - "subtitleInvite": "Verify your email, then accept the invitation to join your team.", - "fullNameLabel": "Full name", - "fullNamePlaceholder": "John Doe", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "passwordLabel": "Password", - "passwordPlaceholder": "At least 6 characters", - "confirmPasswordLabel": "Confirm password", - "confirmPasswordPlaceholder": "Repeat your password", - "submit": "Create account", - "submitting": "Creating account...", - "haveAccount": "Already have an account?", - "signIn": "Sign in", - "passwordMismatch": "Passwords do not match", - "passwordTooShort": "Password must be at least 6 characters", - "checkEmailTitle": "Check your email", - "checkEmailBody": "We've sent a confirmation link to {email}. Please check your inbox and click the link to verify your account.", - "backToSignIn": "Back to sign in" - }, - "forgotPassword": { - "title": "Reset password", - "subtitle": "Enter your email and we'll send you a reset link", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "submit": "Send reset link", - "submitting": "Sending...", - "checkEmailTitle": "Check your email", - "checkEmailBody": "We've sent a password reset link to {email}. Please check your inbox.", - "backToSignIn": "Back to sign in" - } - }, - "join": { - "verifying": "Verifying invitation…", - "invitedToTitle": "You're invited to {accountName}", - "invitedAs": "You'll join as {role}. Link valid until {date, date, medium}.", - "acceptInvitation": "Accept invitation", - "accepting": "Accepting…", - "acceptFooter": "Accepting moves your login into {accountName}. Your empty personal account from signup will be cleaned up.", - "createAccountAndJoin": "Create account & join", - "alreadyHaveAccount": "I already have an account", - "conflictTitle": "Can't join {accountName} with this account", - "conflictBody": "To join {accountName}, sign out and sign up again with a different email address. The invite link stays valid as long as it hasn't expired.", - "staySignedIn": "Stay signed in", - "signOutAndRetry": "Sign out & use a different email", - "signingOut": "Signing out…", - "createNewAccountInstead": "Create a new account instead", - "signIn": "Sign in", - "tryAgain": "Try again", - "redeemConflictFallback": "You are already in another account. Sign in with a different email to join this one.", - "redeemFailedFallback": "Failed to accept invitation", - "redeemNetworkError": "Could not reach the server", - "signOutError": "Could not sign out. Try refreshing the page.", - "welcomeToast": "Welcome to the team", - "fail": { - "notFound": { - "title": "Invite not found", - "body": "This link doesn't match a valid invitation. Double-check the URL or ask the person who invited you to send a new one." - }, - "used": { - "title": "Invite already used", - "body": "This invitation has already been accepted. If that wasn't you, ask the account admin to send a fresh link." - }, - "expired": { - "title": "Invite expired", - "body": "This invitation has expired. Ask the account admin to send a new one — they take a few seconds to generate." - }, - "serverError": { - "title": "Something went wrong", - "body": "We couldn't verify this invitation right now. Try refreshing the page in a moment." - } - } - }, - "localeSwitcher": { - "label": "Language", - "ariaLabel": "Change language", - "locales": { - "en": "English", - "es": "Español", - "lt": "Lietuvių" - } - } -} diff --git a/messages/lt.json b/messages/lt.json deleted file mode 100644 index 3b44906..0000000 --- a/messages/lt.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "common": { - "save": "Save", - "cancel": "Cancel", - "delete": "Delete", - "edit": "Edit", - "close": "Close", - "back": "Back", - "next": "Next", - "loading": "Loading...", - "submit": "Submit", - "retry": "Try again", - "ok": "OK" - }, - "appName": "wacrm", - "appTagline": "CRM Template for WhatsApp", - "nav": { - "dashboard": "Dashboard", - "inbox": "Inbox", - "contacts": "Contacts", - "pipelines": "Pipelines", - "broadcasts": "Broadcasts", - "automations": "Automations", - "flows": "Flows", - "settings": "Settings", - "beta": "Beta", - "betaFeatureAria": "Beta feature", - "unreadAria": "{count, plural, =1 {# unread conversation} other {# unread conversations}}", - "openMenu": "Open menu", - "closeMenu": "Close menu", - "primaryAria": "Primary", - "openAccountMenu": "Open account menu", - "avatarAlt": "Avatar", - "userFallback": "User", - "profile": "Profile", - "signOut": "Sign out" - }, - "roles": { - "owner": "Owner", - "admin": "Admin", - "agent": "Agent", - "viewer": "Viewer" - }, - "auth": { - "login": { - "title": "Welcome back", - "titleInvite": "Sign in to accept", - "subtitle": "Sign in to your account", - "subtitleInvite": "Sign in and we'll take you to the invitation.", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "passwordLabel": "Password", - "passwordPlaceholder": "Enter your password", - "forgotPassword": "Forgot password?", - "submit": "Sign in", - "submitting": "Signing in...", - "noAccount": "Don't have an account?", - "createAccount": "Create account" - }, - "signup": { - "title": "Create account", - "titleInvite": "Create account & join", - "subtitle": "Get started with CRM Template for WhatsApp", - "subtitleInvite": "Verify your email, then accept the invitation to join your team.", - "fullNameLabel": "Full name", - "fullNamePlaceholder": "John Doe", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "passwordLabel": "Password", - "passwordPlaceholder": "At least 6 characters", - "confirmPasswordLabel": "Confirm password", - "confirmPasswordPlaceholder": "Repeat your password", - "submit": "Create account", - "submitting": "Creating account...", - "haveAccount": "Already have an account?", - "signIn": "Sign in", - "passwordMismatch": "Passwords do not match", - "passwordTooShort": "Password must be at least 6 characters", - "checkEmailTitle": "Check your email", - "checkEmailBody": "We've sent a confirmation link to {email}. Please check your inbox and click the link to verify your account.", - "backToSignIn": "Back to sign in" - }, - "forgotPassword": { - "title": "Reset password", - "subtitle": "Enter your email and we'll send you a reset link", - "emailLabel": "Email", - "emailPlaceholder": "you@example.com", - "submit": "Send reset link", - "submitting": "Sending...", - "checkEmailTitle": "Check your email", - "checkEmailBody": "We've sent a password reset link to {email}. Please check your inbox.", - "backToSignIn": "Back to sign in" - } - }, - "join": { - "verifying": "Verifying invitation…", - "invitedToTitle": "You're invited to {accountName}", - "invitedAs": "You'll join as {role}. Link valid until {date, date, medium}.", - "acceptInvitation": "Accept invitation", - "accepting": "Accepting…", - "acceptFooter": "Accepting moves your login into {accountName}. Your empty personal account from signup will be cleaned up.", - "createAccountAndJoin": "Create account & join", - "alreadyHaveAccount": "I already have an account", - "conflictTitle": "Can't join {accountName} with this account", - "conflictBody": "To join {accountName}, sign out and sign up again with a different email address. The invite link stays valid as long as it hasn't expired.", - "staySignedIn": "Stay signed in", - "signOutAndRetry": "Sign out & use a different email", - "signingOut": "Signing out…", - "createNewAccountInstead": "Create a new account instead", - "signIn": "Sign in", - "tryAgain": "Try again", - "redeemConflictFallback": "You are already in another account. Sign in with a different email to join this one.", - "redeemFailedFallback": "Failed to accept invitation", - "redeemNetworkError": "Could not reach the server", - "signOutError": "Could not sign out. Try refreshing the page.", - "welcomeToast": "Welcome to the team", - "fail": { - "notFound": { - "title": "Invite not found", - "body": "This link doesn't match a valid invitation. Double-check the URL or ask the person who invited you to send a new one." - }, - "used": { - "title": "Invite already used", - "body": "This invitation has already been accepted. If that wasn't you, ask the account admin to send a fresh link." - }, - "expired": { - "title": "Invite expired", - "body": "This invitation has expired. Ask the account admin to send a new one — they take a few seconds to generate." - }, - "serverError": { - "title": "Something went wrong", - "body": "We couldn't verify this invitation right now. Try refreshing the page in a moment." - } - } - }, - "localeSwitcher": { - "label": "Language", - "ariaLabel": "Change language", - "locales": { - "en": "English", - "es": "Español", - "lt": "Lietuvių" - } - } -} diff --git a/next.config.ts b/next.config.ts index 05e1db0..02bd16f 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,9 +1,5 @@ -import path from "node:path"; -import createNextIntlPlugin from "next-intl/plugin"; import type { NextConfig } from "next"; -const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts"); - /** * Baseline security headers applied to every response. * @@ -58,20 +54,6 @@ const SECURITY_HEADERS = [ ] as const; const nextConfig: NextConfig = { - // Pin file-tracing to this directory so Next.js doesn't ascend to the - // parent GHWebhosting folder (which has its own lockfile) and either - // bundle the wrong stuff or skip ours. Was visible as a workspace-root - // warning during builds. Also see `outputFileTracingIncludes` below — - // a wrong root makes the includes match incorrectly. - outputFileTracingRoot: path.join(__dirname), - // Force the production artifact to include the i18n message dictionaries. - // `src/i18n/request.ts` loads them via a static import map but the - // tracer can still miss JSON-only files that no code statically - // imports relative to this entry point. Belt-and-suspenders. - outputFileTracingIncludes: { - "/**/*": ["./messages/**/*.json"], - }, - /** * Cache-Control policy. * @@ -145,4 +127,4 @@ const nextConfig: NextConfig = { }, }; -export default withNextIntl(nextConfig); +export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 70a16ec..fc3eb84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,6 @@ "date-fns": "^4.3.0", "lucide-react": "^1.16.0", "next": "16.2.6", - "next-intl": "^4.13.0", "react": "19.2.4", "react-dom": "19.2.4", "recharts": "^3.8.1", @@ -45,7 +44,7 @@ "vitest": "^4.1.7" }, "engines": { - "node": ">=20.10.0" + "node": ">=20.0.0" } }, "node_modules/@alloc/quick-lru": { @@ -1016,36 +1015,6 @@ "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, - "node_modules/@formatjs/fast-memoize": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.5.tgz", - "integrity": "sha512-KLi3fan6WnCHmigd9pmEEN8Hid0v4wiFBW576M/d07KMWYecf1CvyMI3n34vCmHT4AoVqG2n702kiHbXjzZX2A==", - "license": "MIT" - }, - "node_modules/@formatjs/icu-messageformat-parser": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.10.tgz", - "integrity": "sha512-XeJihYLy1lCe19xfK1KWKG/betBOK2rB0luL8lSkjfvJj0zP+LTJvkC+RKd0jsFI8mWxN71LrarHSrEXE8xxOQ==", - "license": "MIT", - "dependencies": { - "@formatjs/icu-skeleton-parser": "2.1.9" - } - }, - "node_modules/@formatjs/icu-skeleton-parser": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.9.tgz", - "integrity": "sha512-rsxswgHMfU1zUgB2byc08fesf83wLGjFnzLCEtuf00mx2doiqc6pYrf67raI37XqdRcGUviQepk2UKGqpng74Q==", - "license": "MIT" - }, - "node_modules/@formatjs/intl-localematcher": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.9.tgz", - "integrity": "sha512-GmB0F/gYh4Hdl4rLWjgDsgT+x4pB54fkJeRh8kAZ4XFzKeCK8dGs+SBJWXO42QZtOUni+IDWKNuCw6wiL4lTvw==", - "license": "MIT", - "dependencies": { - "@formatjs/fast-memoize": "3.1.5" - } - }, "node_modules/@hono/node-server": { "version": "1.19.14", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", @@ -2056,313 +2025,6 @@ "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@parcel/watcher": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", - "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.6", - "@parcel/watcher-darwin-arm64": "2.5.6", - "@parcel/watcher-darwin-x64": "2.5.6", - "@parcel/watcher-freebsd-x64": "2.5.6", - "@parcel/watcher-linux-arm-glibc": "2.5.6", - "@parcel/watcher-linux-arm-musl": "2.5.6", - "@parcel/watcher-linux-arm64-glibc": "2.5.6", - "@parcel/watcher-linux-arm64-musl": "2.5.6", - "@parcel/watcher-linux-x64-glibc": "2.5.6", - "@parcel/watcher-linux-x64-musl": "2.5.6", - "@parcel/watcher-win32-arm64": "2.5.6", - "@parcel/watcher-win32-ia32": "2.5.6", - "@parcel/watcher-win32-x64": "2.5.6" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", - "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", - "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", - "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", - "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", - "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", - "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", - "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", - "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", - "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", - "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", - "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", - "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", - "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@reduxjs/toolkit": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", @@ -2689,12 +2351,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@schummar/icu-type-parser": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz", - "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", - "license": "MIT" - }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -2834,222 +2490,15 @@ "node": ">=20.0.0" } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.40.tgz", - "integrity": "sha512-PaYyclfmQ++77D8ityYvmmVzHv9aG8ROwt2GfG6/ccloy4Hgf80qtOnzb9VYvPsUT7Ty1uhuDRhv3XYpf62qhQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.40.tgz", - "integrity": "sha512-HbbPzvfLBUXjIB1Ezks+//lNUjmLjfyd63XSwprJgrZaXYdm70kohXPJUWdqKZozolFxbPaO+xtBaiUp6BoueA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.40.tgz", - "integrity": "sha512-SlRZsCjOCPR2LvFs0Ri/Xrx/5o5TCt8vl4gW6mX1hEZOG0a625RxzRHpHdAQNGykmAN/7IeaFAJG+QnNmxlHcA==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.40.tgz", - "integrity": "sha512-Q8byxJt2fh8CR3EUX6snBpy47AoBVm+In/+Z3rjDHMjC38ZvR9/gtUUNCT0tfrn4EdVsO8/QPi59nxrxvqxvBQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.40.tgz", - "integrity": "sha512-4z0MgHU+7M0pZDqBN1El7mFXDI1SBwinfcUkAyA4v8QrhOIUOZltySt2aStQLZGrdXVXM4Y4ylfiTC04ED+MoQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-ppc64-gnu": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.40.tgz", - "integrity": "sha512-fLI4iUgeSZu0eRWUXwe6YzPFx9gHbFiPkl8Rp3mJfP8OpNR3nTQCGPvHdDh9xniW7mVvgMY4ni7A4VzqI1KrpA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-s390x-gnu": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.40.tgz", - "integrity": "sha512-YqeKMAb7d4nQSGMJQ454IlaCENpzcDqhvBE9+CPfdnYpnUXxd+BSrB6Xk0YjW8UyoEhUj4p6quATCxbsp6J3jg==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.40.tgz", - "integrity": "sha512-7HOuS1iGcme/j/TuL1TfmmLGiMQrjv/GmjyZeydl00FKPtpGXEldwqfI56xgd1YzrzoB2svWjxbGGyQ0TEASxg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.40.tgz", - "integrity": "sha512-h4kZYHc7dpc9P9u4brRJaS8Pl7tPVHAeiLSzw7T5RfIJgAoSdaCMKzI/2Uay9gFhaw8uyCDl0L5q37r0EpAfIA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.40.tgz", - "integrity": "sha512-+mQgKZXSj6mV38Zh05QaxSjUDmGP/R2JWlXZTDLSPkDzHU6p3GxN9eeSf5dfyDVU86946fmCvSzyl/ucImx8+A==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.40.tgz", - "integrity": "sha512-yvwdPLGd25mcj/mNatjNQ0lZujtQD6psH3v9PNmMb+fSzjbNG8KIDxjFWrcV+fsFVLOkyOmdJsFmX7NAFjVyPw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.40.tgz", - "integrity": "sha512-OXtKsLU1bVtInzzDEAY2sYiF/rl4tvAnLLLpuMp3HzAOQZ5A+i69AKDhA1YLQTaMAqO3vzyYNVAYVRMPtSYD4w==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "license": "Apache-2.0" - }, "node_modules/@swc/helpers": { - "version": "0.5.23", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", - "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" } }, - "node_modules/@swc/types": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", - "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3" - } - }, "node_modules/@tailwindcss/node": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", @@ -5684,6 +5133,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -7310,21 +6760,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/icu-minify": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.13.0.tgz", - "integrity": "sha512-SIFMeUHZJjzS5RvIGvybKvWoHjDm9cGVEs2EpJ8PmywOdJLWyblPm7TdPLLoUtkJtwQD7iGhl2WMptZ+N0on+w==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/amannn" - } - ], - "license": "MIT", - "dependencies": { - "@formatjs/icu-messageformat-parser": "^3.4.0" - } - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -7400,16 +6835,6 @@ "node": ">=12" } }, - "node_modules/intl-messageformat": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.7.tgz", - "integrity": "sha512-+q6Ktg119nULZEpZ8YTuGOst9MyEzFtjD63FTGBlN1mLz0Z/MOUYDIvnpVKwq17eezIEh+cfJIebfJoCetpiNw==", - "license": "BSD-3-Clause", - "dependencies": { - "@formatjs/fast-memoize": "3.1.5", - "@formatjs/icu-messageformat-parser": "3.5.10" - } - }, "node_modules/ip-address": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", @@ -8877,89 +8302,6 @@ } } }, - "node_modules/next-intl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.13.0.tgz", - "integrity": "sha512-OvNq2v5XLx4EkQOsAhVE9g+6zdb83XHusADCXXtIW4LILYnjEVaeINdr1lkVWKSjzwNUiMSlH5N4K0OQTRiv6A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/amannn" - } - ], - "license": "MIT", - "dependencies": { - "@formatjs/intl-localematcher": "^0.8.1", - "@parcel/watcher": "^2.4.1", - "@swc/core": "^1.15.2", - "icu-minify": "^4.13.0", - "negotiator": "^1.0.0", - "next-intl-swc-plugin-extractor": "^4.13.0", - "po-parser": "^2.1.1", - "use-intl": "^4.13.0" - }, - "peerDependencies": { - "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/next-intl-swc-plugin-extractor": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.13.0.tgz", - "integrity": "sha512-6S/fJI0KXvLCL8nhBo9P8eGaJPzmwJBTCzX0NaUIj0VyU8U89d//T+vjMLdNIXl5MlLaYH7B9MbAjb8Mvu+tqQ==", - "license": "MIT" - }, - "node_modules/next-intl/node_modules/@swc/core": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.40.tgz", - "integrity": "sha512-2kwzJikRvgtNAG7MwVZY2vEzZjTxKIq5jXOihuSV/8U+Hej8Va22t65aKnJZs3P+NwojZvR8Mf8kyM7O+V8sQg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.26" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.40", - "@swc/core-darwin-x64": "1.15.40", - "@swc/core-linux-arm-gnueabihf": "1.15.40", - "@swc/core-linux-arm64-gnu": "1.15.40", - "@swc/core-linux-arm64-musl": "1.15.40", - "@swc/core-linux-ppc64-gnu": "1.15.40", - "@swc/core-linux-s390x-gnu": "1.15.40", - "@swc/core-linux-x64-gnu": "1.15.40", - "@swc/core-linux-x64-musl": "1.15.40", - "@swc/core-win32-arm64-msvc": "1.15.40", - "@swc/core-win32-ia32-msvc": "1.15.40", - "@swc/core-win32-x64-msvc": "1.15.40" - }, - "peerDependencies": { - "@swc/helpers": ">=0.5.17" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" - }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -9480,12 +8822,6 @@ "node": ">=16.20.0" } }, - "node_modules/po-parser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz", - "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==", - "license": "MIT" - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -11466,27 +10802,6 @@ "punycode": "^2.1.0" } }, - "node_modules/use-intl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.13.0.tgz", - "integrity": "sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/amannn" - } - ], - "license": "MIT", - "dependencies": { - "@formatjs/fast-memoize": "^3.1.0", - "@schummar/icu-type-parser": "1.21.5", - "icu-minify": "^4.13.0", - "intl-messageformat": "^11.1.0" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" - } - }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", diff --git a/package.json b/package.json index 88b662c..a0d863b 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "template" ], "engines": { - "node": ">=20.10.0" + "node": ">=20.0.0" }, "scripts": { "dev": "next dev", @@ -52,7 +52,6 @@ "date-fns": "^4.3.0", "lucide-react": "^1.16.0", "next": "16.2.6", - "next-intl": "^4.13.0", "react": "19.2.4", "react-dom": "19.2.4", "recharts": "^3.8.1", @@ -78,7 +77,6 @@ "postcss": "^8.5.10", "ip-address": "^10.1.1", "fast-uri": "^3.1.2", - "hono": "^4.12.18", - "@swc/helpers": "^0.5.17" + "hono": "^4.12.18" } } diff --git a/src/app/[locale]/(auth)/forgot-password/page.tsx b/src/app/(auth)/forgot-password/page.tsx similarity index 85% rename from src/app/[locale]/(auth)/forgot-password/page.tsx rename to src/app/(auth)/forgot-password/page.tsx index b0c10f6..02ff209 100644 --- a/src/app/[locale]/(auth)/forgot-password/page.tsx +++ b/src/app/(auth)/forgot-password/page.tsx @@ -1,8 +1,7 @@ "use client"; import { useState } from "react"; -import { useTranslations } from "next-intl"; -import { Link } from "@/i18n/navigation"; +import Link from "next/link"; import { createClient } from "@/lib/supabase/client"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -17,7 +16,6 @@ import { import { MessageSquare, CheckCircle, ArrowLeft } from "lucide-react"; export default function ForgotPasswordPage() { - const t = useTranslations("auth.forgotPassword"); const [email, setEmail] = useState(""); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); @@ -52,15 +50,12 @@ export default function ForgotPasswordPage() { - {t("checkEmailTitle")} + Check your email - {t.rich("checkEmailBody", { - email, - highlight: (chunks) => ( - {chunks} - ), - })} + We've sent a password reset link to{" "} + {email}. Please check your + inbox. @@ -69,7 +64,7 @@ export default function ForgotPasswordPage() { variant="outline" className="w-full border-slate-700 text-slate-300 hover:bg-slate-800 hover:text-white" > - {t("backToSignIn")} + Back to sign in @@ -85,9 +80,9 @@ export default function ForgotPasswordPage() {
- {t("title")} + Reset password - {t("subtitle")} + Enter your email and we'll send you a reset link @@ -100,12 +95,12 @@ export default function ForgotPasswordPage() {
setEmail(e.target.value)} required @@ -118,7 +113,7 @@ export default function ForgotPasswordPage() { disabled={loading} className="mt-2 h-10 w-full bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50" > - {loading ? t("submitting") : t("submit")} + {loading ? "Sending..." : "Send reset link"} @@ -127,7 +122,7 @@ export default function ForgotPasswordPage() { className="mt-6 flex items-center justify-center gap-2 text-sm text-slate-400 hover:text-slate-300" > - {t("backToSignIn")} + Back to sign in diff --git a/src/app/[locale]/(auth)/layout.tsx b/src/app/(auth)/layout.tsx similarity index 100% rename from src/app/[locale]/(auth)/layout.tsx rename to src/app/(auth)/layout.tsx diff --git a/src/app/[locale]/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx similarity index 88% rename from src/app/[locale]/(auth)/login/page.tsx rename to src/app/(auth)/login/page.tsx index ac25695..1a53226 100644 --- a/src/app/[locale]/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,9 +1,8 @@ "use client"; import { Suspense, useState } from "react"; -import { useSearchParams } from "next/navigation"; -import { useTranslations } from "next-intl"; -import { Link, useRouter } from "@/i18n/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; +import Link from "next/link"; import { createClient } from "@/lib/supabase/client"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -31,7 +30,6 @@ export default function LoginPage() { } function LoginPageInner() { - const t = useTranslations("auth.login"); const searchParams = useSearchParams(); // Forwarded from `/join/` when the visitor already has an // account. After a successful sign-in we send them to the join @@ -80,10 +78,12 @@ function LoginPageInner() { )}
- {inviteToken ? t("titleInvite") : t("title")} + {inviteToken ? "Sign in to accept" : "Welcome back"} - {inviteToken ? t("subtitleInvite") : t("subtitle")} + {inviteToken + ? "Sign in and we'll take you to the invitation." + : "Sign in to your account"} @@ -96,12 +96,12 @@ function LoginPageInner() {
setEmail(e.target.value)} required @@ -112,19 +112,19 @@ function LoginPageInner() {
- {t("forgotPassword")} + Forgot password?
setPassword(e.target.value)} required @@ -137,12 +137,12 @@ function LoginPageInner() { disabled={loading} className="mt-2 h-10 w-full bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50" > - {loading ? t("submitting") : t("submit")} + {loading ? "Signing in..." : "Sign in"}

- {t("noAccount")}{" "} + Don't have an account?{" "} - {t("createAccount")} + Create account

diff --git a/src/app/[locale]/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx similarity index 87% rename from src/app/[locale]/(auth)/signup/page.tsx rename to src/app/(auth)/signup/page.tsx index 875ab4a..c431fe9 100644 --- a/src/app/[locale]/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -1,9 +1,8 @@ "use client"; import { Suspense, useState } from "react"; +import Link from "next/link"; import { useSearchParams } from "next/navigation"; -import { useTranslations } from "next-intl"; -import { Link } from "@/i18n/navigation"; import { createClient } from "@/lib/supabase/client"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -28,7 +27,6 @@ export default function SignupPage() { } function SignupPageInner() { - const t = useTranslations("auth.signup"); const searchParams = useSearchParams(); // When the user lands here from `/join/` we carry the // invite token in the query so it survives the signup → email @@ -51,12 +49,12 @@ function SignupPageInner() { setError(null); if (password !== confirmPassword) { - setError(t("passwordMismatch")); + setError("Passwords do not match"); return; } if (password.length < 6) { - setError(t("passwordTooShort")); + setError("Password must be at least 6 characters"); return; } @@ -100,15 +98,12 @@ function SignupPageInner() {
- {t("checkEmailTitle")} + Check your email - {t.rich("checkEmailBody", { - email, - highlight: (chunks) => ( - {chunks} - ), - })} + We've sent a confirmation link to{" "} + {email}. Please check your + inbox and click the link to verify your account. @@ -123,7 +118,7 @@ function SignupPageInner() { variant="outline" className="w-full border-slate-700 text-slate-300 hover:bg-slate-800 hover:text-white" > - {t("backToSignIn")} + Back to sign in @@ -144,10 +139,12 @@ function SignupPageInner() { )}
- {inviteToken ? t("titleInvite") : t("title")} + {inviteToken ? "Create account & join" : "Create account"} - {inviteToken ? t("subtitleInvite") : t("subtitle")} + {inviteToken + ? "Verify your email, then accept the invitation to join your team." + : "Get started with CRM Template for WhatsApp"} @@ -160,12 +157,12 @@ function SignupPageInner() {
setFullName(e.target.value)} required @@ -175,12 +172,12 @@ function SignupPageInner() {
setEmail(e.target.value)} required @@ -190,12 +187,12 @@ function SignupPageInner() {
setPassword(e.target.value)} required @@ -205,12 +202,12 @@ function SignupPageInner() {
setConfirmPassword(e.target.value)} required @@ -223,12 +220,12 @@ function SignupPageInner() { disabled={loading} className="mt-2 h-10 w-full bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50" > - {loading ? t("submitting") : t("submit")} + {loading ? "Creating account..." : "Create account"}

- {t("haveAccount")}{" "} + Already have an account?{" "} - {t("signIn")} + Sign in

diff --git a/src/app/[locale]/(dashboard)/automations/[id]/edit/page.tsx b/src/app/(dashboard)/automations/[id]/edit/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/automations/[id]/edit/page.tsx rename to src/app/(dashboard)/automations/[id]/edit/page.tsx diff --git a/src/app/[locale]/(dashboard)/automations/[id]/logs/page.tsx b/src/app/(dashboard)/automations/[id]/logs/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/automations/[id]/logs/page.tsx rename to src/app/(dashboard)/automations/[id]/logs/page.tsx diff --git a/src/app/[locale]/(dashboard)/automations/new/page.tsx b/src/app/(dashboard)/automations/new/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/automations/new/page.tsx rename to src/app/(dashboard)/automations/new/page.tsx diff --git a/src/app/[locale]/(dashboard)/automations/page.tsx b/src/app/(dashboard)/automations/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/automations/page.tsx rename to src/app/(dashboard)/automations/page.tsx diff --git a/src/app/[locale]/(dashboard)/broadcasts/[id]/page.tsx b/src/app/(dashboard)/broadcasts/[id]/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/broadcasts/[id]/page.tsx rename to src/app/(dashboard)/broadcasts/[id]/page.tsx diff --git a/src/app/[locale]/(dashboard)/broadcasts/new/page.tsx b/src/app/(dashboard)/broadcasts/new/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/broadcasts/new/page.tsx rename to src/app/(dashboard)/broadcasts/new/page.tsx diff --git a/src/app/[locale]/(dashboard)/broadcasts/page.tsx b/src/app/(dashboard)/broadcasts/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/broadcasts/page.tsx rename to src/app/(dashboard)/broadcasts/page.tsx diff --git a/src/app/[locale]/(dashboard)/contacts/page.tsx b/src/app/(dashboard)/contacts/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/contacts/page.tsx rename to src/app/(dashboard)/contacts/page.tsx diff --git a/src/app/[locale]/(dashboard)/dashboard-shell.tsx b/src/app/(dashboard)/dashboard-shell.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/dashboard-shell.tsx rename to src/app/(dashboard)/dashboard-shell.tsx diff --git a/src/app/[locale]/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/dashboard/page.tsx rename to src/app/(dashboard)/dashboard/page.tsx diff --git a/src/app/[locale]/(dashboard)/flows/[id]/page.tsx b/src/app/(dashboard)/flows/[id]/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/flows/[id]/page.tsx rename to src/app/(dashboard)/flows/[id]/page.tsx diff --git a/src/app/[locale]/(dashboard)/flows/[id]/runs/page.tsx b/src/app/(dashboard)/flows/[id]/runs/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/flows/[id]/runs/page.tsx rename to src/app/(dashboard)/flows/[id]/runs/page.tsx diff --git a/src/app/[locale]/(dashboard)/flows/page.tsx b/src/app/(dashboard)/flows/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/flows/page.tsx rename to src/app/(dashboard)/flows/page.tsx diff --git a/src/app/[locale]/(dashboard)/inbox/page.tsx b/src/app/(dashboard)/inbox/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/inbox/page.tsx rename to src/app/(dashboard)/inbox/page.tsx diff --git a/src/app/[locale]/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/layout.tsx rename to src/app/(dashboard)/layout.tsx diff --git a/src/app/[locale]/(dashboard)/pipelines/page.tsx b/src/app/(dashboard)/pipelines/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/pipelines/page.tsx rename to src/app/(dashboard)/pipelines/page.tsx diff --git a/src/app/[locale]/(dashboard)/settings/page.tsx b/src/app/(dashboard)/settings/page.tsx similarity index 100% rename from src/app/[locale]/(dashboard)/settings/page.tsx rename to src/app/(dashboard)/settings/page.tsx diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx deleted file mode 100644 index b262e23..0000000 --- a/src/app/[locale]/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { redirect } from "@/i18n/navigation"; - -export default async function RootPage({ - params, -}: { - params: Promise<{ locale: string }>; -}) { - const { locale } = await params; - redirect({ href: "/dashboard", locale }); -} diff --git a/src/app/[locale]/join/[token]/page.tsx b/src/app/join/[token]/page.tsx similarity index 81% rename from src/app/[locale]/join/[token]/page.tsx rename to src/app/join/[token]/page.tsx index 5fdc4ee..4767505 100644 --- a/src/app/[locale]/join/[token]/page.tsx +++ b/src/app/join/[token]/page.tsx @@ -23,9 +23,8 @@ // ============================================================ import { useCallback, useEffect, useState } from 'react'; +import Link from 'next/link'; import { useParams } from 'next/navigation'; -import { useTranslations } from 'next-intl'; -import { Link } from '@/i18n/navigation'; import { toast } from 'sonner'; import { AlertTriangle, @@ -66,16 +65,32 @@ interface PeekFail { } type PeekResult = PeekOk | PeekFail; -const FAIL_REASON_KEY: Record = { - not_found: 'notFound', - used: 'used', - expired: 'expired', - server_error: 'serverError', +const ROLE_LABEL: Record = { + admin: 'Admin', + agent: 'Agent', + viewer: 'Viewer', +}; + +const FAIL_COPY: Record = { + not_found: { + title: 'Invite not found', + body: 'This link doesn’t match a valid invitation. Double-check the URL or ask the person who invited you to send a new one.', + }, + used: { + title: 'Invite already used', + body: 'This invitation has already been accepted. If that wasn’t you, ask the account admin to send a fresh link.', + }, + expired: { + title: 'Invite expired', + body: 'This invitation has expired. Ask the account admin to send a new one — they take a few seconds to generate.', + }, + server_error: { + title: 'Something went wrong', + body: 'We couldn’t verify this invitation right now. Try refreshing the page in a moment.', + }, }; export default function JoinPage() { - const t = useTranslations('join'); - const tRoles = useTranslations('roles'); const params = useParams<{ token: string }>(); const token = params?.token; @@ -167,24 +182,25 @@ export default function JoinPage() { // rather than a 3-second toast. if (res.status === 409) { setConflictMessage( - payload.error || t('redeemConflictFallback'), + payload.error || + 'You are already in another account. Sign in with a different email to join this one.', ); } else { - toast.error(payload.error || t('redeemFailedFallback')); + toast.error(payload.error || 'Failed to accept invitation'); } setAccepting(false); return; } - toast.success(t('welcomeToast')); + toast.success('Welcome to the team'); // Full reload (not router.push) so AuthProvider re-fetches // the profile with the new account_id and account_role. window.location.href = '/dashboard'; } catch (err) { console.error('[join] redeem error:', err); - toast.error(t('redeemNetworkError')); + toast.error('Could not reach the server'); setAccepting(false); } - }, [token, t]); + }, [token]); const handleSignOutAndRetry = useCallback(async () => { setSigningOut(true); @@ -196,10 +212,10 @@ export default function JoinPage() { window.location.reload(); } catch (err) { console.error('[join] sign-out error:', err); - toast.error(t('signOutError')); + toast.error('Could not sign out. Try refreshing the page.'); setSigningOut(false); } - }, [t]); + }, []); // ----- Loading state (peek pending OR auth not yet resolved) ----- if (peek === null || authedUserId === undefined) { @@ -207,7 +223,7 @@ export default function JoinPage() { -

{t('verifying')}

+

Verifying invitation…

); @@ -215,18 +231,16 @@ export default function JoinPage() { // ----- Peek failed ----- if (!peek.ok) { - const reasonKey = FAIL_REASON_KEY[peek.reason]; + const copy = FAIL_COPY[peek.reason]; return (
- - {t(`fail.${reasonKey}.title`)} - + {copy.title} - {t(`fail.${reasonKey}.body`)} + {copy.body}
@@ -243,14 +257,14 @@ export default function JoinPage() { onClick={loadPeekAndAuth} className="w-full bg-primary text-primary-foreground hover:bg-primary/90" > - {t('tryAgain')} + Try again @@ -258,7 +272,7 @@ export default function JoinPage() { <> @@ -266,7 +280,7 @@ export default function JoinPage() { variant="outline" className="w-full border-slate-700 text-slate-300 hover:bg-slate-800 hover:text-white" > - {t('signIn')} + Sign in @@ -283,21 +297,22 @@ export default function JoinPage() {
- {t.rich('invitedToTitle', { - accountName: peek.account_name, - highlight: (chunks) => {chunks}, - })} + You're invited to{' '} + {peek.account_name} - {t.rich('invitedAs', { - role: () => ( - - - {tRoles(peek.role)} - - ), - date: new Date(peek.expires_at), + You'll join as{' '} + + + {ROLE_LABEL[peek.role]} + + . Link valid until{' '} + {new Date(peek.expires_at).toLocaleDateString(undefined, { + year: 'numeric', + month: 'short', + day: 'numeric', })} + . ); @@ -317,22 +332,19 @@ export default function JoinPage() { {accepting ? ( <> - {t('accepting')} + Accepting… ) : ( <> - {t('acceptInvitation')} + Accept invitation )}

- {t.rich('acceptFooter', { - accountName: peek.account_name, - highlight: (chunks) => ( - {chunks} - ), - })} + Accepting moves your login into{' '} + {peek.account_name}. Your + empty personal account from signup will be cleaned up.

@@ -351,7 +363,7 @@ export default function JoinPage() { - {t('conflictTitle', { accountName: peek.account_name })} + Can't join {peek.account_name} with this account {conflictMessage} @@ -359,12 +371,11 @@ export default function JoinPage() {

- {t.rich('conflictBody', { - accountName: peek.account_name, - highlight: (chunks) => ( - {chunks} - ), - })} + To join{' '} + {peek.account_name}, + sign out and sign up again with a different email address. + The invite link stays valid as long as it hasn't + expired.

@@ -373,7 +384,7 @@ export default function JoinPage() { onClick={() => setConflictMessage(null)} className="border-slate-700 text-slate-300 hover:bg-slate-800" > - {t('staySignedIn')} + Stay signed in @@ -403,7 +414,7 @@ export default function JoinPage() { @@ -411,7 +422,7 @@ export default function JoinPage() { variant="outline" className="w-full border-slate-700 text-slate-300 hover:bg-slate-800 hover:text-white" > - {t('alreadyHaveAccount')} + I already have an account diff --git a/src/app/[locale]/join/layout.tsx b/src/app/join/layout.tsx similarity index 100% rename from src/app/[locale]/join/layout.tsx rename to src/app/join/layout.tsx diff --git a/src/app/[locale]/layout.tsx b/src/app/layout.tsx similarity index 65% rename from src/app/[locale]/layout.tsx rename to src/app/layout.tsx index 8121180..0956aa5 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/layout.tsx @@ -1,13 +1,9 @@ import type { Metadata, Viewport } from "next"; -import { hasLocale, NextIntlClientProvider } from "next-intl"; -import { setRequestLocale } from "next-intl/server"; import { Inter } from "next/font/google"; -import { notFound } from "next/navigation"; import Script from "next/script"; import { Toaster } from "sonner"; -import "../globals.css"; +import "./globals.css"; import { ThemeProvider } from "@/hooks/use-theme"; -import { routing } from "@/i18n/routing"; import { DEFAULT_THEME, STORAGE_KEY, THEME_IDS } from "@/lib/themes"; const inter = Inter({ @@ -44,6 +40,11 @@ export const viewport: Viewport = { // chosen theme is on the element before first paint. Without // this every page load flashes the default Violet for a frame before // the React tree mounts and applies the picked theme. +// +// Kept dependency-free (no imports, no JSX) — must be a string the +// browser can run as a single