Skip to content

Commit 51fbac8

Browse files
committed
Extract Dashboard URL to display within anchor tag
1 parent 2ad4dc1 commit 51fbac8

File tree

6 files changed

+65
-27
lines changed

6 files changed

+65
-27
lines changed

packages/clerk-js/src/core/clerk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ export class Clerk implements ClerkInterface {
746746
): { status: 'enabled' | 'prompt-shown' } => {
747747
const { for: setting, caller } = params;
748748

749-
// If not in development instance, return enabled status in order to not open the in-app prompt
749+
// If not in development instance, return enabled status in order to not open the prompt
750750
if (this.#instanceType !== 'development') {
751751
return { status: 'enabled' };
752752
}

packages/clerk-js/src/ui/Components.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ const Components = (props: ComponentsProps) => {
353353

354354
componentsControls.openModal = (name, props) => {
355355
// Prevent opening enableOrganizations prompt if it's already open
356-
// to avoid duplicate mounting when component is called multiple times
356+
// It should open the first call and ignore the subsequent calls
357357
if (name === 'enableOrganizationsPrompt') {
358358
setState(prev => {
359359
// Modal is already open, don't update state

packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,27 @@ import { useClerk } from '@clerk/shared/react';
22
import type { __internal_EnableOrganizationsPromptProps } from '@clerk/shared/types';
33
// eslint-disable-next-line no-restricted-imports
44
import { css } from '@emotion/react';
5-
import { useState } from 'react';
5+
import { useMemo, useState } from 'react';
66

77
import { Modal } from '@/ui/elements/Modal';
88
import { InternalThemeProvider } from '@/ui/styledSystem';
99

1010
import { DevTools } from '../../../../core/resources/DevTools';
11+
import type { Environment } from '../../../../core/resources/Environment';
1112
import { Flex } from '../../../customizables';
1213
import { Portal } from '../../../elements/Portal';
13-
import { basePromptElementStyles, PromptContainer, PromptSuccessIcon } from '../shared';
14+
import { basePromptElementStyles, handleDashboardUrlParsing, PromptContainer, PromptSuccessIcon } from '../shared';
15+
16+
/**
17+
* If we cannot reconstruct the url properly, then simply fallback to Clerk Dashboard
18+
*/
19+
function withLastActiveFallback(cb: () => string): string {
20+
try {
21+
return cb();
22+
} catch {
23+
return 'https://dashboard.clerk.com/last-active?path=organization-settings';
24+
}
25+
}
1426

1527
const EnableOrganizationsPromptInternal = ({
1628
caller,
@@ -21,6 +33,28 @@ const EnableOrganizationsPromptInternal = ({
2133
const [isLoading, setIsLoading] = useState(false);
2234
const [isEnabled, setIsEnabled] = useState(false);
2335

36+
// @ts-expect-error - __unstable__environment is not typed
37+
const environment = clerk?.__unstable__environment as Environment | undefined;
38+
39+
const organizationSettingsUrl = useMemo(() => {
40+
return withLastActiveFallback(() => {
41+
const currentUrl = window.location.href;
42+
try {
43+
const redirectUrlParts = handleDashboardUrlParsing(currentUrl);
44+
const url = new URL(
45+
`${redirectUrlParts.baseDomain}/apps/${redirectUrlParts.appId}/instances/${redirectUrlParts.instanceId}/organization-settings`,
46+
);
47+
return url.href;
48+
} catch {
49+
if (!environment?.id) {
50+
throw new Error('Cannot construct dashboard URL');
51+
}
52+
53+
return 'https://dashboard.clerk.com/last-active?path=organization-settings';
54+
}
55+
});
56+
}, [environment?.id]);
57+
2458
const handleEnableOrganizations = () => {
2559
setIsLoading(true);
2660

@@ -193,8 +227,7 @@ const EnableOrganizationsPromptInternal = ({
193227
font-size: 0.8125rem;
194228
`,
195229
]}
196-
/* TODO - Generate URL to Dashboard */
197-
href='https://clerk.com/docs/guides/organizations'
230+
href={organizationSettingsUrl}
198231
target='_blank'
199232
rel='noopener noreferrer'
200233
tabIndex={-1}

packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/index.tsx

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import { createPortal } from 'react-dom';
88
import { Flex, Link } from '../../../customizables';
99
import { Portal } from '../../../elements/Portal';
1010
import { InternalThemeProvider } from '../../../styledSystem';
11-
import { basePromptElementStyles, PromptContainer, PromptSuccessIcon } from '../shared';
11+
import {
12+
basePromptElementStyles,
13+
handleDashboardUrlParsing,
14+
handleDashboardUrlParsing,
15+
PromptContainer,
16+
PromptSuccessIcon,
17+
} from '../shared';
1218
import { ClerkLogoIcon } from './ClerkLogoIcon';
1319
import { KeySlashIcon } from './KeySlashIcon';
1420
import { useRevalidateEnvironment } from './use-revalidate-environment';
@@ -34,25 +40,6 @@ function withLastActiveFallback(cb: () => string): string {
3440
}
3541
}
3642

37-
function handleDashboardUrlParsing(url: string) {
38-
// make sure this is a valid url
39-
const __url = new URL(url);
40-
const regex = /^https?:\/\/(.*?)\/apps\/app_(.+?)\/instances\/ins_(.+?)(?:\/.*)?$/;
41-
42-
const match = __url.href.match(regex);
43-
44-
if (!match) {
45-
throw new Error('invalid value dashboard url structure');
46-
}
47-
48-
// Extracting base domain, app ID with prefix, and instanceId with prefix
49-
return {
50-
baseDomain: `https://${match[1]}`,
51-
appId: `app_${match[2]}`,
52-
instanceId: `ins_${match[3]}`,
53-
};
54-
}
55-
5643
const KeylessPromptInternal = (_props: KeylessPromptProps) => {
5744
const { isSignedIn } = useUser();
5845
const [isExpanded, setIsExpanded] = useState(false);

packages/clerk-js/src/ui/components/devPrompts/shared.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,22 @@ export function PromptSuccessIcon(props: React.ComponentProps<'svg'>) {
8181
</svg>
8282
);
8383
}
84+
85+
export function handleDashboardUrlParsing(url: string) {
86+
// make sure this is a valid url
87+
const __url = new URL(url);
88+
const regex = /^https?:\/\/(.*?)\/apps\/app_(.+?)\/instances\/ins_(.+?)(?:\/.*)?$/;
89+
90+
const match = __url.href.match(regex);
91+
92+
if (!match) {
93+
throw new Error('invalid value dashboard url structure');
94+
}
95+
96+
// Extracting base domain, app ID with prefix, and instanceId with prefix
97+
return {
98+
baseDomain: `https://${match[1]}`,
99+
appId: `app_${match[2]}`,
100+
instanceId: `ins_${match[3]}`,
101+
};
102+
}

packages/shared/src/organization.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ export function useAttemptToEnableOrganizations(caller: 'useOrganization' | 'use
3838
clerk.__internal_attemptToEnableEnvironmentSetting({
3939
for: 'organizations',
4040
caller,
41-
onSuccess: () => {},
4241
});
4342
}, [clerk, caller]);
4443
}

0 commit comments

Comments
 (0)