diff --git a/front/src/modules/command-menu/components/CommandMenu.tsx b/front/src/modules/command-menu/components/CommandMenu.tsx index 842c6322a5..5901f75626 100644 --- a/front/src/modules/command-menu/components/CommandMenu.tsx +++ b/front/src/modules/command-menu/components/CommandMenu.tsx @@ -15,7 +15,9 @@ import { import { getLogoUrlFromDomainName } from '~/utils'; import { useCommandMenu } from '../hooks/useCommandMenu'; +import { commandMenuCommand } from '../states/commandMenuCommandsState'; import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState'; +import { CommandType } from '../types/Command'; import { CommandMenuItem } from './CommandMenuItem'; import { @@ -31,6 +33,8 @@ export function CommandMenu() { const openActivityRightDrawer = useOpenActivityRightDrawer(); const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState); const [search, setSearch] = useState(''); + const commands = useRecoilValue(commandMenuCommand); + useScopedHotkeys( 'ctrl+k,meta+k', @@ -77,36 +81,16 @@ export function CommandMenu() { }); const activities = activityData?.searchResults ?? []; - const commands = [ - { - to: '/people', - label: 'Go to People', - shortcuts: ['G', 'P'], - }, - { - to: '/companies', - label: 'Go to Companies', - shortcuts: ['G', 'C'], - }, - { - to: '/opportunities', - label: 'Go to Opportunities', - shortcuts: ['G', 'O'], - }, - { - to: '/settings/profile', - label: 'Go to Settings', - shortcuts: ['G', 'S'], - }, - { - to: '/tasks', - label: 'Go to Tasks', - shortcuts: ['G', 'T'], - }, - ]; + const matchingNavigateCommand = commands.find( + (cmd) => + cmd.shortcuts?.join('') === search?.toUpperCase() && + cmd.type === CommandType.Navigate, + ); - const matchingCommand = commands.find( - (cmd) => cmd.shortcuts.join('') === search?.toUpperCase(), + const matchingCreateCommand = commands.find( + (cmd) => + cmd.shortcuts?.join('') === search?.toUpperCase() && + cmd.type === CommandType.Create, ); /* @@ -164,12 +148,40 @@ export function CommandMenu() { /> No results found. - {matchingCommand && ( + {!matchingCreateCommand && ( + + {commands + .filter((cmd) => cmd.type === CommandType.Create) + .map((cmd) => ( + + ))} + + )} + {matchingCreateCommand && ( + + + + )} + {matchingNavigateCommand && ( )} @@ -223,17 +235,18 @@ export function CommandMenu() { ))} )} - {!matchingCommand && ( + {!matchingNavigateCommand && ( {commands .filter( (cmd) => - cmd.shortcuts?.join('').includes(search?.toUpperCase()) || - cmd.label?.toUpperCase().includes(search?.toUpperCase()), + (cmd.shortcuts?.join('').includes(search?.toUpperCase()) || + cmd.label?.toUpperCase().includes(search?.toUpperCase())) && + cmd.type === CommandType.Navigate, ) .map((cmd) => ( [...prev, ...addCommand]); + } + + function setToIntitialCommandMenu() { + setCommands(commandMenuCommands); + } + return { openCommandMenu, closeCommandMenu, + addToCommandMenu, + setToIntitialCommandMenu, }; } diff --git a/front/src/modules/command-menu/states/commandMenuCommandsState.ts b/front/src/modules/command-menu/states/commandMenuCommandsState.ts new file mode 100644 index 0000000000..8071bd8d89 --- /dev/null +++ b/front/src/modules/command-menu/states/commandMenuCommandsState.ts @@ -0,0 +1,14 @@ +import { atom } from 'recoil'; + +import { Command, CommandType } from '../types/Command'; + +export const commandMenuCommand = atom({ + key: 'command-menu/commandMenuCommand', + default: [ + { + to: '', + label: '', + type: CommandType.Navigate, + }, + ], +}); diff --git a/front/src/modules/command-menu/types/Command.ts b/front/src/modules/command-menu/types/Command.ts new file mode 100644 index 0000000000..7dd4164c99 --- /dev/null +++ b/front/src/modules/command-menu/types/Command.ts @@ -0,0 +1,13 @@ +export enum CommandType { + Navigate = 'Navigate', + Create = 'Create', +} + +export type Command = { + to: string; + label: string; + type: CommandType.Navigate | CommandType.Create; + icon?: JSX.Element; + shortcuts?: string[]; + onCommandClick?: () => void; +}; diff --git a/front/src/sync-hooks/AppInternalHooks.tsx b/front/src/sync-hooks/AppInternalHooks.tsx index 91340c8819..7152943957 100644 --- a/front/src/sync-hooks/AppInternalHooks.tsx +++ b/front/src/sync-hooks/AppInternalHooks.tsx @@ -1,9 +1,11 @@ +import { CommandMenuHook } from './CommandMenuHook'; import { GotoHotkeysHooks } from './GotoHotkeysHooks'; export function AppInternalHooks() { return ( <> + ); } diff --git a/front/src/sync-hooks/AuthAutoRouter.tsx b/front/src/sync-hooks/AuthAutoRouter.tsx index 274a35982c..1aa39e5857 100644 --- a/front/src/sync-hooks/AuthAutoRouter.tsx +++ b/front/src/sync-hooks/AuthAutoRouter.tsx @@ -1,15 +1,20 @@ import { useEffect, useState } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { matchPath, useLocation, useNavigate } from 'react-router-dom'; +import { IconCheckbox, IconNotes } from '@tabler/icons-react'; +import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { useEventTracker } from '@/analytics/hooks/useEventTracker'; import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; +import { CommandType } from '@/command-menu/types/Command'; import { AppBasePath } from '@/types/AppBasePath'; import { AppPath } from '@/types/AppPath'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { SettingsPath } from '@/types/SettingsPath'; import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; +import { ActivityType, CommentableType } from '~/generated/graphql'; import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation'; @@ -27,6 +32,10 @@ export function AuthAutoRouter() { const eventTracker = useEventTracker(); + const { addToCommandMenu, setToIntitialCommandMenu } = useCommandMenu(); + + const openCreateActivity = useOpenCreateActivityDrawer(); + useEffect(() => { if (!previousLocation || previousLocation !== location.pathname) { setPreviousLocation(location.pathname); @@ -129,6 +138,75 @@ export function AuthAutoRouter() { } } + setToIntitialCommandMenu(); + switch (true) { + case isMatchingLocation(AppPath.CompanyShowPage): { + const companyId = matchPath( + { path: '/companies/:id' }, + location.pathname, + )?.params.id; + + const entity = !!companyId + ? { id: companyId, type: CommentableType.Company } + : undefined; + + addToCommandMenu([ + { + to: '', + label: 'Create Task', + type: CommandType.Create, + icon: , + onCommandClick: () => openCreateActivity(ActivityType.Task, entity), + }, + { + to: '', + label: 'Create Note', + type: CommandType.Create, + icon: , + onCommandClick: () => openCreateActivity(ActivityType.Note, entity), + }, + ]); + break; + } + case isMatchingLocation(AppPath.PersonShowPage): { + const personId = matchPath({ path: '/person/:id' }, location.pathname) + ?.params.id; + + const entity = !!personId + ? { id: personId, type: CommentableType.Person } + : undefined; + + addToCommandMenu([ + { + to: '', + label: 'Create Task', + type: CommandType.Create, + icon: , + onCommandClick: () => openCreateActivity(ActivityType.Task, entity), + }, + { + to: '', + label: 'Create Note', + type: CommandType.Create, + icon: , + onCommandClick: () => openCreateActivity(ActivityType.Note, entity), + }, + ]); + break; + } + default: + addToCommandMenu([ + { + to: '', + label: 'Create Task', + type: CommandType.Create, + icon: , + onCommandClick: () => openCreateActivity(ActivityType.Task), + }, + ]); + break; + } + setTimeout(() => { eventTracker('pageview', { location: { @@ -144,6 +222,9 @@ export function AuthAutoRouter() { location, previousLocation, eventTracker, + addToCommandMenu, + openCreateActivity, + setToIntitialCommandMenu, ]); return <>; diff --git a/front/src/sync-hooks/CommandMenuHook.tsx b/front/src/sync-hooks/CommandMenuHook.tsx new file mode 100644 index 0000000000..42860ae3cb --- /dev/null +++ b/front/src/sync-hooks/CommandMenuHook.tsx @@ -0,0 +1,13 @@ +import { useSetRecoilState } from 'recoil'; + +import { commandMenuCommands } from '@/command-menu/constants/commandMenuCommands'; +import { commandMenuCommand } from '@/command-menu/states/commandMenuCommandsState'; + +export function CommandMenuHook() { + const setCommands = useSetRecoilState(commandMenuCommand); + + const commands = commandMenuCommands; + setCommands(commands); + + return <>; +}