Feat/better hotkeys scope (#526)

* Working version

* fix

* Fixed console log

* Fix lint

* wip

* Fix

* Fix

* consolelog

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2023-07-08 03:53:05 +02:00
committed by GitHub
parent 611cda1f41
commit 66dcc9b2e1
77 changed files with 1240 additions and 454 deletions

View File

@ -1,16 +1,17 @@
import { useCallback, useEffect, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useNavigate } from 'react-router-dom';
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { SubTitle } from '@/auth/components/ui/SubTitle';
import { Title } from '@/auth/components/ui/Title';
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
import { currentUserState } from '@/auth/states/currentUserState';
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
import { captureHotkeyTypeInFocusState } from '@/hotkeys/states/captureHotkeyTypeInFocusState';
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { MainButton } from '@/ui/components/buttons/MainButton';
import { ImageInput } from '@/ui/components/inputs/ImageInput';
import { TextInput } from '@/ui/components/inputs/TextInput';
@ -48,9 +49,6 @@ export function CreateProfile() {
const onboardingStatus = useOnboardingStatus();
const [currentUser] = useRecoilState(currentUserState);
const [, setCaptureHotkeyTypeInFocus] = useRecoilState(
captureHotkeyTypeInFocusState,
);
const [updateUser] = useUpdateUserMutation();
@ -85,29 +83,18 @@ export function CreateProfile() {
throw errors;
}
setCaptureHotkeyTypeInFocus(false);
navigate('/');
} catch (error) {
console.error(error);
}
}, [
currentUser?.id,
firstName,
lastName,
navigate,
setCaptureHotkeyTypeInFocus,
updateUser,
]);
}, [currentUser?.id, firstName, lastName, navigate, updateUser]);
useHotkeys(
'enter',
useScopedHotkeys(
Key.Enter,
() => {
handleCreate();
},
{
enableOnContentEditable: true,
enableOnFormTags: true,
},
InternalHotkeysScope.Modal,
[handleCreate],
);
@ -117,10 +104,6 @@ export function CreateProfile() {
}
}, [onboardingStatus, navigate]);
useEffect(() => {
setCaptureHotkeyTypeInFocus(true);
}, [setCaptureHotkeyTypeInFocus]);
return (
<>
<Title>Create profile</Title>

View File

@ -1,5 +1,4 @@
import { useCallback, useEffect, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useNavigate } from 'react-router-dom';
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled';
@ -8,6 +7,8 @@ import { SubTitle } from '@/auth/components/ui/SubTitle';
import { Title } from '@/auth/components/ui/Title';
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { MainButton } from '@/ui/components/buttons/MainButton';
import { ImageInput } from '@/ui/components/inputs/ImageInput';
import { TextInput } from '@/ui/components/inputs/TextInput';
@ -68,15 +69,12 @@ export function CreateWorkspace() {
}
}, [navigate, updateWorkspace, workspaceName]);
useHotkeys(
useScopedHotkeys(
'enter',
() => {
handleCreate();
},
{
enableOnContentEditable: true,
enableOnFormTags: true,
},
InternalHotkeysScope.Modal,
[handleCreate],
);

View File

@ -1,5 +1,4 @@
import { useCallback, useEffect, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useNavigate } from 'react-router-dom';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
@ -13,7 +12,8 @@ import { Title } from '@/auth/components/ui/Title';
import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState';
import { isMockModeState } from '@/auth/states/isMockModeState';
import { authProvidersState } from '@/client-config/states/authProvidersState';
import { captureHotkeyTypeInFocusState } from '@/hotkeys/states/captureHotkeyTypeInFocusState';
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { MainButton } from '@/ui/components/buttons/MainButton';
import { TextInput } from '@/ui/components/inputs/TextInput';
import { AnimatedEaseIn } from '@/ui/components/motion/AnimatedEaseIn';
@ -31,9 +31,6 @@ const StyledFooterNote = styled(FooterNote)`
`;
export function Index() {
const [, setCaptureHotkeyTypeInFocus] = useRecoilState(
captureHotkeyTypeInFocusState,
);
const navigate = useNavigate();
const theme = useTheme();
const [, setMockMode] = useRecoilState(isMockModeState);
@ -59,29 +56,19 @@ export function Index() {
navigate('/auth/password-login');
}, [navigate, visible]);
useHotkeys(
useScopedHotkeys(
'enter',
() => {
onPasswordLoginClick();
},
{
enableOnContentEditable: true,
enableOnFormTags: true,
},
InternalHotkeysScope.Modal,
[onPasswordLoginClick],
);
useEffect(() => {
setMockMode(true);
setCaptureHotkeyTypeInFocus(true);
setAuthFlowUserEmail(demoMode ? 'tim@apple.dev' : '');
}, [
navigate,
setMockMode,
setCaptureHotkeyTypeInFocus,
setAuthFlowUserEmail,
demoMode,
]);
}, [navigate, setMockMode, setAuthFlowUserEmail, demoMode]);
return (
<>

View File

@ -1,5 +1,4 @@
import { useCallback, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useNavigate } from 'react-router-dom';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
@ -12,6 +11,8 @@ import { useAuth } from '@/auth/hooks/useAuth';
import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState';
import { isMockModeState } from '@/auth/states/isMockModeState';
import { isDemoModeState } from '@/client-config/states/isDemoModeState';
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { MainButton } from '@/ui/components/buttons/MainButton';
import { TextInput } from '@/ui/components/inputs/TextInput';
import { SubSectionTitle } from '@/ui/components/section-titles/SubSectionTitle';
@ -74,15 +75,12 @@ export function PasswordLogin() {
}
}, [login, authFlowUserEmail, internalPassword, setMockMode, navigate]);
useHotkeys(
useScopedHotkeys(
'enter',
() => {
handleLogin();
},
{
enableOnContentEditable: true,
enableOnFormTags: true,
},
InternalHotkeysScope.Modal,
[handleLogin],
);

View File

@ -1,9 +1,13 @@
import { getOperationName } from '@apollo/client/utilities';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { v4 as uuidv4 } from 'uuid';
import { isMockModeState } from '@/auth/states/isMockModeState';
import { GET_COMPANIES } from '@/companies/services';
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar';
import { IconBuildingSkyscraper } from '@/ui/icons/index';
@ -24,6 +28,18 @@ const StyledTableContainer = styled.div`
`;
export function Companies() {
const [isMockMode] = useRecoilState(isMockModeState);
const hotkeysEnabled = !isMockMode;
useHotkeysScopeOnMountOnly(
{
scope: InternalHotkeysScope.Table,
customScopes: { 'command-menu': true, goto: true },
},
hotkeysEnabled,
);
const [insertCompany] = useInsertCompanyMutation();
async function handleAddButtonClick() {
@ -45,20 +61,22 @@ export function Companies() {
const theme = useTheme();
return (
<WithTopBarContainer
title="Companies"
icon={<IconBuildingSkyscraper size={theme.icon.size.md} />}
onAddButtonClick={handleAddButtonClick}
>
<RecoilScope SpecificContext={TableContext}>
<StyledTableContainer>
<CompanyTable />
</StyledTableContainer>
<EntityTableActionBar>
<TableActionBarButtonCreateCommentThreadCompany />
<TableActionBarButtonDeleteCompanies />
</EntityTableActionBar>
</RecoilScope>
</WithTopBarContainer>
<>
<WithTopBarContainer
title="Companies"
icon={<IconBuildingSkyscraper size={theme.icon.size.md} />}
onAddButtonClick={handleAddButtonClick}
>
<RecoilScope SpecificContext={TableContext}>
<StyledTableContainer>
<CompanyTable />
</StyledTableContainer>
<EntityTableActionBar>
<TableActionBarButtonCreateCommentThreadCompany />
<TableActionBarButtonDeleteCompanies />
</EntityTableActionBar>
</RecoilScope>
</WithTopBarContainer>
</>
);
}

View File

@ -3,6 +3,8 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { v4 as uuidv4 } from 'uuid';
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { GET_PEOPLE } from '@/people/services';
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar';
@ -22,6 +24,11 @@ const StyledPeopleContainer = styled.div`
`;
export function People() {
useHotkeysScopeOnMountOnly({
scope: InternalHotkeysScope.Table,
customScopes: { 'command-menu': true, goto: true },
});
const [insertPersonMutation] = useInsertPersonMutation();
async function handleAddButtonClick() {