Enhanced Sidebar to support sub collapsible sections (#80)

* Enhanced Sidebar to support sub collapsible sections
* Data-Table: support getSortedRowModel
* Add missing renderAction; 
* Fix Sidebar on mobile
* Do not initialize Analytics Provider server side
* Do not bind i18Next until it's initialized
* Avoid infinite redirects in the auth path when Supabase emits a SIGNED_OUT event
* Force admin layout to be dynamic
This commit is contained in:
Giancarlo Buomprisco
2024-11-06 16:01:45 +01:00
committed by GitHub
parent 27ef8f7510
commit 465655fdd4
18 changed files with 322 additions and 160 deletions

View File

@@ -13,7 +13,7 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.48.2", "@playwright/test": "^1.48.2",
"@types/node": "^22.8.6", "@types/node": "^22.8.7",
"node-html-parser": "^6.1.13" "node-html-parser": "^6.1.13"
} }
} }

View File

@@ -7,6 +7,8 @@ export const metadata = {
title: `Super Admin`, title: `Super Admin`,
}; };
export const dynamic = 'force-dynamic';
export default function AdminLayout(props: React.PropsWithChildren) { export default function AdminLayout(props: React.PropsWithChildren) {
return ( return (
<Page style={'sidebar'}> <Page style={'sidebar'}>

View File

@@ -11,6 +11,7 @@ import {
ConsumerProvidedEventTypes, ConsumerProvidedEventTypes,
useAppEvents, useAppEvents,
} from '@kit/shared/events'; } from '@kit/shared/events';
import { isBrowser } from '@kit/shared/utils';
type AnalyticsMapping< type AnalyticsMapping<
T extends ConsumerProvidedEventTypes = NonNullable<unknown>, T extends ConsumerProvidedEventTypes = NonNullable<unknown>,
@@ -65,10 +66,7 @@ const analyticsMapping: AnalyticsMapping = {
}, },
}; };
/** function AnalyticsProviderBrowser(props: React.PropsWithChildren) {
* Provider for the analytics service
*/
export function AnalyticsProvider(props: React.PropsWithChildren) {
// Subscribe to app events and map them to analytics actions // Subscribe to app events and map them to analytics actions
useAnalyticsMapping(analyticsMapping); useAnalyticsMapping(analyticsMapping);
@@ -79,6 +77,17 @@ export function AnalyticsProvider(props: React.PropsWithChildren) {
return props.children; return props.children;
} }
/**
* Provider for the analytics service
*/
export function AnalyticsProvider(props: React.PropsWithChildren) {
if (!isBrowser()) {
return props.children;
}
return <AnalyticsProviderBrowser>{props.children}</AnalyticsProviderBrowser>;
}
/** /**
* Hook to report page views to the analytics service * Hook to report page views to the analytics service
* @param reportAnalyticsFn * @param reportAnalyticsFn

View File

@@ -79,7 +79,7 @@
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@next/bundle-analyzer": "15.0.2", "@next/bundle-analyzer": "15.0.2",
"@types/mdx": "^2.0.13", "@types/mdx": "^2.0.13",
"@types/node": "^22.8.6", "@types/node": "^22.8.7",
"@types/react": "npm:types-react@19.0.0-rc.1", "@types/react": "npm:types-react@19.0.0-rc.1",
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",

View File

@@ -51,7 +51,7 @@
"@types/react": "npm:types-react@19.0.0-rc.1", "@types/react": "npm:types-react@19.0.0-rc.1",
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
"i18next": "23.16.4", "i18next": "23.16.4",
"react-i18next": "15.1.0" "react-i18next": "^15.1.0"
} }
} }
} }

View File

@@ -17,7 +17,7 @@
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tailwind-config": "workspace:*", "@kit/tailwind-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/node": "^22.8.6" "@types/node": "^22.8.7"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@@ -19,7 +19,7 @@
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/wordpress": "workspace:*", "@kit/wordpress": "workspace:*",
"@types/node": "^22.8.6" "@types/node": "^22.8.7"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@@ -26,7 +26,7 @@
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@types/node": "^22.8.6", "@types/node": "^22.8.7",
"@types/react": "npm:types-react@19.0.0-rc.1", "@types/react": "npm:types-react@19.0.0-rc.1",
"react": "19.0.0-rc-45804af1-20241021", "react": "19.0.0-rc-45804af1-20241021",
"zod": "^3.23.8" "zod": "^3.23.8"

View File

@@ -20,7 +20,7 @@
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@types/node": "^22.8.6", "@types/node": "^22.8.7",
"@types/react": "npm:types-react@19.0.0-rc.1", "@types/react": "npm:types-react@19.0.0-rc.1",
"wp-types": "^4.66.1" "wp-types": "^4.66.1"
}, },

View File

@@ -15,26 +15,52 @@ export async function initializeServerI18n(
const i18nInstance = createInstance(); const i18nInstance = createInstance();
const loadedNamespaces = new Set<string>(); const loadedNamespaces = new Set<string>();
await i18nInstance await new Promise((resolve) => {
.use( void i18nInstance
resourcesToBackend(async (language, namespace, callback) => { .use(
try { resourcesToBackend(async (language, namespace, callback) => {
const data = await resolver(language, namespace); try {
loadedNamespaces.add(namespace); const data = await resolver(language, namespace);
loadedNamespaces.add(namespace);
return callback(null, data); return callback(null, data);
} catch (error) { } catch (error) {
console.log( console.log(
`Error loading i18n file: locales/${language}/${namespace}.json`, `Error loading i18n file: locales/${language}/${namespace}.json`,
error, error,
); );
return callback(null, {}); return callback(null, {});
} }
}), }),
) )
.use(initReactI18next) .use({
.init(settings); type: '3rdParty',
init: async (i18next: typeof i18nInstance) => {
let iterations = 0;
const maxIterations = 100;
// do not bind this to the i18next instance until it's initialized
while (i18next.isInitializing) {
iterations++;
if (iterations > maxIterations) {
console.error(
`i18next is not initialized after ${maxIterations} iterations`,
);
break;
}
await new Promise((resolve) => setTimeout(resolve, 1));
}
initReactI18next.init(i18next);
resolve(i18next);
},
})
.init(settings);
});
const namespaces = settings.ns as string[]; const namespaces = settings.ns as string[];

View File

@@ -19,7 +19,7 @@
"@kit/resend": "workspace:*", "@kit/resend": "workspace:*",
"@kit/tailwind-config": "workspace:*", "@kit/tailwind-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/node": "^22.8.6", "@types/node": "^22.8.7",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"eslintConfig": { "eslintConfig": {

View File

@@ -18,7 +18,7 @@
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tailwind-config": "workspace:*", "@kit/tailwind-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/node": "^22.8.6", "@types/node": "^22.8.7",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"eslintConfig": { "eslintConfig": {

View File

@@ -14,6 +14,12 @@ import { useSupabase } from './use-supabase';
*/ */
const PRIVATE_PATH_PREFIXES = ['/home', '/admin', '/join', '/update-password']; const PRIVATE_PATH_PREFIXES = ['/home', '/admin', '/join', '/update-password'];
/**
* @name AUTH_PATHS
* @description A list of auth paths
*/
const AUTH_PATHS = ['/auth'];
/** /**
* @name useAuthChangeListener * @name useAuthChangeListener
* @param privatePathPrefixes - A list of private path prefixes * @param privatePathPrefixes - A list of private path prefixes
@@ -53,6 +59,12 @@ export function useAuthChangeListener({
// revalidate user session when user signs in or out // revalidate user session when user signs in or out
if (event === 'SIGNED_OUT') { if (event === 'SIGNED_OUT') {
// sometimes Supabase sends SIGNED_OUT event
// but in the auth path, so we ignore it
if (AUTH_PATHS.some((path) => pathName.startsWith(path))) {
return;
}
window.location.reload(); window.location.reload();
} }
}); });

View File

@@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation';
import { import {
flexRender, flexRender,
getCoreRowModel, getCoreRowModel,
getSortedRowModel,
useReactTable, useReactTable,
} from '@tanstack/react-table'; } from '@tanstack/react-table';
import type { import type {
@@ -45,6 +46,8 @@ interface ReactTableProps<T extends object> {
pageSize?: number; pageSize?: number;
pageCount?: number; pageCount?: number;
onPaginationChange?: (pagination: PaginationState) => void; onPaginationChange?: (pagination: PaginationState) => void;
manualPagination?: boolean;
manualSorting?: boolean;
tableProps?: React.ComponentProps<typeof Table> & tableProps?: React.ComponentProps<typeof Table> &
Record<`data-${string}`, string>; Record<`data-${string}`, string>;
} }
@@ -57,6 +60,8 @@ export function DataTable<T extends object>({
pageCount, pageCount,
onPaginationChange, onPaginationChange,
tableProps, tableProps,
manualPagination = true,
manualSorting = false,
}: ReactTableProps<T>) { }: ReactTableProps<T>) {
const [pagination, setPagination] = useState<PaginationState>({ const [pagination, setPagination] = useState<PaginationState>({
pageIndex: pageIndex ?? 0, pageIndex: pageIndex ?? 0,
@@ -74,7 +79,9 @@ export function DataTable<T extends object>({
data, data,
columns, columns,
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
manualPagination: true, getSortedRowModel: getSortedRowModel(),
manualPagination,
manualSorting,
onSortingChange: setSorting, onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters, onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: setColumnVisibility, onColumnVisibilityChange: setColumnVisibility,

View File

@@ -9,25 +9,32 @@ const Divider = z.object({
divider: z.literal(true), divider: z.literal(true),
}); });
const RouteChildren = z.array( const RouteSubChild = z.object({
z.object({ label: z.string(),
label: z.string(), path: z.string(),
path: z.string(), Icon: z.custom<React.ReactNode>().optional(),
Icon: z.custom<React.ReactNode>(), end: RouteMatchingEnd,
end: RouteMatchingEnd, renderAction: z.custom<React.ReactNode>().optional(),
children: z });
.array(
z.object({ const RouteChild = z.object({
label: z.string(), label: z.string(),
path: z.string(), path: z.string(),
Icon: z.custom<React.ReactNode>(), Icon: z.custom<React.ReactNode>().optional(),
end: RouteMatchingEnd, end: RouteMatchingEnd,
}), children: z.array(RouteSubChild).default([]).optional(),
) collapsible: z.boolean().default(false).optional(),
.default([]) collapsed: z.boolean().default(false).optional(),
.optional(), renderAction: z.custom<React.ReactNode>().optional(),
}), });
);
const RouteGroup = z.object({
label: z.string(),
collapsible: z.boolean().optional(),
collapsed: z.boolean().optional(),
children: z.array(RouteChild),
renderAction: z.custom<React.ReactNode>().optional(),
});
export const NavigationConfigSchema = z.object({ export const NavigationConfigSchema = z.object({
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'), style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
@@ -36,16 +43,5 @@ export const NavigationConfigSchema = z.object({
.default('false') .default('false')
.optional() .optional()
.transform((value) => value === `true`), .transform((value) => value === `true`),
routes: z.array( routes: z.array(z.union([RouteGroup, Divider])),
z.union([
z.object({
label: z.string(),
collapsible: z.boolean().optional(),
collapsed: z.boolean().optional(),
children: RouteChildren,
renderAction: z.custom<React.ReactNode>().optional(),
}),
Divider,
]),
),
}); });

View File

@@ -329,16 +329,24 @@ export function SidebarNavigation({
collapsed={item.collapsed} collapsed={item.collapsed}
> >
{item.children.map((child) => { {item.children.map((child) => {
return ( if ('collapsible' in child && child.collapsible) {
<SidebarItem throw new Error(
key={child.path} 'Collapsible groups are not supported in the old Sidebar. Please migrate to the new Sidebar.',
end={child.end} );
path={child.path} }
Icon={child.Icon}
> if ('path' in child) {
<Trans i18nKey={child.label} defaults={child.label} /> return (
</SidebarItem> <SidebarItem
); key={child.path}
end={child.end}
path={child.path}
Icon={child.Icon}
>
<Trans i18nKey={child.label} defaults={child.label} />
</SidebarItem>
);
}
})} })}
</SidebarGroup> </SidebarGroup>
); );

View File

@@ -910,18 +910,96 @@ export function SidebarNavigation({
</SidebarGroupAction> </SidebarGroupAction>
</If> </If>
<ContentContainer> <SidebarGroupContent>
<SidebarGroupContent> <SidebarMenu>
<SidebarMenu> <ContentContainer>
{item.children.map((child) => { {item.children.map((child, childIndex) => {
const isActive = isRouteActive( if (child.renderAction) {
child.path, return (
currentPath, <SidebarMenuSubItem key={child.path}>
child.end, {child.renderAction}
); </SidebarMenuSubItem>
);
}
return ( const Container = (props: React.PropsWithChildren) => {
<SidebarMenuItem key={child.path}> if ('collapsible' in child && child.collapsible) {
return (
<Collapsible
defaultOpen={!child.collapsed}
className={'group/collapsible'}
>
{props.children}
</Collapsible>
);
}
return props.children;
};
const ContentContainer = (
props: React.PropsWithChildren,
) => {
if ('collapsible' in child && child.collapsible) {
return (
<CollapsibleContent>
{props.children}
</CollapsibleContent>
);
}
return props.children;
};
const TriggerItem = () => {
if ('collapsible' in child && child.collapsible) {
return (
<CollapsibleTrigger asChild>
<SidebarMenuButton tooltip={child.label}>
<div
className={cn('flex items-center gap-2', {
'mx-auto w-full gap-0 [&>svg]:flex-1 [&>svg]:shrink-0':
minimized,
})}
>
{child.Icon}
<span
className={cn(
'w-auto transition-opacity duration-300',
{
'w-0 opacity-0': minimized,
},
)}
>
<Trans
i18nKey={child.label}
defaults={child.label}
/>
</span>
<ChevronDown
className={cn(
'ml-auto size-4 transition-transform group-data-[state=open]/collapsible:rotate-180',
{
'hidden size-0': minimized,
},
)}
/>
</div>
</SidebarMenuButton>
</CollapsibleTrigger>
);
}
const path = 'path' in child ? child.path : '';
const end = 'end' in child ? child.end : false;
const isActive = isRouteActive(
path,
currentPath,
end,
);
return (
<SidebarMenuButton <SidebarMenuButton
asChild asChild
isActive={isActive} isActive={isActive}
@@ -932,10 +1010,9 @@ export function SidebarNavigation({
'mx-auto w-full !gap-0 [&>svg]:flex-1': 'mx-auto w-full !gap-0 [&>svg]:flex-1':
minimized, minimized,
})} })}
href={child.path} href={path}
> >
{child.Icon} {child.Icon}
<span <span
className={cn( className={cn(
'w-auto transition-opacity duration-300', 'w-auto transition-opacity duration-300',
@@ -951,61 +1028,86 @@ export function SidebarNavigation({
</span> </span>
</Link> </Link>
</SidebarMenuButton> </SidebarMenuButton>
);
};
<If condition={child.children}> return (
{(children) => ( <Container key={`group-${index}-${childIndex}`}>
<SidebarMenuSub <SidebarMenuItem>
className={cn({ 'mx-0 px-1.5': minimized })} <TriggerItem />
>
{children.map((child) => {
const isActive = isRouteActive(
child.path,
currentPath,
child.end,
);
return ( <ContentContainer>
<SidebarMenuSubItem key={child.path}> <If condition={child.children}>
<SidebarMenuSubButton {(children) => (
isActive={isActive} <SidebarMenuSub
asChild className={cn({
> 'mx-0 px-1.5': minimized,
<Link })}
className={cn('flex items-center', { >
'mx-auto w-full !gap-0 [&>svg]:flex-1': {children.map((child) => {
minimized, if (child.renderAction) {
})} return (
href={child.path} <SidebarMenuSubItem
> key={child.path}
{child.Icon}
<span
className={cn(
'w-auto transition-opacity duration-300',
{
'w-0 opacity-0': minimized,
},
)}
> >
<Trans {child.renderAction}
i18nKey={child.label} </SidebarMenuSubItem>
defaults={child.label} );
/> }
</span>
</Link> const isActive = isRouteActive(
</SidebarMenuSubButton> child.path,
</SidebarMenuSubItem> currentPath,
); child.end,
})} );
</SidebarMenuSub>
)} return (
</If> <SidebarMenuSubItem key={child.path}>
</SidebarMenuItem> <SidebarMenuSubButton
isActive={isActive}
asChild
>
<Link
className={cn(
'flex items-center',
{
'mx-auto w-full !gap-0 [&>svg]:flex-1':
minimized,
},
)}
href={child.path}
>
{child.Icon}
<span
className={cn(
'w-auto transition-opacity duration-300',
{
'w-0 opacity-0':
minimized,
},
)}
>
<Trans
i18nKey={child.label}
defaults={child.label}
/>
</span>
</Link>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
);
})}
</SidebarMenuSub>
)}
</If>
</ContentContainer>
</SidebarMenuItem>
</Container>
); );
})} })}
</SidebarMenu> </ContentContainer>
</SidebarGroupContent> </SidebarMenu>
</ContentContainer> </SidebarGroupContent>
</SidebarGroup> </SidebarGroup>
<If condition={minimized && !isLast}> <If condition={minimized && !isLast}>

48
pnpm-lock.yaml generated
View File

@@ -11,7 +11,7 @@ overrides:
'@types/react': npm:types-react@19.0.0-rc.1 '@types/react': npm:types-react@19.0.0-rc.1
'@types/react-dom': npm:types-react-dom@19.0.0-rc.1 '@types/react-dom': npm:types-react-dom@19.0.0-rc.1
i18next: 23.16.4 i18next: 23.16.4
react-i18next: 15.1.0 react-i18next: ^15.1.0
importers: importers:
@@ -42,7 +42,7 @@ importers:
specifier: ^1.48.2 specifier: ^1.48.2
version: 1.48.2 version: 1.48.2
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
node-html-parser: node-html-parser:
specifier: ^6.1.13 specifier: ^6.1.13
@@ -156,7 +156,7 @@ importers:
specifier: ^7.53.1 specifier: ^7.53.1
version: 7.53.1(react@19.0.0-rc-45804af1-20241021) version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
recharts: recharts:
specifier: 2.13.3 specifier: 2.13.3
@@ -190,7 +190,7 @@ importers:
specifier: ^2.0.13 specifier: ^2.0.13
version: 2.0.13 version: 2.0.13
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
'@types/react': '@types/react':
specifier: npm:types-react@19.0.0-rc.1 specifier: npm:types-react@19.0.0-rc.1
@@ -247,7 +247,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../tooling/typescript version: link:../../tooling/typescript
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
packages/billing/core: packages/billing/core:
@@ -331,7 +331,7 @@ importers:
specifier: ^7.53.1 specifier: ^7.53.1
version: 7.53.1(react@19.0.0-rc-45804af1-20241021) version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
zod: zod:
specifier: ^3.23.8 specifier: ^3.23.8
@@ -453,7 +453,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../wordpress version: link:../wordpress
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
packages/cms/keystatic: packages/cms/keystatic:
@@ -484,7 +484,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../ui version: link:../../ui
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
'@types/react': '@types/react':
specifier: npm:types-react@19.0.0-rc.1 specifier: npm:types-react@19.0.0-rc.1
@@ -526,7 +526,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../ui version: link:../../ui
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
'@types/react': '@types/react':
specifier: npm:types-react@19.0.0-rc.1 specifier: npm:types-react@19.0.0-rc.1
@@ -675,7 +675,7 @@ importers:
specifier: ^7.53.1 specifier: ^7.53.1
version: 7.53.1(react@19.0.0-rc-45804af1-20241021) version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
sonner: sonner:
specifier: ^1.7.0 specifier: ^1.7.0
@@ -801,7 +801,7 @@ importers:
specifier: ^7.53.1 specifier: ^7.53.1
version: 7.53.1(react@19.0.0-rc-45804af1-20241021) version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
sonner: sonner:
specifier: ^1.7.0 specifier: ^1.7.0
@@ -849,7 +849,7 @@ importers:
specifier: 19.0.0-rc-45804af1-20241021 specifier: 19.0.0-rc-45804af1-20241021
version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021) version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
packages/features/team-accounts: packages/features/team-accounts:
@@ -937,7 +937,7 @@ importers:
specifier: ^7.53.1 specifier: ^7.53.1
version: 7.53.1(react@19.0.0-rc-45804af1-20241021) version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
sonner: sonner:
specifier: ^1.7.0 specifier: ^1.7.0
@@ -986,7 +986,7 @@ importers:
specifier: 19.0.0-rc-45804af1-20241021 specifier: 19.0.0-rc-45804af1-20241021
version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021) version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
packages/mailers/core: packages/mailers/core:
@@ -1010,7 +1010,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../../tooling/typescript version: link:../../../tooling/typescript
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
zod: zod:
specifier: ^3.23.8 specifier: ^3.23.8
@@ -1062,7 +1062,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../../tooling/typescript version: link:../../../tooling/typescript
'@types/node': '@types/node':
specifier: ^22.8.6 specifier: ^22.8.7
version: 22.9.0 version: 22.9.0
zod: zod:
specifier: ^3.23.8 specifier: ^3.23.8
@@ -1429,7 +1429,7 @@ importers:
specifier: ^7.53.1 specifier: ^7.53.1
version: 7.53.1(react@19.0.0-rc-45804af1-20241021) version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
react-i18next: react-i18next:
specifier: 15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
sonner: sonner:
specifier: ^1.7.0 specifier: ^1.7.0
@@ -6680,8 +6680,8 @@ packages:
react-native: react-native:
optional: true optional: true
react-is@19.0.0-rc-4d577fd2-20241104: react-is@19.0.0-rc-33c7bd9a-20241104:
resolution: {integrity: sha512-U52Z3ZQsfvw6cIbCUt+JAPn73TL+4hN4X5D9JvQ3M+M3nlibKXL1SwC90yD23TI2gsZghM+OFXW561pMpS+6yg==} resolution: {integrity: sha512-MNHzi8NhHjNzoO4ADF2VMuEkaWX6qJNz+/J6CoHsKVhA7LBAO20oGe87FB2f/0gmtOldH9g7rW9nyaEo/NJjBg==}
react-promise-suspense@0.3.4: react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==} resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
@@ -12616,7 +12616,7 @@ snapshots:
hoist-non-react-statics@3.3.2: hoist-non-react-statics@3.3.2:
dependencies: dependencies:
react-is: 19.0.0-rc-4d577fd2-20241104 react-is: 19.0.0-rc-33c7bd9a-20241104
html-escaper@2.0.2: {} html-escaper@2.0.2: {}
@@ -13993,7 +13993,7 @@ snapshots:
'@jest/types': 24.9.0 '@jest/types': 24.9.0
ansi-regex: 4.1.1 ansi-regex: 4.1.1
ansi-styles: 3.2.1 ansi-styles: 3.2.1
react-is: 19.0.0-rc-4d577fd2-20241104 react-is: 19.0.0-rc-33c7bd9a-20241104
prismjs@1.29.0: {} prismjs@1.29.0: {}
@@ -14009,7 +14009,7 @@ snapshots:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
object-assign: 4.1.1 object-assign: 4.1.1
react-is: 19.0.0-rc-4d577fd2-20241104 react-is: 19.0.0-rc-33c7bd9a-20241104
prosemirror-commands@1.6.2: prosemirror-commands@1.6.2:
dependencies: dependencies:
@@ -14143,7 +14143,7 @@ snapshots:
optionalDependencies: optionalDependencies:
react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021) react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
react-is@19.0.0-rc-4d577fd2-20241104: {} react-is@19.0.0-rc-33c7bd9a-20241104: {}
react-promise-suspense@0.3.4: react-promise-suspense@0.3.4:
dependencies: dependencies:
@@ -14237,7 +14237,7 @@ snapshots:
lodash: 4.17.21 lodash: 4.17.21
react: 19.0.0-rc-45804af1-20241021 react: 19.0.0-rc-45804af1-20241021
react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021) react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
react-is: 19.0.0-rc-4d577fd2-20241104 react-is: 19.0.0-rc-33c7bd9a-20241104
react-smooth: 4.0.1(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) react-smooth: 4.0.1(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
recharts-scale: 0.4.5 recharts-scale: 0.4.5
tiny-invariant: 1.3.3 tiny-invariant: 1.3.3