review(front): refacto url-manager (#8861)

Replace https://github.com/twentyhq/twenty/pull/8855
This commit is contained in:
Antoine Moreaux
2024-12-05 11:47:51 +01:00
committed by GitHub
parent 7ab00a4c82
commit 081ecbcfaf
33 changed files with 639 additions and 271 deletions

View File

@ -0,0 +1,34 @@
import { isDefined } from '~/utils/isDefined';
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
import { useRecoilValue } from 'recoil';
export const useBuildWorkspaceUrl = () => {
const domainConfiguration = useRecoilValue(domainConfigurationState);
const buildWorkspaceUrl = (
subdomain?: string,
pathname?: string,
searchParams?: Record<string, string>,
) => {
const url = new URL(window.location.href);
if (isDefined(subdomain) && subdomain.length !== 0) {
url.hostname = `${subdomain}.${domainConfiguration.frontDomain}`;
}
if (isDefined(pathname)) {
url.pathname = pathname;
}
if (isDefined(searchParams)) {
Object.entries(searchParams).forEach(([key, value]) =>
url.searchParams.set(key, value),
);
}
return url.toString();
};
return {
buildWorkspaceUrl,
};
};

View File

@ -0,0 +1,42 @@
import { useGetPublicWorkspaceDataBySubdomainQuery } from '~/generated/graphql';
import { isDefined } from '~/utils/isDefined';
import { authProvidersState } from '@/client-config/states/authProvidersState';
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useRedirectToDefaultDomain } from '@/domain-manager/hooks/useRedirectToDefaultDomain';
import { useLastAuthenticatedWorkspaceDomain } from '@/domain-manager/hooks/useLastAuthenticatedWorkspaceDomain';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { useIsCurrentLocationOnDefaultDomain } from '@/domain-manager/hooks/useIsCurrentLocationOnDefaultDomain';
export const useGetPublicWorkspaceDataBySubdomain = () => {
const { isDefaultDomain } = useIsCurrentLocationOnDefaultDomain();
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
const setAuthProviders = useSetRecoilState(authProvidersState);
const workspacePublicData = useRecoilValue(workspacePublicDataState);
const { redirectToDefaultDomain } = useRedirectToDefaultDomain();
const setWorkspacePublicDataState = useSetRecoilState(
workspacePublicDataState,
);
const { setLastAuthenticateWorkspaceDomain } =
useLastAuthenticatedWorkspaceDomain();
const { loading } = useGetPublicWorkspaceDataBySubdomainQuery({
skip:
(isMultiWorkspaceEnabled && isDefaultDomain) ||
isDefined(workspacePublicData),
onCompleted: (data) => {
setAuthProviders(data.getPublicWorkspaceDataBySubdomain.authProviders);
setWorkspacePublicDataState(data.getPublicWorkspaceDataBySubdomain);
},
onError: (error) => {
// eslint-disable-next-line no-console
console.error(error);
setLastAuthenticateWorkspaceDomain(null);
redirectToDefaultDomain();
},
});
return {
loading,
};
};

View File

@ -0,0 +1,27 @@
import { isDefined } from '~/utils/isDefined';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { useRecoilValue } from 'recoil';
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
import { useReadDefaultDomainFromConfiguration } from '@/domain-manager/hooks/useReadDefaultDomainFromConfiguration';
export const useIsCurrentLocationOnAWorkspaceSubdomain = () => {
const { defaultDomain } = useReadDefaultDomainFromConfiguration();
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
const domainConfiguration = useRecoilValue(domainConfigurationState);
if (
isMultiWorkspaceEnabled &&
(!isDefined(domainConfiguration.frontDomain) ||
!isDefined(domainConfiguration.defaultSubdomain))
) {
throw new Error('frontDomain and defaultSubdomain are required');
}
const isOnAWorkspaceSubdomain =
isMultiWorkspaceEnabled && window.location.hostname !== defaultDomain;
return {
isOnAWorkspaceSubdomain,
};
};

View File

@ -0,0 +1,15 @@
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { useRecoilValue } from 'recoil';
import { useReadDefaultDomainFromConfiguration } from '@/domain-manager/hooks/useReadDefaultDomainFromConfiguration';
export const useIsCurrentLocationOnDefaultDomain = () => {
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
const { defaultDomain } = useReadDefaultDomainFromConfiguration();
const isDefaultDomain = isMultiWorkspaceEnabled
? window.location.hostname === defaultDomain
: true;
return {
isDefaultDomain,
};
};

