Merge branch 'develop' into feature/MED-129
This commit is contained in:
@@ -5,12 +5,10 @@ import { useCallback } from 'react';
|
||||
import type { AuthChangeEvent, Session } from '@supabase/supabase-js';
|
||||
|
||||
import { useMonitoring } from '@kit/monitoring/hooks';
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
import { useAppEvents } from '@kit/shared/events';
|
||||
import { useAuthChangeListener } from '@kit/supabase/hooks/use-auth-change-listener';
|
||||
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
|
||||
|
||||
export function AuthProvider(props: React.PropsWithChildren) {
|
||||
const dispatchEvent = useDispatchAppEventFromAuthEvent();
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@kit/ui/dialog';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
@@ -38,7 +37,7 @@ export default function ConfirmationModal({
|
||||
<Trans i18nKey={descriptionKey} />
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter className='gap-3'>
|
||||
<DialogFooter className="gap-3">
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
<Trans i18nKey={cancelKey} />
|
||||
</Button>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { DropdownMenuItem } from "@kit/ui/dropdown-menu";
|
||||
import { Trans } from "@kit/ui/trans";
|
||||
import { LogOut } from "lucide-react";
|
||||
import { LogOut } from 'lucide-react';
|
||||
|
||||
import { DropdownMenuItem } from '@kit/ui/dropdown-menu';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
export default function SignOutDropdownItem(
|
||||
props: React.PropsWithChildren<{
|
||||
|
||||
@@ -24,7 +24,9 @@ export function ButtonTooltip({
|
||||
<Info className="size-4 cursor-pointer" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className='sm:max-w-[30vw] sm:leading-4'>{content}</TooltipContent>
|
||||
<TooltipContent className="sm:max-w-[30vw] sm:leading-4">
|
||||
{content}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { DropdownMenuItem } from "@kit/ui/dropdown-menu";
|
||||
import { Trans } from "@kit/ui/trans";
|
||||
import Link from "next/link";
|
||||
import Link from 'next/link';
|
||||
|
||||
import { DropdownMenuItem } from '@kit/ui/dropdown-menu';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
export default function DropdownLink(
|
||||
props: React.PropsWithChildren<{
|
||||
@@ -30,4 +31,4 @@ export default function DropdownLink(
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ export function InfoTooltip({
|
||||
<TooltipTrigger>
|
||||
{icon || <Info className="size-4 cursor-pointer" />}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className='max-w-[90vw] sm:max-w-[400px]'>{content}</TooltipContent>
|
||||
<TooltipContent className="max-w-[90vw] sm:max-w-[400px]">
|
||||
{content}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { Button } from "@kit/ui/button";
|
||||
import { type ComponentProps } from "react";
|
||||
import { useFormStatus } from "react-dom";
|
||||
import { type ComponentProps } from 'react';
|
||||
|
||||
import { useFormStatus } from 'react-dom';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
|
||||
type Props = ComponentProps<typeof Button> & {
|
||||
pendingText?: string;
|
||||
@@ -10,7 +12,7 @@ type Props = ComponentProps<typeof Button> & {
|
||||
|
||||
export function SubmitButton({
|
||||
children,
|
||||
pendingText = "Submitting...",
|
||||
pendingText = 'Submitting...',
|
||||
...props
|
||||
}: Props) {
|
||||
const { pending } = useFormStatus();
|
||||
@@ -20,4 +22,4 @@ export function SubmitButton({
|
||||
{pending ? pendingText : children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
33
packages/shared/src/config/admin-navigation.config.tsx
Normal file
33
packages/shared/src/config/admin-navigation.config.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { LayoutDashboard, Users } from 'lucide-react';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
import { NavigationConfigSchema } from '@kit/ui/navigation-schema';
|
||||
|
||||
const iconClasses = 'w-4 stroke-[1.5px]';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
label: 'Dashboard',
|
||||
path: pathsConfig.app.admin,
|
||||
Icon: <LayoutDashboard className={iconClasses} />,
|
||||
end: true,
|
||||
},
|
||||
{
|
||||
label: 'Accounts',
|
||||
path: `${pathsConfig.app.admin}/accounts`,
|
||||
Icon: <Users className={iconClasses} />,
|
||||
end: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
] satisfies z.infer<typeof NavigationConfigSchema>['routes'];
|
||||
|
||||
export const adminNavigationConfig = NavigationConfigSchema.parse({
|
||||
routes,
|
||||
style: 'custom',
|
||||
sidebarCollapsed: false,
|
||||
sidebarCollapsedStyle: 'icon',
|
||||
});
|
||||
@@ -16,14 +16,16 @@ const AppConfigSchema = z
|
||||
})
|
||||
.describe(`This is the default title tag of your SaaS.`)
|
||||
.min(1),
|
||||
description: z.string({
|
||||
error: `Please provide the variable NEXT_PUBLIC_SITE_DESCRIPTION`,
|
||||
})
|
||||
description: z
|
||||
.string({
|
||||
error: `Please provide the variable NEXT_PUBLIC_SITE_DESCRIPTION`,
|
||||
})
|
||||
.describe(`This is the default description of your SaaS.`),
|
||||
url: z.url({
|
||||
error: (issue) => issue.input === undefined
|
||||
? "Please provide the variable NEXT_PUBLIC_SITE_URL"
|
||||
: `You are deploying a production build but have entered a NEXT_PUBLIC_SITE_URL variable using http instead of https. It is very likely that you have set the incorrect URL. The build will now fail to prevent you from from deploying a faulty configuration. Please provide the variable NEXT_PUBLIC_SITE_URL with a valid URL, such as: 'https://example.com'`
|
||||
error: (issue) =>
|
||||
issue.input === undefined
|
||||
? 'Please provide the variable NEXT_PUBLIC_SITE_URL'
|
||||
: `You are deploying a production build but have entered a NEXT_PUBLIC_SITE_URL variable using http instead of https. It is very likely that you have set the incorrect URL. The build will now fail to prevent you from from deploying a faulty configuration. Please provide the variable NEXT_PUBLIC_SITE_URL with a valid URL, such as: 'https://example.com'`,
|
||||
}),
|
||||
locale: z
|
||||
.string({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Provider } from '@supabase/supabase-js';
|
||||
|
||||
import authConfig from './auth.config';
|
||||
|
||||
type SupabaseExternalProvider = Provider | 'email';
|
||||
@@ -10,7 +11,10 @@ interface SupabaseAuthSettings {
|
||||
|
||||
export class AuthProvidersService {
|
||||
private supabaseUrl: string;
|
||||
private cache: Map<string, { data: SupabaseAuthSettings; timestamp: number }> = new Map();
|
||||
private cache: Map<
|
||||
string,
|
||||
{ data: SupabaseAuthSettings; timestamp: number }
|
||||
> = new Map();
|
||||
private readonly CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
constructor(supabaseUrl: string) {
|
||||
@@ -21,7 +25,7 @@ export class AuthProvidersService {
|
||||
try {
|
||||
const cacheKey = 'auth-settings';
|
||||
const cached = this.cache.get(cacheKey);
|
||||
|
||||
|
||||
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
|
||||
return cached.data;
|
||||
}
|
||||
@@ -31,22 +35,28 @@ export class AuthProvidersService {
|
||||
throw new Error('NEXT_PUBLIC_SUPABASE_ANON_KEY is required');
|
||||
}
|
||||
|
||||
const response = await fetch(`${this.supabaseUrl}/auth/v1/settings?apikey=${anonKey}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
const response = await fetch(
|
||||
`${this.supabaseUrl}/auth/v1/settings?apikey=${anonKey}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.warn('Failed to fetch auth settings from Supabase:', response.status);
|
||||
console.warn(
|
||||
'Failed to fetch auth settings from Supabase:',
|
||||
response.status,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const settings: SupabaseAuthSettings = await response.json();
|
||||
|
||||
|
||||
this.cache.set(cacheKey, { data: settings, timestamp: Date.now() });
|
||||
|
||||
|
||||
return settings;
|
||||
} catch (error) {
|
||||
console.warn('Error fetching auth settings from Supabase:', error);
|
||||
@@ -54,7 +64,11 @@ export class AuthProvidersService {
|
||||
}
|
||||
}
|
||||
|
||||
isPasswordEnabled({ settings }: { settings: SupabaseAuthSettings | null }): boolean {
|
||||
isPasswordEnabled({
|
||||
settings,
|
||||
}: {
|
||||
settings: SupabaseAuthSettings | null;
|
||||
}): boolean {
|
||||
if (settings) {
|
||||
return settings.external.email === true && !settings.disable_signup;
|
||||
}
|
||||
@@ -62,7 +76,11 @@ export class AuthProvidersService {
|
||||
return process.env.NEXT_PUBLIC_AUTH_PASSWORD === 'true';
|
||||
}
|
||||
|
||||
isMailerAutoconfirmEnabled({ settings }: { settings: SupabaseAuthSettings | null }): boolean {
|
||||
isMailerAutoconfirmEnabled({
|
||||
settings,
|
||||
}: {
|
||||
settings: SupabaseAuthSettings | null;
|
||||
}): boolean {
|
||||
return settings?.mailer_autoconfirm === true;
|
||||
}
|
||||
|
||||
@@ -84,11 +102,17 @@ export class AuthProvidersService {
|
||||
return false;
|
||||
}
|
||||
|
||||
getEnabledOAuthProviders({ settings }: { settings: SupabaseAuthSettings | null }): SupabaseExternalProvider[] {
|
||||
getEnabledOAuthProviders({
|
||||
settings,
|
||||
}: {
|
||||
settings: SupabaseAuthSettings | null;
|
||||
}): SupabaseExternalProvider[] {
|
||||
const enabledProviders: SupabaseExternalProvider[] = [];
|
||||
|
||||
|
||||
if (settings && settings.external) {
|
||||
for (const [providerName, isEnabled] of Object.entries(settings.external)) {
|
||||
for (const [providerName, isEnabled] of Object.entries(
|
||||
settings.external,
|
||||
)) {
|
||||
if (isEnabled && providerName !== 'email') {
|
||||
enabledProviders.push(providerName as SupabaseExternalProvider);
|
||||
}
|
||||
@@ -98,19 +122,27 @@ export class AuthProvidersService {
|
||||
|
||||
const potentialProviders: SupabaseExternalProvider[] = ['keycloak'];
|
||||
const enabledFallback: SupabaseExternalProvider[] = [];
|
||||
|
||||
|
||||
for (const provider of potentialProviders) {
|
||||
if (provider !== 'email' && this.isOAuthProviderEnabled({ provider, settings })) {
|
||||
if (
|
||||
provider !== 'email' &&
|
||||
this.isOAuthProviderEnabled({ provider, settings })
|
||||
) {
|
||||
enabledFallback.push(provider);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return enabledFallback;
|
||||
}
|
||||
|
||||
async getAuthConfig() {
|
||||
const settings = await this.fetchAuthSettings();
|
||||
const [passwordEnabled, magicLinkEnabled, oAuthProviders, isMailerAutoconfirmEnabled] = await Promise.all([
|
||||
const [
|
||||
passwordEnabled,
|
||||
magicLinkEnabled,
|
||||
oAuthProviders,
|
||||
isMailerAutoconfirmEnabled,
|
||||
] = await Promise.all([
|
||||
this.isPasswordEnabled({ settings }),
|
||||
this.isMagicLinkEnabled(),
|
||||
this.getEnabledOAuthProviders({ settings }),
|
||||
@@ -135,10 +167,10 @@ export class AuthProvidersService {
|
||||
|
||||
export function createAuthProvidersService(): AuthProvidersService {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
|
||||
|
||||
if (!supabaseUrl) {
|
||||
throw new Error('NEXT_PUBLIC_SUPABASE_URL is required');
|
||||
}
|
||||
|
||||
|
||||
return new AuthProvidersService(supabaseUrl);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ const providers: z.ZodType<Provider> = getProviders();
|
||||
|
||||
const AuthConfigSchema = z.object({
|
||||
captchaTokenSiteKey: z
|
||||
.string().describe('The reCAPTCHA site key.')
|
||||
.string()
|
||||
.describe('The reCAPTCHA site key.')
|
||||
.optional(),
|
||||
displayTermsCheckbox: z
|
||||
.boolean().describe('Whether to display the terms checkbox during sign-up.')
|
||||
.boolean()
|
||||
.describe('Whether to display the terms checkbox during sign-up.')
|
||||
.optional(),
|
||||
providers: z.object({
|
||||
password: z.boolean().describe('Enable password authentication.'),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { Provider } from '@supabase/supabase-js';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
import { createAuthProvidersService } from './auth-providers.service';
|
||||
|
||||
const providers: z.ZodType<Provider> = getProviders();
|
||||
@@ -10,8 +12,12 @@ const DynamicAuthConfigSchema = z.object({
|
||||
magicLink: z.boolean().describe('Enable magic link authentication.'),
|
||||
oAuth: providers.array(),
|
||||
}),
|
||||
displayTermsCheckbox: z.boolean().describe('Whether to display the terms checkbox during sign-up.'),
|
||||
isMailerAutoconfirmEnabled: z.boolean().describe('Whether Supabase sends confirmation email automatically.'),
|
||||
displayTermsCheckbox: z
|
||||
.boolean()
|
||||
.describe('Whether to display the terms checkbox during sign-up.'),
|
||||
isMailerAutoconfirmEnabled: z
|
||||
.boolean()
|
||||
.describe('Whether Supabase sends confirmation email automatically.'),
|
||||
});
|
||||
|
||||
export type DynamicAuthConfig = {
|
||||
@@ -22,7 +28,7 @@ export type DynamicAuthConfig = {
|
||||
};
|
||||
displayTermsCheckbox: boolean | undefined;
|
||||
isMailerAutoconfirmEnabled: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export async function getDynamicAuthConfig() {
|
||||
const authService = createAuthProvidersService();
|
||||
@@ -57,10 +63,13 @@ export async function getCachedAuthConfig() {
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
sessionStorage.setItem('auth-config', JSON.stringify({
|
||||
data: config,
|
||||
timestamp: Date.now(),
|
||||
}));
|
||||
sessionStorage.setItem(
|
||||
'auth-config',
|
||||
JSON.stringify({
|
||||
data: config,
|
||||
timestamp: Date.now(),
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn('Failed to cache auth config:', error);
|
||||
}
|
||||
@@ -73,7 +82,9 @@ export async function getServerAuthConfig() {
|
||||
return getDynamicAuthConfig();
|
||||
}
|
||||
|
||||
export async function isProviderEnabled(provider: 'password' | 'magicLink' | Provider): Promise<boolean> {
|
||||
export async function isProviderEnabled(
|
||||
provider: 'password' | 'magicLink' | Provider,
|
||||
): Promise<boolean> {
|
||||
const authService = createAuthProvidersService();
|
||||
const settings = await authService.fetchAuthSettings();
|
||||
|
||||
|
||||
@@ -3,57 +3,65 @@ import { z } from 'zod';
|
||||
type LanguagePriority = 'user' | 'application';
|
||||
|
||||
const FeatureFlagsSchema = z.object({
|
||||
enableThemeToggle: z.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_THEME_TOGGLE',
|
||||
})
|
||||
.describe( 'Enable theme toggle in the user interface.'),
|
||||
enableAccountDeletion: z.boolean({
|
||||
error:
|
||||
'Provide the variable NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION',
|
||||
})
|
||||
.describe('Enable personal account deletion.'),
|
||||
enableTeamDeletion: z.boolean({
|
||||
error:
|
||||
'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION',
|
||||
})
|
||||
.describe('Enable team deletion.'),
|
||||
enableTeamAccounts: z.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS',
|
||||
})
|
||||
.describe('Enable team accounts.'),
|
||||
enableTeamCreation: z.boolean({
|
||||
error:
|
||||
'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION',
|
||||
})
|
||||
.describe('Enable team creation.'),
|
||||
enablePersonalAccountBilling: z.boolean({
|
||||
error:
|
||||
'Provide the variable NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING',
|
||||
})
|
||||
.describe('Enable personal account billing.'),
|
||||
enableTeamAccountBilling: z.boolean({
|
||||
error:
|
||||
'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING',
|
||||
})
|
||||
.describe('Enable team account billing.'),
|
||||
enableThemeToggle: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_THEME_TOGGLE',
|
||||
})
|
||||
.describe('Enable theme toggle in the user interface.'),
|
||||
enableAccountDeletion: z
|
||||
.boolean({
|
||||
error:
|
||||
'Provide the variable NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION',
|
||||
})
|
||||
.describe('Enable personal account deletion.'),
|
||||
enableTeamDeletion: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION',
|
||||
})
|
||||
.describe('Enable team deletion.'),
|
||||
enableTeamAccounts: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS',
|
||||
})
|
||||
.describe('Enable team accounts.'),
|
||||
enableTeamCreation: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION',
|
||||
})
|
||||
.describe('Enable team creation.'),
|
||||
enablePersonalAccountBilling: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING',
|
||||
})
|
||||
.describe('Enable personal account billing.'),
|
||||
enableTeamAccountBilling: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING',
|
||||
})
|
||||
.describe('Enable team account billing.'),
|
||||
languagePriority: z
|
||||
.enum(['user', 'application'], {
|
||||
error: 'Provide the variable NEXT_PUBLIC_LANGUAGE_PRIORITY',
|
||||
})
|
||||
.describe(`If set to user, use the user's preferred language. If set to application, use the application's default language.`)
|
||||
.describe(
|
||||
`If set to user, use the user's preferred language. If set to application, use the application's default language.`,
|
||||
)
|
||||
.default('application'),
|
||||
enableNotifications: z.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_NOTIFICATIONS',
|
||||
})
|
||||
.describe('Enable notifications functionality'),
|
||||
realtimeNotifications: z.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_REALTIME_NOTIFICATIONS',
|
||||
})
|
||||
.describe('Enable realtime for the notifications functionality'),
|
||||
enableVersionUpdater: z.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_VERSION_UPDATER',
|
||||
})
|
||||
.describe('Enable version updater'),
|
||||
enableNotifications: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_NOTIFICATIONS',
|
||||
})
|
||||
.describe('Enable notifications functionality'),
|
||||
realtimeNotifications: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_REALTIME_NOTIFICATIONS',
|
||||
})
|
||||
.describe('Enable realtime for the notifications functionality'),
|
||||
enableVersionUpdater: z
|
||||
.boolean({
|
||||
error: 'Provide the variable NEXT_PUBLIC_ENABLE_VERSION_UPDATER',
|
||||
})
|
||||
.describe('Enable version updater'),
|
||||
});
|
||||
|
||||
const featureFlagsConfig = FeatureFlagsSchema.parse({
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { adminNavigationConfig } from './admin-navigation.config';
|
||||
import appConfig from './app.config';
|
||||
import authConfig from './auth.config';
|
||||
import billingConfig from './billing.config';
|
||||
import {
|
||||
DynamicAuthConfig,
|
||||
getCachedAuthConfig,
|
||||
getServerAuthConfig,
|
||||
} from './dynamic-auth.config';
|
||||
import featureFlagsConfig from './feature-flags.config';
|
||||
import pathsConfig from './paths.config';
|
||||
import { personalAccountNavigationConfig } from './personal-account-navigation.config';
|
||||
@@ -8,9 +14,9 @@ import {
|
||||
createPath,
|
||||
getTeamAccountSidebarConfig,
|
||||
} from './team-account-navigation.config';
|
||||
import { DynamicAuthConfig, getCachedAuthConfig, getServerAuthConfig } from './dynamic-auth.config';
|
||||
|
||||
export {
|
||||
adminNavigationConfig,
|
||||
appConfig,
|
||||
authConfig,
|
||||
billingConfig,
|
||||
|
||||
@@ -7,7 +7,6 @@ const iconClasses = 'w-4';
|
||||
|
||||
const getRoutes = (account: string) => [
|
||||
{
|
||||
label: 'common:routes.application',
|
||||
children: [
|
||||
{
|
||||
label: 'common:routes.dashboard',
|
||||
@@ -15,12 +14,6 @@ const getRoutes = (account: string) => [
|
||||
Icon: <LayoutDashboard className={iconClasses} />,
|
||||
end: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'common:routes.settings',
|
||||
collapsible: false,
|
||||
children: [
|
||||
{
|
||||
label: 'common:routes.settings',
|
||||
path: createPath(pathsConfig.app.accountSettings, account),
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import type { Provider } from '@supabase/supabase-js';
|
||||
import { getCachedAuthConfig } from '../config/dynamic-auth.config';
|
||||
|
||||
import { authConfig } from '../config';
|
||||
import { getCachedAuthConfig } from '../config/dynamic-auth.config';
|
||||
|
||||
interface AuthConfig {
|
||||
providers: {
|
||||
@@ -33,7 +35,9 @@ export function useAuthConfig(): UseAuthConfigResult {
|
||||
setConfig(authConfig);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch auth config', err);
|
||||
setError(err instanceof Error ? err : new Error('Failed to fetch auth config'));
|
||||
setError(
|
||||
err instanceof Error ? err : new Error('Failed to fetch auth config'),
|
||||
);
|
||||
setConfig(authConfig);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -52,7 +56,9 @@ export function useAuthConfig(): UseAuthConfigResult {
|
||||
};
|
||||
}
|
||||
|
||||
export function useProviderEnabled(provider: 'password' | 'magicLink' | Provider) {
|
||||
export function useProviderEnabled(
|
||||
provider: 'password' | 'magicLink' | Provider,
|
||||
) {
|
||||
const { config, loading, error } = useAuthConfig();
|
||||
|
||||
const isEnabled = (() => {
|
||||
|
||||
@@ -4,6 +4,6 @@ const Logger = {
|
||||
warn: console.warn,
|
||||
debug: console.debug,
|
||||
fatal: console.error,
|
||||
}
|
||||
};
|
||||
|
||||
export { Logger };
|
||||
export { Logger };
|
||||
|
||||
@@ -46,7 +46,7 @@ export type UuringElement = {
|
||||
};
|
||||
UuringuVastus?: UuringuVastus | UuringuVastus[]; // 0..n
|
||||
UuringuKommentaar?: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type ResponseUuring = {
|
||||
UuringuElement: UuringElement;
|
||||
@@ -127,6 +127,6 @@ export type MedipostOrderResponse = IMedipostResponseXMLBase & {
|
||||
};
|
||||
Tellimus?: {
|
||||
ValisTellimuseId: string;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user