3959 create a activationstatus in coreworkspace and use it in front to redirect properly (#3989)

* Add computed field to workspace entity

* Add activationStatus to front requests

* Update Selector

* Use activation status

* Stop using selector for mock values

* Remove isCurrentWorkspaceActiveSelector

* Use activation status

* Fix typo

* Use activation status

* Create hook for sign in up navigate

* Update hook to handle profile creation

* Use varaible

* Use more readable boolean function
This commit is contained in:
martmull
2024-02-16 16:00:39 +01:00
committed by GitHub
parent 03a1d3aa75
commit 0ee512a983
26 changed files with 165 additions and 105 deletions

View File

@@ -62,7 +62,7 @@ export const App = () => {
<Route path={AppPath.CreateWorkspace} element={<CreateWorkspace />} />
<Route path={AppPath.CreateProfile} element={<CreateProfile />} />
<Route path={AppPath.PlanRequired} element={<PlanRequired />} />
<Route path="/" element={<DefaultHomePage />} />
<Route path={AppPath.Index} element={<DefaultHomePage />} />
<Route path={AppPath.TasksPage} element={<Tasks />} />
<Route path={AppPath.Impersonate} element={<ImpersonateEffect />} />

View File

@@ -39,7 +39,7 @@ export const PageChangeEffect = () => {
const [workspaceFromInviteHashQuery] =
useGetWorkspaceFromInviteHashLazyQuery();
const { addToCommandMenu, setToIntitialCommandMenu } = useCommandMenu();
const { addToCommandMenu, setToInitialCommandMenu } = useCommandMenu();
const openCreateActivity = useOpenCreateActivityDrawer();
@@ -209,7 +209,7 @@ export const PageChangeEffect = () => {
}, [isMatchingLocation, setHotkeyScope]);
useEffect(() => {
setToIntitialCommandMenu();
setToInitialCommandMenu();
addToCommandMenu([
{
@@ -221,7 +221,7 @@ export const PageChangeEffect = () => {
onCommandClick: () => openCreateActivity({ type: 'Task' }),
},
]);
}, [addToCommandMenu, setToIntitialCommandMenu, openCreateActivity]);
}, [addToCommandMenu, setToInitialCommandMenu, openCreateActivity]);
useEffect(() => {
setTimeout(() => {

View File

@@ -577,6 +577,7 @@ export type Verify = {
export type Workspace = {
__typename?: 'Workspace';
activationStatus: Scalars['String'];
allowImpersonation: Scalars['Boolean'];
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
@@ -782,7 +783,7 @@ export type ImpersonateMutationVariables = Exact<{
}>;
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
export type RenewTokenMutationVariables = Exact<{
refreshToken: Scalars['String'];
@@ -813,7 +814,7 @@ export type VerifyMutationVariables = Exact<{
}>;
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
export type CheckUserExistsQueryVariables = Exact<{
email: Scalars['String'];
@@ -850,7 +851,7 @@ export type UploadImageMutationVariables = Exact<{
export type UploadImageMutation = { __typename?: 'Mutation', uploadImage: string };
export type UserQueryFragmentFragment = { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } };
export type UserQueryFragmentFragment = { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } };
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
@@ -867,7 +868,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } } };
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } } };
export type ActivateWorkspaceMutationVariables = Exact<{
input: ActivateWorkspaceInput;
@@ -988,6 +989,7 @@ export const UserQueryFragmentFragmentDoc = gql`
inviteHash
allowImpersonation
subscriptionStatus
activationStatus
featureFlags {
id
key
@@ -1721,6 +1723,7 @@ export const GetCurrentUserDocument = gql`
inviteHash
allowImpersonation
subscriptionStatus
activationStatus
featureFlags {
id
key

View File

@@ -0,0 +1,44 @@
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState.ts';
import { billingState } from '@/client-config/states/billingState.ts';
import { AppPath } from '@/types/AppPath.ts';
import { WorkspaceMember } from '~/generated/graphql.tsx';
export const useNavigateAfterSignInUp = () => {
const navigate = useNavigate();
const billing = useRecoilValue(billingState);
const navigateAfterSignInUp = useCallback(
(
currentWorkspace: CurrentWorkspace,
currentWorkspaceMember: WorkspaceMember | null,
) => {
if (
billing?.isBillingEnabled &&
currentWorkspace.subscriptionStatus !== 'active'
) {
navigate(AppPath.PlanRequired);
return;
}
if (currentWorkspace.activationStatus !== 'active') {
navigate(AppPath.CreateWorkspace);
return;
}
if (
!currentWorkspaceMember?.name.firstName ||
!currentWorkspaceMember?.name.lastName
) {
navigate(AppPath.CreateProfile);
return;
}
navigate(AppPath.Index);
},
[billing, navigate],
);
return { navigateAfterSignInUp };
};

View File

@@ -1,10 +1,9 @@
import { useCallback, useState } from 'react';
import { SubmitHandler, UseFormReturn } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { useParams } from 'react-router-dom';
import { useNavigateAfterSignInUp } from '@/auth/sign-in-up/hooks/useNavigateAfterSignInUp.ts';
import { Form } from '@/auth/sign-in-up/hooks/useSignInUpForm.ts';
import { billingState } from '@/client-config/states/billingState';
import { AppPath } from '@/types/AppPath';
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
@@ -26,14 +25,18 @@ export enum SignInUpStep {
}
export const useSignInUp = (form: UseFormReturn<Form>) => {
const navigate = useNavigate();
const { enqueueSnackBar } = useSnackBar();
const isMatchingLocation = useIsMatchingLocation();
const billing = useRecoilValue(billingState);
const workspaceInviteHash = useParams().workspaceInviteHash;
const { navigateAfterSignInUp } = useNavigateAfterSignInUp();
const [signInUpStep, setSignInUpStep] = useState<SignInUpStep>(
SignInUpStep.Init,
);
const [signInUpMode, setSignInUpMode] = useState<SignInUpMode>(() => {
if (isMatchingLocation(AppPath.Invite)) {
return SignInUpMode.Invite;
@@ -43,6 +46,7 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
? SignInUpMode.SignIn
: SignInUpMode.SignUp;
});
const {
signInWithCredentials,
signUpWithCredentials,
@@ -84,7 +88,10 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
throw new Error('Email and password are required');
}
const { workspace: currentWorkspace } =
const {
workspace: currentWorkspace,
workspaceMember: currentWorkspaceMember,
} =
signInUpMode === SignInUpMode.SignIn
? await signInWithCredentials(
data.email.toLowerCase().trim(),
@@ -96,19 +103,7 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
workspaceInviteHash,
);
if (
billing?.isBillingEnabled &&
currentWorkspace.subscriptionStatus !== 'active'
) {
navigate(AppPath.PlanRequired);
return;
}
if (currentWorkspace.displayName) {
navigate(AppPath.Index);
return;
}
navigate(AppPath.CreateWorkspace);
navigateAfterSignInUp(currentWorkspace, currentWorkspaceMember);
} catch (err: any) {
enqueueSnackBar(err?.message, {
variant: 'error',
@@ -120,8 +115,7 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
signInWithCredentials,
signUpWithCredentials,
workspaceInviteHash,
billing?.isBillingEnabled,
navigate,
navigateAfterSignInUp,
enqueueSnackBar,
],
);

View File

@@ -11,6 +11,7 @@ export type CurrentWorkspace = Pick<
| 'allowImpersonation'
| 'featureFlags'
| 'subscriptionStatus'
| 'activationStatus'
>;
export const currentWorkspaceState = atom<CurrentWorkspace | null>({

View File

@@ -1,11 +0,0 @@
import { selector } from 'recoil';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
export const isCurrentWorkspaceActiveSelector = selector({
key: 'isCurrentWorkspaceActiveSelector',
get: ({ get }) => {
const currentWorkspaceMember = get(currentWorkspaceMemberState);
return !!currentWorkspaceMember;
},
});

View File

@@ -39,13 +39,13 @@ export const getOnboardingStatus = ({
return OnboardingStatus.Canceled;
}
if (!currentWorkspaceMember) {
if (currentWorkspace?.activationStatus !== 'active') {
return OnboardingStatus.OngoingWorkspaceActivation;
}
if (
!currentWorkspaceMember.name.firstName ||
!currentWorkspaceMember.name.lastName
!currentWorkspaceMember?.name.firstName ||
!currentWorkspaceMember?.name.lastName
) {
return OnboardingStatus.OngoingProfileCreation;
}

View File

@@ -31,14 +31,14 @@ const meta: Meta<typeof CommandMenu> = {
const setCurrentWorkspaceMember = useSetRecoilState(
currentWorkspaceMemberState,
);
const { addToCommandMenu, setToIntitialCommandMenu, openCommandMenu } =
const { addToCommandMenu, setToInitialCommandMenu, openCommandMenu } =
useCommandMenu();
setCurrentWorkspace(mockDefaultWorkspace);
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
useEffect(() => {
setToIntitialCommandMenu();
setToInitialCommandMenu();
addToCommandMenu([
{
id: 'create-task',
@@ -58,7 +58,7 @@ const meta: Meta<typeof CommandMenu> = {
},
]);
openCommandMenu();
}, [addToCommandMenu, setToIntitialCommandMenu, openCommandMenu]);
}, [addToCommandMenu, setToInitialCommandMenu, openCommandMenu]);
return <Story />;
},

View File

@@ -107,11 +107,11 @@ describe('useCommandMenu', () => {
expect(onClickMock).toHaveBeenCalledTimes(1);
});
it('should setToIntitialCommandMenu command menu', () => {
it('should setToInitialCommandMenu command menu', () => {
const { result } = renderHooks();
act(() => {
result.current.commandMenu.setToIntitialCommandMenu();
result.current.commandMenu.setToInitialCommandMenu();
});
expect(result.current.commandMenuCommands.length).toBe(5);

View File

@@ -61,7 +61,7 @@ export const useCommandMenu = () => {
[setCommands],
);
const setToIntitialCommandMenu = () => {
const setToInitialCommandMenu = () => {
setCommands(commandMenuCommands);
};
@@ -87,6 +87,6 @@ export const useCommandMenu = () => {
toggleCommandMenu,
addToCommandMenu,
onItemClick,
setToIntitialCommandMenu,
setToInitialCommandMenu,
};
};

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { useRecoilValue } from 'recoil';
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState.ts';
import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
@@ -9,14 +10,17 @@ export const ObjectMetadataItemsProvider = ({
children,
}: React.PropsWithChildren) => {
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const isCurrentWorkspaceActive = useRecoilValue(
isCurrentWorkspaceActiveSelector,
);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const shouldDisplayChildren = () => {
if (objectMetadataItems.length) {
return true;
}
return !currentWorkspaceMember;
};
return (
<>
<ObjectMetadataItemsLoadEffect />
{(!isCurrentWorkspaceActive || !!objectMetadataItems.length) && (
{shouldDisplayChildren() && (
<RelationPickerScope relationPickerScopeId="relation-picker">
{children}
</RelationPickerScope>

View File

@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
import { useRecoilValue } from 'recoil';
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState.ts';
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
@@ -40,9 +40,8 @@ export const useObjectMetadataItem = (
{ objectNameSingular }: ObjectMetadataItemIdentifier,
depth?: number,
) => {
const isCurrentWorkspaceActive = useRecoilValue(
isCurrentWorkspaceActiveSelector,
);
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
@@ -54,7 +53,7 @@ export const useObjectMetadataItem = (
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
if (!isCurrentWorkspaceActive) {
if (currentWorkspace?.activationStatus !== 'active') {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>

View File

@@ -1,6 +1,6 @@
import { useRecoilValue } from 'recoil';
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState.ts';
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
@@ -12,9 +12,8 @@ import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentif
export const useObjectMetadataItemOnly = ({
objectNameSingular,
}: ObjectMetadataItemIdentifier) => {
const isCurrentWorkspaceActive = useRecoilValue(
isCurrentWorkspaceActiveSelector,
);
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
@@ -26,7 +25,7 @@ export const useObjectMetadataItemOnly = ({
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
if (!isCurrentWorkspaceActive) {
if (currentWorkspace?.activationStatus !== 'active') {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>

View File

@@ -1,6 +1,6 @@
import { useRecoilValue } from 'recoil';
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState.ts';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
import { isDefined } from '~/utils/isDefined';
@@ -10,9 +10,7 @@ export const useObjectNamePluralFromSingular = ({
}: {
objectNameSingular: string;
}) => {
const isCurrentWorkspaceActive = useRecoilValue(
isCurrentWorkspaceActiveSelector,
);
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
@@ -22,7 +20,7 @@ export const useObjectNamePluralFromSingular = ({
}),
);
if (!isCurrentWorkspaceActive) {
if (currentWorkspace?.activationStatus !== 'active') {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>

View File

@@ -1,6 +1,6 @@
import { useRecoilValue } from 'recoil';
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState.ts';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
import { isDefined } from '~/utils/isDefined';
@@ -10,9 +10,8 @@ export const useObjectNameSingularFromPlural = ({
}: {
objectNamePlural: string;
}) => {
const isCurrentWorkspaceActive = useRecoilValue(
isCurrentWorkspaceActiveSelector,
);
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
@@ -22,7 +21,7 @@ export const useObjectNameSingularFromPlural = ({
}),
);
if (!isCurrentWorkspaceActive) {
if (currentWorkspace?.activationStatus !== 'active') {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>

View File

@@ -1,6 +1,6 @@
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState.ts';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
@@ -14,9 +14,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
const { setRecordTableData, setIsRecordTableInitialLoading } =
useRecordTable();
const isCurrentWorkspaceActive = useRecoilValue(
isCurrentWorkspaceActiveSelector,
);
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
@@ -58,7 +56,10 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
});
return {
records: isCurrentWorkspaceActive ? records : signInBackgroundMockCompanies,
records:
currentWorkspace?.activationStatus === 'active'
? records
: signInBackgroundMockCompanies,
totalCount: totalCount || 0,
loading,
fetchMoreRecords,

View File

@@ -26,6 +26,7 @@ export const USER_QUERY_FRAGMENT = gql`
inviteHash
allowImpersonation
subscriptionStatus
activationStatus
featureFlags {
id
key

View File

@@ -28,6 +28,7 @@ export const GET_CURRENT_USER = gql`
inviteHash
allowImpersonation
subscriptionStatus
activationStatus
featureFlags {
id
key

View File

@@ -6,15 +6,14 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { motion } from 'framer-motion';
import { useRecoilValue } from 'recoil';
import { z } from 'zod';
import { Logo } from '@/auth/components/Logo';
import { Title } from '@/auth/components/Title';
import { useAuth } from '@/auth/hooks/useAuth';
import { useIsLogged } from '@/auth/hooks/useIsLogged';
import { useNavigateAfterSignInUp } from '@/auth/sign-in-up/hooks/useNavigateAfterSignInUp.ts';
import { PASSWORD_REGEX } from '@/auth/utils/passwordRegex';
import { billingState } from '@/client-config/states/billingState';
import { AppPath } from '@/types/AppPath';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { MainButton } from '@/ui/input/button/components/MainButton';
@@ -124,7 +123,7 @@ export const PasswordReset = () => {
const { signInWithCredentials } = useAuth();
const billing = useRecoilValue(billingState);
const { navigateAfterSignInUp } = useNavigateAfterSignInUp();
const onSubmit = async (formData: Form) => {
try {
@@ -150,25 +149,12 @@ export const PasswordReset = () => {
return;
}
const { workspace: currentWorkspace } = await signInWithCredentials(
email || '',
formData.newPassword,
);
const {
workspace: currentWorkspace,
workspaceMember: currentWorkspaceMember,
} = await signInWithCredentials(email || '', formData.newPassword);
if (
billing?.isBillingEnabled &&
currentWorkspace.subscriptionStatus !== 'active'
) {
navigate(AppPath.PlanRequired);
return;
}
if (currentWorkspace.displayName) {
navigate(AppPath.Index);
return;
}
navigate(AppPath.CreateWorkspace);
navigateAfterSignInUp(currentWorkspace, currentWorkspaceMember);
} catch (err) {
logError(err);
enqueueSnackBar(

View File

@@ -1,6 +1,5 @@
import { useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil';
import { useAuth } from '@/auth/hooks/useAuth';
@@ -25,7 +24,7 @@ export const VerifyEffect = () => {
} else {
await verify(loginToken);
if (isNonEmptyString(currentWorkspace?.displayName)) {
if (currentWorkspace?.activationStatus === 'active') {
navigate(AppPath.Index);
} else {
navigate(AppPath.CreateWorkspace);

View File

@@ -29,6 +29,7 @@ export const mockDefaultWorkspace: Workspace = {
logo: workspaceLogoUrl,
allowImpersonation: true,
subscriptionStatus: 'active',
activationStatus: 'active',
featureFlags: [],
createdAt: '2023-04-26T10:23:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',

View File

@@ -35,6 +35,10 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
return user.defaultWorkspace;
}
async isWorkspaceActivated(id: string): Promise<boolean> {
return await this.workspaceManagerService.doesDataSourceExist(id);
}
async deleteWorkspace(id: string, shouldDeleteCoreWorkspace = true) {
const workspace = await this.workspaceRepository.findOneBy({ id });

View File

@@ -62,4 +62,7 @@ export class Workspace {
@Field()
@Column({ default: 'incomplete' })
subscriptionStatus: 'incomplete' | 'active' | 'canceled';
@Field()
activationStatus: 'active' | 'inactive';
}

View File

@@ -1,4 +1,11 @@
import { Resolver, Query, Args, Mutation } from '@nestjs/graphql';
import {
Resolver,
Query,
Args,
Mutation,
ResolveField,
Parent,
} from '@nestjs/graphql';
import { ForbiddenException, UseGuards } from '@nestjs/common';
import { FileUpload, GraphQLUpload } from 'graphql-upload';
@@ -90,4 +97,15 @@ export class WorkspaceResolver {
return this.workspaceService.deleteWorkspace(id);
}
@ResolveField(() => String)
async activationStatus(
@Parent() workspace: Workspace,
): Promise<'active' | 'inactive'> {
if (await this.workspaceService.isWorkspaceActivated(workspace.id)) {
return 'active';
}
return 'inactive';
}
}

View File

@@ -80,6 +80,22 @@ export class WorkspaceManagerService {
await this.prefillWorkspaceWithDemoObjects(dataSourceMetadata, workspaceId);
}
/**
*
* Check if the workspace schema has already been created or not
*
* @param workspaceId
* @Returns Promise<boolean>
*/
public async doesDataSourceExist(workspaceId: string): Promise<boolean> {
const dataSource =
await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId(
workspaceId,
);
return dataSource.length > 0;
}
/**
*
* We are updating the pg_graphql max_rows from 30 (default value) to 60