Skip to content

Commit ca50670

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

File tree

6 files changed

+58
-27
lines changed

6 files changed

+58
-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: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ 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 { basePromptElementStyles, handleDashboardUrlParsing, PromptContainer, PromptSuccessIcon } from '../shared';
1212
import { ClerkLogoIcon } from './ClerkLogoIcon';
1313
import { KeySlashIcon } from './KeySlashIcon';
1414
import { useRevalidateEnvironment } from './use-revalidate-environment';
@@ -34,25 +34,6 @@ function withLastActiveFallback(cb: () => string): string {
3434
}
3535
}
3636

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-
5637
const KeylessPromptInternal = (_props: KeylessPromptProps) => {
5738
const { isSignedIn } = useUser();
5839
const [isExpanded, setIsExpanded] = useState(false);

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

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

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)