View File

@ -0,0 +1,29 @@
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { lastAuthenticatedWorkspaceDomainState } from '@/domain-manager/states/lastAuthenticatedWorkspaceDomainState';
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
export const useLastAuthenticatedWorkspaceDomain = () => {
const domainConfiguration = useRecoilValue(domainConfigurationState);
const setLastAuthenticatedWorkspaceDomain = useSetRecoilState(
lastAuthenticatedWorkspaceDomainState,
);
const setLastAuthenticateWorkspaceDomainWithCookieAttributes = (
params: { workspaceId: string; subdomain: string } | null,
) => {
setLastAuthenticatedWorkspaceDomain(
params
? {
...params,
cookieAttributes: {
domain: `.${domainConfiguration.frontDomain}`,
},
}
: null,
);
};
return {
setLastAuthenticateWorkspaceDomain:
setLastAuthenticateWorkspaceDomainWithCookieAttributes,
};
};

View File

@ -0,0 +1,16 @@
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { useRecoilValue } from 'recoil';
export const useReadDefaultDomainFromConfiguration = () => {
const domainConfiguration = useRecoilValue(domainConfigurationState);
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
const defaultDomain = isMultiWorkspaceEnabled
? `${domainConfiguration.defaultSubdomain}.${domainConfiguration.frontDomain}`
: domainConfiguration.frontDomain;
return {
defaultDomain,
};
};

View File

@ -0,0 +1,24 @@
import { isDefined } from '~/utils/isDefined';
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
import { useRecoilValue } from 'recoil';
import { useIsCurrentLocationOnAWorkspaceSubdomain } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspaceSubdomain';
export const useReadWorkspaceSubdomainFromCurrentLocation = () => {
const domainConfiguration = useRecoilValue(domainConfigurationState);
const { isOnAWorkspaceSubdomain } =
useIsCurrentLocationOnAWorkspaceSubdomain();
if (!isDefined(domainConfiguration.frontDomain)) {
throw new Error('frontDomain is not defined');
}
const workspaceSubdomain = isOnAWorkspaceSubdomain
? window.location.hostname.replace(
`.${domainConfiguration.frontDomain}`,
'',
)
: null;
return {
workspaceSubdomain,
};
};

View File

@ -0,0 +1,16 @@
import { useReadDefaultDomainFromConfiguration } from '@/domain-manager/hooks/useReadDefaultDomainFromConfiguration';
export const useRedirectToDefaultDomain = () => {
const { defaultDomain } = useReadDefaultDomainFromConfiguration();
const redirectToDefaultDomain = () => {
const url = new URL(window.location.href);
if (url.hostname !== defaultDomain) {
url.hostname = defaultDomain;
window.location.href = url.toString();
}
};
return {
redirectToDefaultDomain,
};
};

View File

@ -0,0 +1,21 @@
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { useRecoilValue } from 'recoil';
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
export const useRedirectToWorkspaceDomain = () => {
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
const { buildWorkspaceUrl } = useBuildWorkspaceUrl();
const redirectToWorkspaceDomain = (
subdomain: string,
pathname?: string,
searchParams?: Record<string, string>,
) => {
if (!isMultiWorkspaceEnabled) return;
window.location.href = buildWorkspaceUrl(subdomain, pathname, searchParams);
};
return {
redirectToWorkspaceDomain,
};
};

View File

@ -0,0 +1,12 @@
import { createState } from 'twenty-ui';
import { ClientConfig } from '~/generated/graphql';
export const domainConfigurationState = createState<
Pick<ClientConfig, 'frontDomain' | 'defaultSubdomain'>
>({
key: 'domainConfiguration',
defaultValue: {
frontDomain: '',
defaultSubdomain: undefined,
},
});

View File

@ -0,0 +1,16 @@
import { cookieStorageEffect } from '~/utils/recoil-effects';
import { createState } from 'twenty-ui';
export const lastAuthenticatedWorkspaceDomainState = createState<{
subdomain: string;
workspaceId: string;
cookieAttributes?: Cookies.CookieAttributes;
} | null>({
key: 'lastAuthenticateWorkspaceDomain',
defaultValue: null,
effects: [
cookieStorageEffect('lastAuthenticateWorkspaceDomain', {
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), // 1 year
}),
],
});