diff --git a/apps/web/app/[locale]/home/[account]/layout.tsx b/apps/web/app/[locale]/home/[account]/layout.tsx index 3ce320f9d..b487eefca 100644 --- a/apps/web/app/[locale]/home/[account]/layout.tsx +++ b/apps/web/app/[locale]/home/[account]/layout.tsx @@ -54,8 +54,6 @@ async function SidebarLayout({ image: picture_url, })); - console.log(state); - return ( diff --git a/apps/web/content/documentation/getting-started/configuration.mdoc b/apps/web/content/documentation/getting-started/configuration.mdoc index 0afaae10f..4ece7c014 100644 --- a/apps/web/content/documentation/getting-started/configuration.mdoc +++ b/apps/web/content/documentation/getting-started/configuration.mdoc @@ -103,13 +103,13 @@ import { HomeIcon, SettingsIcon } from 'lucide-react'; export default [ { - label: 'common:routes.home', + label: 'common.routes.home', path: pathsConfig.app.personalAccount, Icon: , end: true, }, { - label: 'common:routes.settings', + label: 'common.routes.settings', path: pathsConfig.app.settings, Icon: , }, @@ -122,18 +122,18 @@ export default [ // config/team-account-navigation.config.tsx export default [ { - label: 'common:routes.dashboard', + label: 'common.routes.dashboard', path: createPath(pathsConfig.app.teamAccount, account), Icon: , end: true, }, { - label: 'common:routes.projects', + label: 'common.routes.projects', path: createPath(pathsConfig.app.projects, account), Icon: , }, { - label: 'common:routes.members', + label: 'common.routes.members', path: createPath(pathsConfig.app.members, account), Icon: , }, diff --git a/apps/web/public/images/dashboard.webp b/apps/web/public/images/dashboard.webp index 1dafa8ba3..a9a4145c2 100644 Binary files a/apps/web/public/images/dashboard.webp and b/apps/web/public/images/dashboard.webp differ diff --git a/docs/api/policies-api.mdoc b/docs/api/policies-api.mdoc index 6ac281841..817d97dbe 100644 --- a/docs/api/policies-api.mdoc +++ b/docs/api/policies-api.mdoc @@ -444,17 +444,17 @@ async function validateEnterpriseFeatureAccess(context: FeatureContext) { policies: [ createPolicy(async (ctx) => ctx.subscription?.plan === 'enterprise' && ctx.subscription.active - ? allow({ billing: 'enterprise-subscription' }) + ? allow({ billing. 'enterprise-subscription' }) : deny('Enterprise subscription required') ), createPolicy(async (ctx) => ctx.trial?.type === 'enterprise' && ctx.trial.daysRemaining > 0 - ? allow({ billing: 'enterprise-trial', daysLeft: ctx.trial.daysRemaining }) + ? allow({ billing. 'enterprise-trial', daysLeft: ctx.trial.daysRemaining }) : deny('Active enterprise trial required') ), createPolicy(async (ctx) => ctx.adminOverride?.enabled && ctx.user.role === 'super-admin' - ? allow({ billing: 'admin-override' }) + ? allow({ billing. 'admin-override' }) : deny('Admin override not available') ), ], diff --git a/docs/installation/v3-migration.mdoc b/docs/installation/v3-migration.mdoc index 2f64838c3..157e0f534 100644 --- a/docs/installation/v3-migration.mdoc +++ b/docs/installation/v3-migration.mdoc @@ -6,6 +6,8 @@ order: 9 description: "A guide to updating this kit from v2 to v3 using git and AI Agents" --- +The source for this page is available at `docs/installation/v3-migration.mdoc`. You can reference this file to AI agents for automatic migrations. + v3 is a major upgrade that modernizes the entire stack: - **Zod v4** — faster validation, smaller bundle, cleaner API @@ -85,6 +87,12 @@ Each step is tagged so you can merge incrementally: | 9 | `v3-step/remove-edge-csrf` | Drops CSRF middleware in favor of Server Actions | | 10 | `v3-step/final` | Centralizes dependency versions | +After merging the last tag (`v3-step/final`), merge the latest `main` to pick up any fixes and improvements released after the migration tags: + +```bash +git pull upstream main +``` + ### Before starting the migration Please make sure your `main` branch is up to date with the branch `v2`. Also, @@ -412,6 +420,30 @@ If you used Radix primitives directly, these sub-components were renamed: Base UI also introduces a **Positioner** wrapper for floating components (Popover, Tooltip, Select, DropdownMenu). Props like `align`, `side`, `sideOffset` move from `Content`/`Popup` to the `Positioner`. +### AlertDialog inside Dropdowns + +Base UI does not support nesting an `AlertDialog` trigger around a `DropdownMenuItem`. If you have an `AlertDialogTrigger` wrapping a dropdown item, remove the trigger and instead control the dialog with state, placing it outside the dropdown: + +```diff +- +- +- Delete +- +- ... +- ++ const [isAlertOpen, setIsAlertOpen] = useState(false); ++ ++ setIsAlertOpen(true)}> ++ Delete ++ ++ ++ ++ ... ++ +``` + +Use `useState` to control `open` and `onOpenChange` on the `AlertDialog`, and trigger it from the dropdown item's `onClick` handler. Note: Base UI uses `onClick` instead of Radix's `onSelect` on menu items. + ### Sidebar Import Path Change The shadcn sidebar component moved: @@ -457,16 +489,36 @@ The interpolation syntax changed from double to single curly braces: This applies to **every custom translation string** that uses variables. -### withI18n Removal +### i18next API Removal -The `withI18n` higher-order component is removed. If you wrapped page exports -with it, remove the wrapper: +The entire `react-i18next` / `i18next` API surface is removed in v3. This includes: + +- **`withI18n` HOC** — no longer needed. If you wrapped Server Component page exports with it, remove the wrapper: ```diff - export default withI18n(MyPage); + export default MyPage; ``` +- **`useTranslation` hook** — replace with `useTranslations` from `next-intl`: + +```diff +- import { useTranslation } from 'react-i18next'; +- const { t } = useTranslation('namespace'); ++ import { useTranslations } from 'next-intl'; ++ const t = useTranslations('namespace'); +``` + +- **`createI18nServerInstance` / `getTranslation`** — replace with `getTranslations` from `next-intl/server` (see above). + +- **`Trans` component** — now imported from `@kit/ui/trans` (backed by `next-intl`), not from `react-i18next`. The API is the same but key syntax uses dots instead of colons. + +- **`i18next.init` / custom i18n configuration** — replaced by the `next-intl` config in `apps/web/i18n/request.ts`. Remove any custom i18next initialization code. + +- **Custom namespaces** — if you added custom translation namespaces, register them in `apps/web/i18n/request.ts` so `next-intl` can load them. + +- **Custom locales** — if you added custom locales, register them in `packages/i18n/src/locales.tsx`. + ### next.config.mjs Your `next.config.mjs` must be wrapped with `createNextIntlPlugin`: @@ -484,9 +536,14 @@ Without this wrapper, `next-intl` will not work. ### Messages Files -**Message files** moved to `apps/web/i18n/messages/{locale}/`. +**Message files** moved from `apps/web/public/locales/{locale}/` to `apps/web/i18n/messages/{locale}/`. -Please migrate your existing messages to `apps/web/i18n/messages/{locale}/`. +Migrate your custom translation files to the new location: + +```bash +# Example: move English translations +mv apps/web/public/locales/en/* apps/web/i18n/messages/en/ +``` ### Navigation Config diff --git a/docs/recipes/projects-data-model.mdoc b/docs/recipes/projects-data-model.mdoc index ea10824fa..8250b38cc 100644 --- a/docs/recipes/projects-data-model.mdoc +++ b/docs/recipes/projects-data-model.mdoc @@ -2333,13 +2333,13 @@ Let's update the navigation menu to add a new link to the projects page. Update ```tsx {% title="apps/web/config/team-account-navigation.config.tsx" %} {7-11} { - label: 'common:routes.dashboard', + label: 'common.routes.dashboard', path: pathsConfig.app.accountHome.replace('[account]', account), Icon: , end: true, }, { - label: 'common:routes.projects', + label: 'common.routes.projects', path: `/home/${account}/projects`, Icon: , }, diff --git a/docs/recipes/stripe-billing-checkout-addons.mdoc b/docs/recipes/stripe-billing-checkout-addons.mdoc index cdecf4011..edfe8b309 100644 --- a/docs/recipes/stripe-billing-checkout-addons.mdoc +++ b/docs/recipes/stripe-billing-checkout-addons.mdoc @@ -670,19 +670,19 @@ function PlanDetails({ {' '} - / + /

diff --git a/package.json b/package.json index f72a8a738..09041b7db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-supabase-saas-kit-turbo", - "version": "3.0.0", + "version": "3.0.1", "private": true, "author": { "name": "MakerKit", diff --git a/packages/billing/gateway/src/components/pricing-table.tsx b/packages/billing/gateway/src/components/pricing-table.tsx index c82d6b45f..4f3cc6bf3 100644 --- a/packages/billing/gateway/src/components/pricing-table.tsx +++ b/packages/billing/gateway/src/components/pricing-table.tsx @@ -159,7 +159,7 @@ function PricingItem( const lineItem = props.primaryLineItem!; const isCustom = props.plan.custom ?? false; - const i18nKey = `billing.units.${lineItem.unit}` as never; + const i18nKey = lineItem?.unit ? `billing.units.${lineItem.unit}` : ''; const unitLabel = lineItem?.unit ? t.has(i18nKey)