mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-22 19:41:53 +03:00
Change to using arrow functions (#1603)
* Change to using arrow functions Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Matheus <matheus_benini@hotmail.com> * Add lint rule --------- Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Matheus <matheus_benini@hotmail.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
parent
549335054a
commit
00a3c8ca2b
@ -22,7 +22,7 @@ export const myAtomState = atom({
|
|||||||
default: 'default value',
|
default: 'default value',
|
||||||
});
|
});
|
||||||
|
|
||||||
export function MyComponent() {
|
export const MyComponent = () => {
|
||||||
const [myAtom, setMyAtom] = useRecoilState(myAtomState);
|
const [myAtom, setMyAtom] = useRecoilState(myAtomState);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -79,7 +79,7 @@ The same can be applied for data fetching logic, with Apollo hooks.
|
|||||||
```tsx
|
```tsx
|
||||||
// ❌ Bad, will cause re-renders even if data is not changing,
|
// ❌ Bad, will cause re-renders even if data is not changing,
|
||||||
// because useEffect needs to be re-evaluated
|
// because useEffect needs to be re-evaluated
|
||||||
export function PageComponent() {
|
export const PageComponent = () => {
|
||||||
const [data, setData] = useRecoilState(dataState);
|
const [data, setData] = useRecoilState(dataState);
|
||||||
const [someDependency] = useRecoilState(someDependencyState);
|
const [someDependency] = useRecoilState(someDependencyState);
|
||||||
|
|
||||||
@ -92,25 +92,23 @@ export function PageComponent() {
|
|||||||
return <div>{data}</div>;
|
return <div>{data}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function App() {
|
export const App = () => (
|
||||||
return (
|
<RecoilRoot>
|
||||||
<RecoilRoot>
|
<PageComponent />
|
||||||
<PageComponent />
|
</RecoilRoot>
|
||||||
</RecoilRoot>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// ✅ Good, will not cause re-renders if data is not changing,
|
// ✅ Good, will not cause re-renders if data is not changing,
|
||||||
// because useEffect is re-evaluated in another sibling component
|
// because useEffect is re-evaluated in another sibling component
|
||||||
export function PageComponent() {
|
export const PageComponent = () => {
|
||||||
const [data, setData] = useRecoilState(dataState);
|
const [data, setData] = useRecoilState(dataState);
|
||||||
|
|
||||||
return <div>{data}</div>;
|
return <div>{data}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function PageData() {
|
export const PageData = () => {
|
||||||
const [data, setData] = useRecoilState(dataState);
|
const [data, setData] = useRecoilState(dataState);
|
||||||
const [someDependency] = useRecoilState(someDependencyState);
|
const [someDependency] = useRecoilState(someDependencyState);
|
||||||
|
|
||||||
@ -123,14 +121,12 @@ export function PageData() {
|
|||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function App() {
|
export const App = () => (
|
||||||
return (
|
<RecoilRoot>
|
||||||
<RecoilRoot>
|
<PageData />
|
||||||
<PageData />
|
<PageComponent />
|
||||||
<PageComponent />
|
</RecoilRoot>
|
||||||
</RecoilRoot>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use recoil family states and recoil family selectors
|
### Use recoil family states and recoil family selectors
|
||||||
@ -189,16 +185,16 @@ Event handler names should start with `handle`, `on` is a prefix used to name ev
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// ❌ Bad
|
// ❌ Bad
|
||||||
function onEmailChange(val: string) {
|
const onEmailChange = (val: string) => {
|
||||||
// ...
|
// ...
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// ✅ Good
|
// ✅ Good
|
||||||
function handleEmailChange(val: string) {
|
const handleEmailChange = (val: string) => {
|
||||||
// ...
|
// ...
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Optional Props
|
## Optional Props
|
||||||
@ -215,25 +211,21 @@ type OwnProps = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function EmailField({ value, disabled = false }: OwnProps) {
|
const EmailField = ({ value, disabled = false }: OwnProps) => (
|
||||||
return <TextInput value={value} disabled={disabled} fullWidth />;
|
<TextInput value={value} disabled={disabled} fullWidth />
|
||||||
}
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// ❌ Bad, passing in the same value as the default value adds no value
|
// ❌ Bad, passing in the same value as the default value adds no value
|
||||||
function Form() {
|
const Form = () => <EmailField value="username@email.com" disabled={false} />;
|
||||||
return <EmailField value="username@email.com" disabled={false} />;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// ✅ Good, assumes the default value
|
// ✅ Good, assumes the default value
|
||||||
function Form() {
|
const Form = () => <EmailField value="username@email.com" />;
|
||||||
return <EmailField value="username@email.com" />;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Component as props
|
## Component as props
|
||||||
@ -243,14 +235,10 @@ Try as much as possible to pass uninstanciated components as props, so chilren c
|
|||||||
The most common example for that is icon components :
|
The most common example for that is icon components :
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
function SomeParentComponent() {
|
const SomeParentComponent = () => <MyComponent Icon={MyIcon} />;
|
||||||
return (
|
|
||||||
<MyComponent Icon={MyIcon} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// In MyComponent
|
// In MyComponent
|
||||||
function MyComponent({ MyIcon }: { MyIcon: IconComponent }) {
|
const MyComponent = ({ MyIcon }: { MyIcon: IconComponent }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -258,7 +246,7 @@ function MyComponent({ MyIcon }: { MyIcon: IconComponent }) {
|
|||||||
<MyIcon size={theme.icon.size.md}>
|
<MyIcon size={theme.icon.size.md}>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
For React to understand that the component is a component, you need to use PascalCase, to later instanciate it with `<MyIcon>`
|
For React to understand that the component is a component, you need to use PascalCase, to later instanciate it with `<MyIcon>`
|
||||||
|
@ -46,18 +46,14 @@ Use props destructuring.
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// ❌ Bad, no type
|
// ❌ Bad, no type
|
||||||
export function MyComponent(props) {
|
export const MyComponent = (props) => <div>Hello {props.name}</div>;
|
||||||
return <div>Hello {props.name}</div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ Good, type
|
// ✅ Good, type
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MyComponent({ name }: OwnProps) {
|
export const MyComponent = ({ name }: OwnProps) => <div>Hello {name}</div>;
|
||||||
return <div>Hello {name}</div>;
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Refrain from using `React.FC` or `React.FunctionComponent` to define prop types.
|
#### Refrain from using `React.FC` or `React.FunctionComponent` to define prop types.
|
||||||
@ -84,9 +80,9 @@ type OwnProps = {
|
|||||||
value: string;
|
value: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function EmailField({ value }: OwnProps) {
|
const EmailField = ({ value }: OwnProps) => (
|
||||||
return <TextInput value={value} disabled fullWidth />;
|
<TextInput value={value} disabled fullWidth />
|
||||||
}
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
@ -1,34 +1,38 @@
|
|||||||
import { createGraphiQLFetcher } from '@graphiql/toolkit';
|
import { createGraphiQLFetcher } from "@graphiql/toolkit";
|
||||||
import { GraphiQL } from 'graphiql';
|
import { GraphiQL } from "graphiql";
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from "react-dom";
|
||||||
import Layout from '@theme/Layout';
|
import Layout from "@theme/Layout";
|
||||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
import BrowserOnly from "@docusaurus/BrowserOnly";
|
||||||
|
|
||||||
import 'graphiql/graphiql.css';
|
|
||||||
|
|
||||||
|
import "graphiql/graphiql.css";
|
||||||
|
|
||||||
// Docusaurus does SSR for custom pages but we need to load GraphiQL in the browser
|
// Docusaurus does SSR for custom pages but we need to load GraphiQL in the browser
|
||||||
function GraphiQLComponent() {
|
const GraphiQLComponent = () => {
|
||||||
if(!window.localStorage.getItem('graphiql:theme') && window.localStorage.getItem('theme') != 'dark') {
|
if (
|
||||||
window.localStorage.setItem('graphiql:theme', 'light');
|
!window.localStorage.getItem("graphiql:theme") &&
|
||||||
}
|
window.localStorage.getItem("theme") != "dark"
|
||||||
|
) {
|
||||||
|
window.localStorage.setItem("graphiql:theme", "light");
|
||||||
|
}
|
||||||
|
|
||||||
const fetcher = createGraphiQLFetcher({ url: 'https://api.twenty.com/graphql' });
|
const fetcher = createGraphiQLFetcher({
|
||||||
|
url: "https://api.twenty.com/graphql",
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<div className="fullHeightPlayground">
|
<div className="fullHeightPlayground">
|
||||||
<GraphiQL fetcher={fetcher} />;
|
<GraphiQL fetcher={fetcher} />;
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function graphQL() {
|
const graphQL = () => (
|
||||||
return (
|
<Layout
|
||||||
<Layout title="GraphQL Playground" description="GraphQL Playground for Twenty">
|
title="GraphQL Playground"
|
||||||
|
description="GraphQL Playground for Twenty"
|
||||||
<BrowserOnly>
|
>
|
||||||
{() => <GraphiQLComponent />}
|
<BrowserOnly>{() => <GraphiQLComponent />}</BrowserOnly>
|
||||||
</BrowserOnly>
|
</Layout>
|
||||||
</Layout>
|
);
|
||||||
);
|
|
||||||
}
|
export default graphQL;
|
||||||
|
@ -32,14 +32,14 @@ import {
|
|||||||
} from "react-icons/tb";
|
} from "react-icons/tb";
|
||||||
|
|
||||||
|
|
||||||
export default function DocSidebarItemLink({
|
const DocSidebarItemLink = ({
|
||||||
item,
|
item,
|
||||||
onItemClick,
|
onItemClick,
|
||||||
activePath,
|
activePath,
|
||||||
level,
|
level,
|
||||||
index,
|
index,
|
||||||
...props
|
...props
|
||||||
}) {
|
}) => {
|
||||||
const {href, label, className, autoAddBaseUrl, customProps = {}} = item;
|
const {href, label, className, autoAddBaseUrl, customProps = {}} = item;
|
||||||
const isActive = isActiveSidebarItem(item, activePath);
|
const isActive = isActiveSidebarItem(item, activePath);
|
||||||
const isInternalLink = isInternalUrl(href);
|
const isInternalLink = isInternalUrl(href);
|
||||||
@ -104,3 +104,5 @@ export default function DocSidebarItemLink({
|
|||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default DocSidebarItemLink;
|
||||||
|
@ -3,7 +3,9 @@ import { TbMoon } from 'react-icons/tb';
|
|||||||
import {useColorMode} from '@docusaurus/theme-common';
|
import {useColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
|
|
||||||
export default function IconDarkMode(props) {
|
const IconDarkMode = (props) => {
|
||||||
const { colorMode } = useColorMode().colorMode;
|
const { colorMode } = useColorMode().colorMode;
|
||||||
return colorMode === 'dark' ? <TbMoon /> : <></>;
|
return colorMode === 'dark' ? <TbMoon /> : <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default IconDarkMode
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import { TbHome } from 'react-icons/tb';
|
import { TbHome } from "react-icons/tb";
|
||||||
export default function IconHome(props) {
|
const IconHome = (props) => <TbHome size={14} />;
|
||||||
return <TbHome size={14} />;
|
|
||||||
}
|
export default IconHome;
|
||||||
|
@ -3,7 +3,9 @@ import { TbSun } from 'react-icons/tb';
|
|||||||
import {useColorMode} from '@docusaurus/theme-common';
|
import {useColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
|
|
||||||
export default function IconLightMode(props) {
|
const IconLightMode = (props) => {
|
||||||
const { colorMode } = useColorMode().colorMode;
|
const { colorMode } = useColorMode().colorMode;
|
||||||
return colorMode === 'dark' ? <></>: <TbSun /> ;
|
return colorMode === 'dark' ? <></>: <TbSun /> ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default IconLightMode;
|
||||||
|
@ -5,7 +5,14 @@ module.exports = {
|
|||||||
tsconfigRootDir: __dirname,
|
tsconfigRootDir: __dirname,
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
},
|
},
|
||||||
plugins: ['@typescript-eslint/eslint-plugin', 'unused-imports', 'simple-import-sort', 'twenty', 'twenty-ts'],
|
plugins: [
|
||||||
|
'@typescript-eslint/eslint-plugin',
|
||||||
|
'unused-imports',
|
||||||
|
'simple-import-sort',
|
||||||
|
'prefer-arrow',
|
||||||
|
'twenty',
|
||||||
|
'twenty-ts',
|
||||||
|
],
|
||||||
extends: [
|
extends: [
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'plugin:prettier/recommended',
|
'plugin:prettier/recommended',
|
||||||
@ -34,6 +41,14 @@ module.exports = {
|
|||||||
['^.+\\.?(css)$']
|
['^.+\\.?(css)$']
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
'prefer-arrow/prefer-arrow-functions': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
"disallowPrototype": true,
|
||||||
|
"singleReturnOnly": false,
|
||||||
|
"classPropertiesAllowed": false
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -161,6 +161,7 @@
|
|||||||
"eslint-config-standard-with-typescript": "^23.0.0",
|
"eslint-config-standard-with-typescript": "^23.0.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-n": "^15.5.1",
|
"eslint-plugin-n": "^15.5.1",
|
||||||
|
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-react": "^7.31.11",
|
"eslint-plugin-react": "^7.31.11",
|
||||||
|
@ -28,7 +28,7 @@ import { getPageTitleFromPath } from './utils/title-utils';
|
|||||||
// TEMP FEATURE FLAG FOR VIEW FIELDS
|
// TEMP FEATURE FLAG FOR VIEW FIELDS
|
||||||
export const ACTIVATE_VIEW_FIELDS = true;
|
export const ACTIVATE_VIEW_FIELDS = true;
|
||||||
|
|
||||||
export function App() {
|
export const App = () => {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const pageTitle = getPageTitleFromPath(pathname);
|
const pageTitle = getPageTitleFromPath(pathname);
|
||||||
|
|
||||||
@ -82,4 +82,4 @@ export function App() {
|
|||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -20,7 +20,7 @@ import NavTitle from '@/ui/navbar/components/NavTitle';
|
|||||||
|
|
||||||
import { measureTotalFrameLoad } from './utils/measureTotalFrameLoad';
|
import { measureTotalFrameLoad } from './utils/measureTotalFrameLoad';
|
||||||
|
|
||||||
export function AppNavbar() {
|
export const AppNavbar = () => {
|
||||||
const currentPath = useLocation().pathname;
|
const currentPath = useLocation().pathname;
|
||||||
const { openCommandMenu } = useCommandMenu();
|
const { openCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
@ -94,4 +94,4 @@ export function AppNavbar() {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -4,7 +4,7 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
import { commandMenuCommands } from '@/command-menu/constants/commandMenuCommands';
|
import { commandMenuCommands } from '@/command-menu/constants/commandMenuCommands';
|
||||||
import { commandMenuCommandsState } from '@/command-menu/states/commandMenuCommandsState';
|
import { commandMenuCommandsState } from '@/command-menu/states/commandMenuCommandsState';
|
||||||
|
|
||||||
export function CommandMenuEffect() {
|
export const CommandMenuEffect = () => {
|
||||||
const setCommands = useSetRecoilState(commandMenuCommandsState);
|
const setCommands = useSetRecoilState(commandMenuCommandsState);
|
||||||
|
|
||||||
const commands = commandMenuCommands;
|
const commands = commandMenuCommands;
|
||||||
@ -13,4 +13,4 @@ export function CommandMenuEffect() {
|
|||||||
}, [commands, setCommands]);
|
}, [commands, setCommands]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useGoToHotkeys } from '@/ui/utilities/hotkey/hooks/useGoToHotkeys';
|
import { useGoToHotkeys } from '@/ui/utilities/hotkey/hooks/useGoToHotkeys';
|
||||||
|
|
||||||
export function GotoHotkeysEffect() {
|
export const GotoHotkeysEffect = () => {
|
||||||
useGoToHotkeys('p', '/people');
|
useGoToHotkeys('p', '/people');
|
||||||
useGoToHotkeys('c', '/companies');
|
useGoToHotkeys('c', '/companies');
|
||||||
useGoToHotkeys('o', '/opportunities');
|
useGoToHotkeys('o', '/opportunities');
|
||||||
@ -8,4 +8,4 @@ export function GotoHotkeysEffect() {
|
|||||||
useGoToHotkeys('t', '/tasks');
|
useGoToHotkeys('t', '/tasks');
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
};
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
|
||||||
|
|
||||||
// TODO: break down into smaller functions and / or hooks
|
// TODO: break down into smaller functions and / or hooks
|
||||||
export function PageChangeEffect() {
|
export const PageChangeEffect = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const isMatchingLocation = useIsMatchingLocation();
|
const isMatchingLocation = useIsMatchingLocation();
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
@ -66,12 +66,12 @@ export function PageChangeEffect() {
|
|||||||
isMatchingLocation(AppPath.CreateWorkspace) ||
|
isMatchingLocation(AppPath.CreateWorkspace) ||
|
||||||
isMatchingLocation(AppPath.CreateProfile);
|
isMatchingLocation(AppPath.CreateProfile);
|
||||||
|
|
||||||
function navigateToSignUp() {
|
const navigateToSignUp = () => {
|
||||||
enqueueSnackBar('workspace does not exist', {
|
enqueueSnackBar('workspace does not exist', {
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
});
|
});
|
||||||
navigate(AppPath.SignUp);
|
navigate(AppPath.SignUp);
|
||||||
}
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.OngoingUserCreation &&
|
onboardingStatus === OnboardingStatus.OngoingUserCreation &&
|
||||||
@ -281,4 +281,4 @@ export function PageChangeEffect() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
};
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React, { Ref, RefCallback } from 'react';
|
import React, { Ref, RefCallback } from 'react';
|
||||||
|
|
||||||
export function useCombinedRefs<T>(
|
export const useCombinedRefs =
|
||||||
...refs: (Ref<T> | undefined)[]
|
<T>(...refs: (Ref<T> | undefined)[]): RefCallback<T> =>
|
||||||
): RefCallback<T> {
|
(node: T) => {
|
||||||
return (node: T) => {
|
|
||||||
for (const ref of refs) {
|
for (const ref of refs) {
|
||||||
if (typeof ref === 'function') {
|
if (typeof ref === 'function') {
|
||||||
ref(node);
|
ref(node);
|
||||||
@ -12,4 +11,3 @@ export function useCombinedRefs<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
export function useFirstMountState(): boolean {
|
export const useFirstMountState = (): boolean => {
|
||||||
const isFirst = useRef(true);
|
const isFirst = useRef(true);
|
||||||
|
|
||||||
if (isFirst.current) {
|
if (isFirst.current) {
|
||||||
@ -10,4 +10,4 @@ export function useFirstMountState(): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return isFirst.current;
|
return isFirst.current;
|
||||||
}
|
};
|
||||||
|
@ -3,14 +3,14 @@ import { parse } from 'url';
|
|||||||
|
|
||||||
import { AppBasePath } from '@/types/AppBasePath';
|
import { AppBasePath } from '@/types/AppBasePath';
|
||||||
|
|
||||||
export function useIsMatchingLocation() {
|
export const useIsMatchingLocation = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
return function isMatchingLocation(path: string, basePath?: AppBasePath) {
|
return (path: string, basePath?: AppBasePath) => {
|
||||||
const constructedPath = basePath
|
const constructedPath = basePath
|
||||||
? parse(`${basePath}/${path}`).pathname ?? ''
|
? parse(`${basePath}/${path}`).pathname ?? ''
|
||||||
: path;
|
: path;
|
||||||
|
|
||||||
return !!matchPath(constructedPath, location.pathname);
|
return !!matchPath(constructedPath, location.pathname);
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -2,7 +2,10 @@ import { DependencyList, EffectCallback, useEffect } from 'react';
|
|||||||
|
|
||||||
import { useFirstMountState } from './useFirstMountState';
|
import { useFirstMountState } from './useFirstMountState';
|
||||||
|
|
||||||
export function useUpdateEffect(effect: EffectCallback, deps?: DependencyList) {
|
export const useUpdateEffect = (
|
||||||
|
effect: EffectCallback,
|
||||||
|
deps?: DependencyList,
|
||||||
|
) => {
|
||||||
const isFirst = useFirstMountState();
|
const isFirst = useFirstMountState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -11,4 +14,4 @@ export function useUpdateEffect(effect: EffectCallback, deps?: DependencyList) {
|
|||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, deps);
|
}, deps);
|
||||||
}
|
};
|
||||||
|
@ -30,11 +30,9 @@ const StyledCommentBody = styled.div`
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function Comment({ comment, actionBar }: OwnProps) {
|
export const Comment = ({ comment, actionBar }: OwnProps) => (
|
||||||
return (
|
<StyledContainer>
|
||||||
<StyledContainer>
|
<CommentHeader comment={comment} actionBar={actionBar} />
|
||||||
<CommentHeader comment={comment} actionBar={actionBar} />
|
<StyledCommentBody>{comment.body}</StyledCommentBody>
|
||||||
<StyledCommentBody>{comment.body}</StyledCommentBody>
|
</StyledContainer>
|
||||||
</StyledContainer>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -62,7 +62,7 @@ const StyledTooltip = styled(Tooltip)`
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function CommentHeader({ comment, actionBar }: OwnProps) {
|
export const CommentHeader = ({ comment, actionBar }: OwnProps) => {
|
||||||
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(comment.createdAt);
|
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(comment.createdAt);
|
||||||
const exactCreatedAt = beautifyExactDateTime(comment.createdAt);
|
const exactCreatedAt = beautifyExactDateTime(comment.createdAt);
|
||||||
const showDate = beautifiedCreatedAt !== '';
|
const showDate = beautifiedCreatedAt !== '';
|
||||||
@ -99,4 +99,4 @@ export function CommentHeader({ comment, actionBar }: OwnProps) {
|
|||||||
<div>{actionBar}</div>
|
<div>{actionBar}</div>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -30,11 +30,11 @@ type UserForSelect = EntityForSelect & {
|
|||||||
entityType: Entity.User;
|
entityType: Entity.User;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityAssigneePicker({
|
export const ActivityAssigneePicker = ({
|
||||||
activity,
|
activity,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const [relationPickerSearchFilter] = useRecoilScopedState(
|
const [relationPickerSearchFilter] = useRecoilScopedState(
|
||||||
relationPickerSearchFilterScopedState,
|
relationPickerSearchFilterScopedState,
|
||||||
);
|
);
|
||||||
@ -68,9 +68,9 @@ export function ActivityAssigneePicker({
|
|||||||
fragment: ACTIVITY_UPDATE_FRAGMENT,
|
fragment: ACTIVITY_UPDATE_FRAGMENT,
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleEntitySelected(
|
const handleEntitySelected = async (
|
||||||
selectedUser: UserForSelect | null | undefined,
|
selectedUser: UserForSelect | null | undefined,
|
||||||
) {
|
) => {
|
||||||
if (selectedUser) {
|
if (selectedUser) {
|
||||||
const workspaceMemberAssignee = (
|
const workspaceMemberAssignee = (
|
||||||
await getWorkspaceMember({
|
await getWorkspaceMember({
|
||||||
@ -108,7 +108,7 @@ export function ActivityAssigneePicker({
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit?.();
|
onSubmit?.();
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleEntitySelect
|
<SingleEntitySelect
|
||||||
@ -119,4 +119,4 @@ export function ActivityAssigneePicker({
|
|||||||
selectedEntity={users.selectedEntities[0]}
|
selectedEntity={users.selectedEntities[0]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -19,7 +19,7 @@ type OwnProps = {
|
|||||||
onChange?: (activityBody: string) => void;
|
onChange?: (activityBody: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityBodyEditor({ activity, onChange }: OwnProps) {
|
export const ActivityBodyEditor = ({ activity, onChange }: OwnProps) => {
|
||||||
const [updateActivityMutation] = useUpdateActivityMutation();
|
const [updateActivityMutation] = useUpdateActivityMutation();
|
||||||
|
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
@ -37,7 +37,7 @@ export function ActivityBodyEditor({ activity, onChange }: OwnProps) {
|
|||||||
}, [body, onChange]);
|
}, [body, onChange]);
|
||||||
|
|
||||||
const debounceOnChange = useMemo(() => {
|
const debounceOnChange = useMemo(() => {
|
||||||
function onInternalChange(activityBody: string) {
|
const onInternalChange = (activityBody: string) => {
|
||||||
setBody(activityBody);
|
setBody(activityBody);
|
||||||
updateActivityMutation({
|
updateActivityMutation({
|
||||||
variables: {
|
variables: {
|
||||||
@ -56,7 +56,7 @@ export function ActivityBodyEditor({ activity, onChange }: OwnProps) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return debounce(onInternalChange, 200);
|
return debounce(onInternalChange, 200);
|
||||||
}, [updateActivityMutation, activity.id, cachedActivity]);
|
}, [updateActivityMutation, activity.id, cachedActivity]);
|
||||||
@ -74,4 +74,4 @@ export function ActivityBodyEditor({ activity, onChange }: OwnProps) {
|
|||||||
<BlockEditor editor={editor} />
|
<BlockEditor editor={editor} />
|
||||||
</StyledBlockNoteStyledContainer>
|
</StyledBlockNoteStyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -59,10 +59,10 @@ const StyledThreadCommentTitle = styled.div`
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function ActivityComments({
|
export const ActivityComments = ({
|
||||||
activity,
|
activity,
|
||||||
scrollableContainerRef,
|
scrollableContainerRef,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const [createCommentMutation] = useCreateCommentMutation();
|
const [createCommentMutation] = useCreateCommentMutation();
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ export function ActivityComments({
|
|||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSendComment(commentText: string) {
|
const handleSendComment = (commentText: string) => {
|
||||||
if (!isNonEmptyString(commentText)) {
|
if (!isNonEmptyString(commentText)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -91,16 +91,16 @@ export function ActivityComments({
|
|||||||
},
|
},
|
||||||
awaitRefetchQueries: true,
|
awaitRefetchQueries: true,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleFocus() {
|
const handleFocus = () => {
|
||||||
const scrollableContainer = scrollableContainerRef.current;
|
const scrollableContainer = scrollableContainerRef.current;
|
||||||
|
|
||||||
scrollableContainer?.scrollTo({
|
scrollableContainer?.scrollTo({
|
||||||
top: scrollableContainer.scrollHeight,
|
top: scrollableContainer.scrollHeight,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -127,4 +127,4 @@ export function ActivityComments({
|
|||||||
</StyledCommentActionBar>
|
</StyledCommentActionBar>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -8,21 +8,19 @@ type ActivityCreateButtonProps = {
|
|||||||
onActivityClick?: () => void;
|
onActivityClick?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityCreateButton({
|
export const ActivityCreateButton = ({
|
||||||
onNoteClick,
|
onNoteClick,
|
||||||
onTaskClick,
|
onTaskClick,
|
||||||
onActivityClick,
|
onActivityClick,
|
||||||
}: ActivityCreateButtonProps) {
|
}: ActivityCreateButtonProps) => (
|
||||||
return (
|
<ButtonGroup variant={'secondary'}>
|
||||||
<ButtonGroup variant={'secondary'}>
|
<Button Icon={IconNotes} title="Note" onClick={onNoteClick} />
|
||||||
<Button Icon={IconNotes} title="Note" onClick={onNoteClick} />
|
<Button Icon={IconCheckbox} title="Task" onClick={onTaskClick} />
|
||||||
<Button Icon={IconCheckbox} title="Task" onClick={onTaskClick} />
|
<Button
|
||||||
<Button
|
Icon={IconTimelineEvent}
|
||||||
Icon={IconTimelineEvent}
|
title="Activity"
|
||||||
title="Activity"
|
soon={true}
|
||||||
soon={true}
|
onClick={onActivityClick}
|
||||||
onClick={onActivityClick}
|
/>
|
||||||
/>
|
</ButtonGroup>
|
||||||
</ButtonGroup>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -79,11 +79,11 @@ type OwnProps = {
|
|||||||
autoFillTitle?: boolean;
|
autoFillTitle?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityEditor({
|
export const ActivityEditor = ({
|
||||||
activity,
|
activity,
|
||||||
showComment = true,
|
showComment = true,
|
||||||
autoFillTitle = false,
|
autoFillTitle = false,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const [hasUserManuallySetTitle, setHasUserManuallySetTitle] =
|
const [hasUserManuallySetTitle, setHasUserManuallySetTitle] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
|
||||||
@ -154,13 +154,13 @@ export function ActivityEditor({
|
|||||||
|
|
||||||
const debouncedUpdateTitle = debounce(updateTitle, 200);
|
const debouncedUpdateTitle = debounce(updateTitle, 200);
|
||||||
|
|
||||||
function updateTitleFromBody(body: string) {
|
const updateTitleFromBody = (body: string) => {
|
||||||
const parsedTitle = JSON.parse(body)[0]?.content[0]?.text;
|
const parsedTitle = JSON.parse(body)[0]?.content[0]?.text;
|
||||||
if (!hasUserManuallySetTitle && autoFillTitle) {
|
if (!hasUserManuallySetTitle && autoFillTitle) {
|
||||||
setTitle(parsedTitle);
|
setTitle(parsedTitle);
|
||||||
debouncedUpdateTitle(parsedTitle);
|
debouncedUpdateTitle(parsedTitle);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if (!activity) {
|
if (!activity) {
|
||||||
return <></>;
|
return <></>;
|
||||||
@ -226,4 +226,4 @@ export function ActivityEditor({
|
|||||||
)}
|
)}
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -11,7 +11,7 @@ const StyledContainer = styled.div`
|
|||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function ActivityTargetChips({
|
export const ActivityTargetChips = ({
|
||||||
targets,
|
targets,
|
||||||
}: {
|
}: {
|
||||||
targets?: Array<
|
targets?: Array<
|
||||||
@ -20,7 +20,7 @@ export function ActivityTargetChips({
|
|||||||
company?: Pick<Company, 'id' | 'domainName' | 'name'> | null;
|
company?: Pick<Company, 'id' | 'domainName' | 'name'> | null;
|
||||||
}
|
}
|
||||||
> | null;
|
> | null;
|
||||||
}) {
|
}) => {
|
||||||
if (!targets) {
|
if (!targets) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -52,4 +52,4 @@ export function ActivityTargetChips({
|
|||||||
})}
|
})}
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -52,32 +52,30 @@ type OwnProps = {
|
|||||||
onCompletionChange: (value: boolean) => void;
|
onCompletionChange: (value: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityTitle({
|
export const ActivityTitle = ({
|
||||||
title,
|
title,
|
||||||
completed,
|
completed,
|
||||||
type,
|
type,
|
||||||
onTitleChange,
|
onTitleChange,
|
||||||
onCompletionChange,
|
onCompletionChange,
|
||||||
}: OwnProps) {
|
}: OwnProps) => (
|
||||||
return (
|
<StyledContainer>
|
||||||
<StyledContainer>
|
{type === ActivityType.Task && (
|
||||||
{type === ActivityType.Task && (
|
<StyledCheckboxContainer onClick={() => onCompletionChange(!completed)}>
|
||||||
<StyledCheckboxContainer onClick={() => onCompletionChange(!completed)}>
|
<Checkbox
|
||||||
<Checkbox
|
size={CheckboxSize.Large}
|
||||||
size={CheckboxSize.Large}
|
shape={CheckboxShape.Rounded}
|
||||||
shape={CheckboxShape.Rounded}
|
checked={completed}
|
||||||
checked={completed}
|
/>
|
||||||
/>
|
</StyledCheckboxContainer>
|
||||||
</StyledCheckboxContainer>
|
)}
|
||||||
)}
|
<StyledEditableTitleInput
|
||||||
<StyledEditableTitleInput
|
autoComplete="off"
|
||||||
autoComplete="off"
|
autoFocus
|
||||||
autoFocus
|
placeholder={`${type} title`}
|
||||||
placeholder={`${type} title`}
|
onChange={(event) => onTitleChange(event.target.value)}
|
||||||
onChange={(event) => onTitleChange(event.target.value)}
|
value={title}
|
||||||
value={title}
|
completed={completed}
|
||||||
completed={completed}
|
/>
|
||||||
/>
|
</StyledContainer>
|
||||||
</StyledContainer>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ type OwnProps = {
|
|||||||
activity: Pick<Activity, 'type'>;
|
activity: Pick<Activity, 'type'>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityTypeDropdown({ activity }: OwnProps) {
|
export const ActivityTypeDropdown = ({ activity }: OwnProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<Chip
|
<Chip
|
||||||
@ -30,4 +30,4 @@ export function ActivityTypeDropdown({ activity }: OwnProps) {
|
|||||||
variant={ChipVariant.Highlighted}
|
variant={ChipVariant.Highlighted}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -14,7 +14,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityAssigneeEditableField({ activity }: OwnProps) {
|
export const ActivityAssigneeEditableField = ({ activity }: OwnProps) => {
|
||||||
return (
|
return (
|
||||||
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
||||||
<RecoilScope>
|
<RecoilScope>
|
||||||
@ -44,4 +44,4 @@ export function ActivityAssigneeEditableField({ activity }: OwnProps) {
|
|||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -18,22 +18,22 @@ export type OwnProps = {
|
|||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityAssigneeEditableFieldEditMode({
|
export const ActivityAssigneeEditableFieldEditMode = ({
|
||||||
activity,
|
activity,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const { closeEditableField } = useEditableField();
|
const { closeEditableField } = useEditableField();
|
||||||
|
|
||||||
function handleSubmit() {
|
const handleSubmit = () => {
|
||||||
closeEditableField();
|
closeEditableField();
|
||||||
onSubmit?.();
|
onSubmit?.();
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleCancel() {
|
const handleCancel = () => {
|
||||||
closeEditableField();
|
closeEditableField();
|
||||||
onCancel?.();
|
onCancel?.();
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
@ -44,4 +44,4 @@ export function ActivityAssigneeEditableFieldEditMode({
|
|||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -19,7 +19,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityRelationEditableField({ activity }: OwnProps) {
|
export const ActivityRelationEditableField = ({ activity }: OwnProps) => {
|
||||||
return (
|
return (
|
||||||
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
||||||
<RecoilScope>
|
<RecoilScope>
|
||||||
@ -41,4 +41,4 @@ export function ActivityRelationEditableField({ activity }: OwnProps) {
|
|||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -24,7 +24,9 @@ const StyledSelectContainer = styled.div`
|
|||||||
top: -8px;
|
top: -8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function ActivityRelationEditableFieldEditMode({ activity }: OwnProps) {
|
export const ActivityRelationEditableFieldEditMode = ({
|
||||||
|
activity,
|
||||||
|
}: OwnProps) => {
|
||||||
const [searchFilter, setSearchFilter] = useState('');
|
const [searchFilter, setSearchFilter] = useState('');
|
||||||
|
|
||||||
const initialPeopleIds = useMemo(
|
const initialPeopleIds = useMemo(
|
||||||
@ -98,9 +100,9 @@ export function ActivityRelationEditableFieldEditMode({ activity }: OwnProps) {
|
|||||||
closeEditableField,
|
closeEditableField,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function handleCancel() {
|
const handleCancel = () => {
|
||||||
closeEditableField();
|
closeEditableField();
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledSelectContainer>
|
<StyledSelectContainer>
|
||||||
@ -120,4 +122,4 @@ export function ActivityRelationEditableFieldEditMode({ activity }: OwnProps) {
|
|||||||
/>
|
/>
|
||||||
</StyledSelectContainer>
|
</StyledSelectContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -14,7 +14,7 @@ import { GET_ACTIVITY } from '../graphql/queries/getActivity';
|
|||||||
import { ActivityTargetableEntityType } from '../types/ActivityTargetableEntity';
|
import { ActivityTargetableEntityType } from '../types/ActivityTargetableEntity';
|
||||||
import { ActivityTargetableEntityForSelect } from '../types/ActivityTargetableEntityForSelect';
|
import { ActivityTargetableEntityForSelect } from '../types/ActivityTargetableEntityForSelect';
|
||||||
|
|
||||||
export function useHandleCheckableActivityTargetChange({
|
export const useHandleCheckableActivityTargetChange = ({
|
||||||
activity,
|
activity,
|
||||||
}: {
|
}: {
|
||||||
activity?: Pick<Activity, 'id'> & {
|
activity?: Pick<Activity, 'id'> & {
|
||||||
@ -22,7 +22,7 @@ export function useHandleCheckableActivityTargetChange({
|
|||||||
Pick<ActivityTarget, 'id' | 'personId' | 'companyId'>
|
Pick<ActivityTarget, 'id' | 'personId' | 'companyId'>
|
||||||
> | null;
|
> | null;
|
||||||
};
|
};
|
||||||
}) {
|
}) => {
|
||||||
const [addActivityTargetsOnActivity] =
|
const [addActivityTargetsOnActivity] =
|
||||||
useAddActivityTargetsOnActivityMutation({
|
useAddActivityTargetsOnActivityMutation({
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
@ -41,10 +41,10 @@ export function useHandleCheckableActivityTargetChange({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
return async function handleCheckItemsChange(
|
return async (
|
||||||
entityValues: Record<string, boolean>,
|
entityValues: Record<string, boolean>,
|
||||||
entities: ActivityTargetableEntityForSelect[],
|
entities: ActivityTargetableEntityForSelect[],
|
||||||
) {
|
) => {
|
||||||
if (!activity) {
|
if (!activity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -96,4 +96,4 @@ export function useHandleCheckableActivityTargetChange({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -7,14 +7,14 @@ import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope
|
|||||||
|
|
||||||
import { viewableActivityIdState } from '../states/viewableActivityIdState';
|
import { viewableActivityIdState } from '../states/viewableActivityIdState';
|
||||||
|
|
||||||
export function useOpenActivityRightDrawer() {
|
export const useOpenActivityRightDrawer = () => {
|
||||||
const { openRightDrawer } = useRightDrawer();
|
const { openRightDrawer } = useRightDrawer();
|
||||||
const [, setViewableActivityId] = useRecoilState(viewableActivityIdState);
|
const [, setViewableActivityId] = useRecoilState(viewableActivityIdState);
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
return function openActivityRightDrawer(activityId: string) {
|
return (activityId: string) => {
|
||||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||||
setViewableActivityId(activityId);
|
setViewableActivityId(activityId);
|
||||||
openRightDrawer(RightDrawerPages.EditActivity);
|
openRightDrawer(RightDrawerPages.EditActivity);
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -19,7 +19,7 @@ import { viewableActivityIdState } from '../states/viewableActivityIdState';
|
|||||||
import { ActivityTargetableEntity } from '../types/ActivityTargetableEntity';
|
import { ActivityTargetableEntity } from '../types/ActivityTargetableEntity';
|
||||||
import { getRelationData } from '../utils/getRelationData';
|
import { getRelationData } from '../utils/getRelationData';
|
||||||
|
|
||||||
export function useOpenCreateActivityDrawer() {
|
export const useOpenCreateActivityDrawer = () => {
|
||||||
const { openRightDrawer } = useRightDrawer();
|
const { openRightDrawer } = useRightDrawer();
|
||||||
const [createActivityMutation] = useCreateActivityMutation();
|
const [createActivityMutation] = useCreateActivityMutation();
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
@ -30,7 +30,7 @@ export function useOpenCreateActivityDrawer() {
|
|||||||
);
|
);
|
||||||
const [, setViewableActivityId] = useRecoilState(viewableActivityIdState);
|
const [, setViewableActivityId] = useRecoilState(viewableActivityIdState);
|
||||||
|
|
||||||
return function openCreateActivityDrawer({
|
return ({
|
||||||
type,
|
type,
|
||||||
targetableEntities,
|
targetableEntities,
|
||||||
assigneeId,
|
assigneeId,
|
||||||
@ -38,7 +38,7 @@ export function useOpenCreateActivityDrawer() {
|
|||||||
type: ActivityType;
|
type: ActivityType;
|
||||||
targetableEntities?: ActivityTargetableEntity[];
|
targetableEntities?: ActivityTargetableEntity[];
|
||||||
assigneeId?: string;
|
assigneeId?: string;
|
||||||
}) {
|
}) => {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
return createActivityMutation({
|
return createActivityMutation({
|
||||||
@ -73,7 +73,7 @@ export function useOpenCreateActivityDrawer() {
|
|||||||
getOperationName(GET_ACTIVITIES_BY_TARGETS) ?? '',
|
getOperationName(GET_ACTIVITIES_BY_TARGETS) ?? '',
|
||||||
getOperationName(GET_ACTIVITIES) ?? '',
|
getOperationName(GET_ACTIVITIES) ?? '',
|
||||||
],
|
],
|
||||||
onCompleted(data) {
|
onCompleted: (data) => {
|
||||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||||
setViewableActivityId(data.createOneActivity.id);
|
setViewableActivityId(data.createOneActivity.id);
|
||||||
setActivityTargetableEntityArray(targetableEntities ?? []);
|
setActivityTargetableEntityArray(targetableEntities ?? []);
|
||||||
@ -81,4 +81,4 @@ export function useOpenCreateActivityDrawer() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -10,15 +10,12 @@ import {
|
|||||||
|
|
||||||
import { useOpenCreateActivityDrawer } from './useOpenCreateActivityDrawer';
|
import { useOpenCreateActivityDrawer } from './useOpenCreateActivityDrawer';
|
||||||
|
|
||||||
export function useOpenCreateActivityDrawerForSelectedRowIds() {
|
export const useOpenCreateActivityDrawerForSelectedRowIds = () => {
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
||||||
|
|
||||||
const openCreateActivityDrawer = useOpenCreateActivityDrawer();
|
const openCreateActivityDrawer = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
return function openCreateCommentDrawerForSelectedRowIds(
|
return (type: ActivityType, entityType: ActivityTargetableEntityType) => {
|
||||||
type: ActivityType,
|
|
||||||
entityType: ActivityTargetableEntityType,
|
|
||||||
) {
|
|
||||||
const activityTargetableEntityArray: ActivityTargetableEntity[] =
|
const activityTargetableEntityArray: ActivityTargetableEntity[] =
|
||||||
selectedRowIds.map((id) => ({
|
selectedRowIds.map((id) => ({
|
||||||
type: entityType,
|
type: entityType,
|
||||||
@ -29,4 +26,4 @@ export function useOpenCreateActivityDrawerForSelectedRowIds() {
|
|||||||
targetableEntities: activityTargetableEntityArray,
|
targetableEntities: activityTargetableEntityArray,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -56,7 +56,7 @@ const StyledFooter = styled.div`
|
|||||||
width: calc(100% - ${({ theme }) => theme.spacing(4)});
|
width: calc(100% - ${({ theme }) => theme.spacing(4)});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function NoteCard({
|
export const NoteCard = ({
|
||||||
note,
|
note,
|
||||||
}: {
|
}: {
|
||||||
note: Pick<
|
note: Pick<
|
||||||
@ -65,7 +65,7 @@ export function NoteCard({
|
|||||||
> & {
|
> & {
|
||||||
activityTargets?: Array<Pick<ActivityTarget, 'id'>> | null;
|
activityTargets?: Array<Pick<ActivityTarget, 'id'>> | null;
|
||||||
};
|
};
|
||||||
}) {
|
}) => {
|
||||||
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
||||||
const body = JSON.parse(note.body ?? '{}')[0]
|
const body = JSON.parse(note.body ?? '{}')[0]
|
||||||
?.content.map((x: any) => x.text)
|
?.content.map((x: any) => x.text)
|
||||||
@ -84,4 +84,4 @@ export function NoteCard({
|
|||||||
</StyledFooter>
|
</StyledFooter>
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -47,24 +47,22 @@ const StyledNoteContainer = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function NoteList({ title, notes, button }: OwnProps) {
|
export const NoteList = ({ title, notes, button }: OwnProps) => (
|
||||||
return (
|
<>
|
||||||
<>
|
{notes && notes.length > 0 && (
|
||||||
{notes && notes.length > 0 && (
|
<StyledContainer>
|
||||||
<StyledContainer>
|
<StyledTitleBar>
|
||||||
<StyledTitleBar>
|
<StyledTitle>
|
||||||
<StyledTitle>
|
{title} <StyledCount>{notes.length}</StyledCount>
|
||||||
{title} <StyledCount>{notes.length}</StyledCount>
|
</StyledTitle>
|
||||||
</StyledTitle>
|
{button}
|
||||||
{button}
|
</StyledTitleBar>
|
||||||
</StyledTitleBar>
|
<StyledNoteContainer>
|
||||||
<StyledNoteContainer>
|
{notes.map((note) => (
|
||||||
{notes.map((note) => (
|
<NoteCard key={note.id} note={note} />
|
||||||
<NoteCard key={note.id} note={note} />
|
))}
|
||||||
))}
|
</StyledNoteContainer>
|
||||||
</StyledNoteContainer>
|
</StyledContainer>
|
||||||
</StyledContainer>
|
)}
|
||||||
)}
|
</>
|
||||||
</>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -45,7 +45,7 @@ const StyledNotesContainer = styled.div`
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function Notes({ entity }: { entity: ActivityTargetableEntity }) {
|
export const Notes = ({ entity }: { entity: ActivityTargetableEntity }) => {
|
||||||
const { notes } = useNotes(entity);
|
const { notes } = useNotes(entity);
|
||||||
|
|
||||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||||
@ -92,4 +92,4 @@ export function Notes({ entity }: { entity: ActivityTargetableEntity }) {
|
|||||||
/>
|
/>
|
||||||
</StyledNotesContainer>
|
</StyledNotesContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -2,7 +2,7 @@ import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
|
|||||||
|
|
||||||
import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity';
|
import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity';
|
||||||
|
|
||||||
export function useNotes(entity: ActivityTargetableEntity) {
|
export const useNotes = (entity: ActivityTargetableEntity) => {
|
||||||
const { data: notesData } = useGetActivitiesQuery({
|
const { data: notesData } = useGetActivitiesQuery({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
@ -24,4 +24,4 @@ export function useNotes(entity: ActivityTargetableEntity) {
|
|||||||
return {
|
return {
|
||||||
notes,
|
notes,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -14,11 +14,11 @@ type OwnProps = {
|
|||||||
activityId: string;
|
activityId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ActivityActionBar({ activityId }: OwnProps) {
|
export const ActivityActionBar = ({ activityId }: OwnProps) => {
|
||||||
const [deleteActivityMutation] = useDeleteActivityMutation();
|
const [deleteActivityMutation] = useDeleteActivityMutation();
|
||||||
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||||
|
|
||||||
function deleteActivity() {
|
const deleteActivity = () => {
|
||||||
deleteActivityMutation({
|
deleteActivityMutation({
|
||||||
variables: { activityId },
|
variables: { activityId },
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
@ -29,7 +29,7 @@ export function ActivityActionBar({ activityId }: OwnProps) {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
setIsRightDrawerOpen(false);
|
setIsRightDrawerOpen(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LightIconButton
|
<LightIconButton
|
||||||
@ -39,4 +39,4 @@ export function ActivityActionBar({ activityId }: OwnProps) {
|
|||||||
size="medium"
|
size="medium"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -22,11 +22,11 @@ type OwnProps = {
|
|||||||
autoFillTitle?: boolean;
|
autoFillTitle?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function RightDrawerActivity({
|
export const RightDrawerActivity = ({
|
||||||
activityId,
|
activityId,
|
||||||
showComment = true,
|
showComment = true,
|
||||||
autoFillTitle = false,
|
autoFillTitle = false,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const { data } = useGetActivityQuery({
|
const { data } = useGetActivityQuery({
|
||||||
variables: {
|
variables: {
|
||||||
activityId: activityId ?? '',
|
activityId: activityId ?? '',
|
||||||
@ -48,4 +48,4 @@ export function RightDrawerActivity({
|
|||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -4,7 +4,7 @@ import { viewableActivityIdState } from '@/activities/states/viewableActivityIdS
|
|||||||
|
|
||||||
import { RightDrawerActivity } from '../RightDrawerActivity';
|
import { RightDrawerActivity } from '../RightDrawerActivity';
|
||||||
|
|
||||||
export function RightDrawerCreateActivity() {
|
export const RightDrawerCreateActivity = () => {
|
||||||
const viewableActivityId = useRecoilValue(viewableActivityIdState);
|
const viewableActivityId = useRecoilValue(viewableActivityIdState);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -18,4 +18,4 @@ export function RightDrawerCreateActivity() {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -4,7 +4,7 @@ import { viewableActivityIdState } from '@/activities/states/viewableActivityIdS
|
|||||||
|
|
||||||
import { RightDrawerActivity } from '../RightDrawerActivity';
|
import { RightDrawerActivity } from '../RightDrawerActivity';
|
||||||
|
|
||||||
export function RightDrawerEditActivity() {
|
export const RightDrawerEditActivity = () => {
|
||||||
const viewableActivityId = useRecoilValue(viewableActivityIdState);
|
const viewableActivityId = useRecoilValue(viewableActivityIdState);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -14,4 +14,4 @@ export function RightDrawerEditActivity() {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -5,7 +5,7 @@ import { CommentChip, CommentChipProps } from './CommentChip';
|
|||||||
// TODO: tie those fixed values to the other components in the cell
|
// TODO: tie those fixed values to the other components in the cell
|
||||||
const StyledCellWrapper = styled.div``;
|
const StyledCellWrapper = styled.div``;
|
||||||
|
|
||||||
export function CellCommentChip(props: CommentChipProps) {
|
export const CellCommentChip = (props: CommentChipProps) => {
|
||||||
if (props.count === 0) return null;
|
if (props.count === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -13,4 +13,4 @@ export function CellCommentChip(props: CommentChipProps) {
|
|||||||
<CommentChip {...props} />
|
<CommentChip {...props} />
|
||||||
</StyledCellWrapper>
|
</StyledCellWrapper>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -46,7 +46,7 @@ const StyledCount = styled.div`
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function CommentChip({ count, onClick }: CommentChipProps) {
|
export const CommentChip = ({ count, onClick }: CommentChipProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
if (count === 0) return null;
|
if (count === 0) return null;
|
||||||
@ -58,4 +58,4 @@ export function CommentChip({ count, onClick }: CommentChipProps) {
|
|||||||
<IconComment size={theme.icon.size.md} />
|
<IconComment size={theme.icon.size.md} />
|
||||||
</StyledChip>
|
</StyledChip>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -4,11 +4,11 @@ import { Button } from '@/ui/button/components/Button';
|
|||||||
import { IconPlus } from '@/ui/icon';
|
import { IconPlus } from '@/ui/icon';
|
||||||
import { ActivityType } from '~/generated/graphql';
|
import { ActivityType } from '~/generated/graphql';
|
||||||
|
|
||||||
export function AddTaskButton({
|
export const AddTaskButton = ({
|
||||||
activityTargetEntity,
|
activityTargetEntity,
|
||||||
}: {
|
}: {
|
||||||
activityTargetEntity?: ActivityTargetableEntity;
|
activityTargetEntity?: ActivityTargetableEntity;
|
||||||
}) {
|
}) => {
|
||||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
if (!activityTargetEntity) {
|
if (!activityTargetEntity) {
|
||||||
@ -29,4 +29,4 @@ export function AddTaskButton({
|
|||||||
}
|
}
|
||||||
></Button>
|
></Button>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -13,7 +13,11 @@ const StyledContainer = styled.div`
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function EntityTasks({ entity }: { entity: ActivityTargetableEntity }) {
|
export const EntityTasks = ({
|
||||||
|
entity,
|
||||||
|
}: {
|
||||||
|
entity: ActivityTargetableEntity;
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<RecoilScope CustomRecoilScopeContext={TasksRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={TasksRecoilScopeContext}>
|
||||||
@ -21,4 +25,4 @@ export function EntityTasks({ entity }: { entity: ActivityTargetableEntity }) {
|
|||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -7,7 +7,7 @@ import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoi
|
|||||||
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
||||||
import { ActivityType } from '~/generated/graphql';
|
import { ActivityType } from '~/generated/graphql';
|
||||||
|
|
||||||
export function PageAddTaskButton() {
|
export const PageAddTaskButton = () => {
|
||||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
const filters = useRecoilScopedValue(
|
const filters = useRecoilScopedValue(
|
||||||
@ -19,16 +19,16 @@ export function PageAddTaskButton() {
|
|||||||
(filter) => filter.key === 'assigneeId',
|
(filter) => filter.key === 'assigneeId',
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleClick() {
|
const handleClick = () => {
|
||||||
openCreateActivity({
|
openCreateActivity({
|
||||||
type: ActivityType.Task,
|
type: ActivityType.Task,
|
||||||
assigneeId: assigneeIdFilter?.value,
|
assigneeId: assigneeIdFilter?.value,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
||||||
<PageAddButton onClick={handleClick} />
|
<PageAddButton onClick={handleClick} />
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -52,7 +52,7 @@ const StyledContainer = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function TaskGroups({ entity, showAddButton }: OwnProps) {
|
export const TaskGroups = ({ entity, showAddButton }: OwnProps) => {
|
||||||
const {
|
const {
|
||||||
todayOrPreviousTasks,
|
todayOrPreviousTasks,
|
||||||
upcomingTasks,
|
upcomingTasks,
|
||||||
@ -136,4 +136,4 @@ export function TaskGroups({ entity, showAddButton }: OwnProps) {
|
|||||||
)}
|
)}
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -46,26 +46,24 @@ const StyledTaskRows = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function TaskList({ title, tasks, button }: OwnProps) {
|
export const TaskList = ({ title, tasks, button }: OwnProps) => (
|
||||||
return (
|
<>
|
||||||
<>
|
{tasks && tasks.length > 0 && (
|
||||||
{tasks && tasks.length > 0 && (
|
<StyledContainer>
|
||||||
<StyledContainer>
|
<StyledTitleBar>
|
||||||
<StyledTitleBar>
|
{title && (
|
||||||
{title && (
|
<StyledTitle>
|
||||||
<StyledTitle>
|
{title} <StyledCount>{tasks.length}</StyledCount>
|
||||||
{title} <StyledCount>{tasks.length}</StyledCount>
|
</StyledTitle>
|
||||||
</StyledTitle>
|
)}
|
||||||
)}
|
{button}
|
||||||
{button}
|
</StyledTitleBar>
|
||||||
</StyledTitleBar>
|
<StyledTaskRows>
|
||||||
<StyledTaskRows>
|
{tasks.map((task) => (
|
||||||
{tasks.map((task) => (
|
<TaskRow key={task.id} task={task} />
|
||||||
<TaskRow key={task.id} task={task} />
|
))}
|
||||||
))}
|
</StyledTaskRows>
|
||||||
</StyledTaskRows>
|
</StyledContainer>
|
||||||
</StyledContainer>
|
)}
|
||||||
)}
|
</>
|
||||||
</>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -61,7 +61,7 @@ const StyledFieldsContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function TaskRow({ task }: { task: TaskForList }) {
|
export const TaskRow = ({ task }: { task: TaskForList }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
||||||
|
|
||||||
@ -109,4 +109,4 @@ export function TaskRow({ task }: { task: TaskForList }) {
|
|||||||
</StyledFieldsContainer>
|
</StyledFieldsContainer>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -9,7 +9,7 @@ import { GET_ACTIVITIES } from '../../graphql/queries/getActivities';
|
|||||||
|
|
||||||
type Task = Pick<Activity, 'id' | 'completedAt'>;
|
type Task = Pick<Activity, 'id' | 'completedAt'>;
|
||||||
|
|
||||||
export function useCompleteTask(task: Task) {
|
export const useCompleteTask = (task: Task) => {
|
||||||
const [updateActivityMutation] = useUpdateActivityMutation();
|
const [updateActivityMutation] = useUpdateActivityMutation();
|
||||||
|
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
@ -44,4 +44,4 @@ export function useCompleteTask(task: Task) {
|
|||||||
return {
|
return {
|
||||||
completeTask,
|
completeTask,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -7,7 +7,7 @@ import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhe
|
|||||||
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
|
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
|
||||||
import { parseDate } from '~/utils/date-utils';
|
import { parseDate } from '~/utils/date-utils';
|
||||||
|
|
||||||
export function useCurrentUserTaskCount() {
|
export const useCurrentUserTaskCount = () => {
|
||||||
const [currentUser] = useRecoilState(currentUserState);
|
const [currentUser] = useRecoilState(currentUserState);
|
||||||
|
|
||||||
const { data } = useGetActivitiesQuery({
|
const { data } = useGetActivitiesQuery({
|
||||||
@ -41,4 +41,4 @@ export function useCurrentUserTaskCount() {
|
|||||||
return {
|
return {
|
||||||
currentUserDueTaskCount,
|
currentUserDueTaskCount,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -8,7 +8,7 @@ import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhe
|
|||||||
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
|
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
|
||||||
import { parseDate } from '~/utils/date-utils';
|
import { parseDate } from '~/utils/date-utils';
|
||||||
|
|
||||||
export function useTasks(entity?: ActivityTargetableEntity) {
|
export const useTasks = (entity?: ActivityTargetableEntity) => {
|
||||||
const [filters] = useRecoilScopedState(
|
const [filters] = useRecoilScopedState(
|
||||||
filtersScopedState,
|
filtersScopedState,
|
||||||
TasksRecoilScopeContext,
|
TasksRecoilScopeContext,
|
||||||
@ -90,4 +90,4 @@ export function useTasks(entity?: ActivityTargetableEntity) {
|
|||||||
unscheduledTasks: unscheduledTasks ?? [],
|
unscheduledTasks: unscheduledTasks ?? [],
|
||||||
completedTasks: completedTasks ?? [],
|
completedTasks: completedTasks ?? [],
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -51,7 +51,7 @@ const StyledEmptyTimelineSubTitle = styled.div`
|
|||||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function Timeline({ entity }: { entity: ActivityTargetableEntity }) {
|
export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => {
|
||||||
const { data: queryResult, loading } = useGetActivitiesByTargetsQuery({
|
const { data: queryResult, loading } = useGetActivitiesByTargetsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
activityTargetIds: [entity.id],
|
activityTargetIds: [entity.id],
|
||||||
@ -99,4 +99,4 @@ export function Timeline({ entity }: { entity: ActivityTargetableEntity }) {
|
|||||||
<TimelineItemsContainer activities={activities} />
|
<TimelineItemsContainer activities={activities} />
|
||||||
</StyledMainContainer>
|
</StyledMainContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -125,7 +125,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TimelineActivity({ activity }: OwnProps) {
|
export const TimelineActivity = ({ activity }: OwnProps) => {
|
||||||
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(activity.createdAt);
|
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(activity.createdAt);
|
||||||
const exactCreatedAt = beautifyExactDateTime(activity.createdAt);
|
const exactCreatedAt = beautifyExactDateTime(activity.createdAt);
|
||||||
const body = JSON.parse(activity.body ?? '{}')[0]?.content[0]?.text;
|
const body = JSON.parse(activity.body ?? '{}')[0]?.content[0]?.text;
|
||||||
@ -176,4 +176,4 @@ export function TimelineActivity({ activity }: OwnProps) {
|
|||||||
</StyledTimelineItemContainer>
|
</StyledTimelineItemContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -26,26 +26,24 @@ const StyledVerticalSeparator = styled.div`
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function TimelineActivityCardFooter({ activity }: OwnProps) {
|
export const TimelineActivityCardFooter = ({ activity }: OwnProps) => (
|
||||||
return (
|
<>
|
||||||
<>
|
{(activity.assignee || activity.dueAt) && (
|
||||||
{(activity.assignee || activity.dueAt) && (
|
<StyledContainer>
|
||||||
<StyledContainer>
|
{activity.assignee && (
|
||||||
{activity.assignee && (
|
<UserChip
|
||||||
<UserChip
|
id={activity.assignee.id}
|
||||||
id={activity.assignee.id}
|
name={activity.assignee.displayName ?? ''}
|
||||||
name={activity.assignee.displayName ?? ''}
|
pictureUrl={activity.assignee.avatarUrl ?? ''}
|
||||||
pictureUrl={activity.assignee.avatarUrl ?? ''}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
{activity.dueAt && (
|
||||||
{activity.dueAt && (
|
<>
|
||||||
<>
|
{activity.assignee && <StyledVerticalSeparator />}
|
||||||
{activity.assignee && <StyledVerticalSeparator />}
|
{beautifyExactDate(activity.dueAt)}
|
||||||
{beautifyExactDate(activity.dueAt)}
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
</StyledContainer>
|
||||||
</StyledContainer>
|
)}
|
||||||
)}
|
</>
|
||||||
</>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -37,34 +37,29 @@ type OwnProps = {
|
|||||||
onCompletionChange?: (value: boolean) => void;
|
onCompletionChange?: (value: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TimelineActivityTitle({
|
export const TimelineActivityTitle = ({
|
||||||
title,
|
title,
|
||||||
completed,
|
completed,
|
||||||
type,
|
type,
|
||||||
onCompletionChange,
|
onCompletionChange,
|
||||||
}: OwnProps) {
|
}: OwnProps) => (
|
||||||
return (
|
<StyledTitleContainer>
|
||||||
<StyledTitleContainer>
|
{type === ActivityType.Task && (
|
||||||
{type === ActivityType.Task && (
|
<StyledCheckboxContainer
|
||||||
<StyledCheckboxContainer
|
onClick={(event) => {
|
||||||
onClick={(event) => {
|
event.preventDefault();
|
||||||
event.preventDefault();
|
event.stopPropagation();
|
||||||
event.stopPropagation();
|
onCompletionChange?.(!completed);
|
||||||
onCompletionChange?.(!completed);
|
}}
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
checked={completed ?? false}
|
|
||||||
shape={CheckboxShape.Rounded}
|
|
||||||
/>
|
|
||||||
</StyledCheckboxContainer>
|
|
||||||
)}
|
|
||||||
<StyledTitleText
|
|
||||||
completed={completed}
|
|
||||||
hasCheckbox={type === ActivityType.Task}
|
|
||||||
>
|
>
|
||||||
<OverflowingTextWithTooltip text={title ? title : 'Task title'} />
|
<Checkbox checked={completed ?? false} shape={CheckboxShape.Rounded} />
|
||||||
</StyledTitleText>
|
</StyledCheckboxContainer>
|
||||||
</StyledTitleContainer>
|
)}
|
||||||
);
|
<StyledTitleText
|
||||||
}
|
completed={completed}
|
||||||
|
hasCheckbox={type === ActivityType.Task}
|
||||||
|
>
|
||||||
|
<OverflowingTextWithTooltip text={title ? title : 'Task title'} />
|
||||||
|
</StyledTitleText>
|
||||||
|
</StyledTitleContainer>
|
||||||
|
);
|
||||||
|
@ -35,9 +35,9 @@ export type TimelineItemsContainerProps = {
|
|||||||
activities: ActivityForDrawer[];
|
activities: ActivityForDrawer[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TimelineItemsContainer({
|
export const TimelineItemsContainer = ({
|
||||||
activities,
|
activities,
|
||||||
}: TimelineItemsContainerProps) {
|
}: TimelineItemsContainerProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<StyledScrollWrapper>
|
<StyledScrollWrapper>
|
||||||
@ -51,4 +51,4 @@ export function TimelineItemsContainer({
|
|||||||
</StyledTimelineContainer>
|
</StyledTimelineContainer>
|
||||||
</StyledScrollWrapper>
|
</StyledScrollWrapper>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||||
|
|
||||||
export function flatMapAndSortEntityForSelectArrayOfArrayByName<
|
export const flatMapAndSortEntityForSelectArrayOfArrayByName = <
|
||||||
T extends EntityForSelect,
|
T extends EntityForSelect,
|
||||||
>(entityForSelectArray: T[][]) {
|
>(
|
||||||
|
entityForSelectArray: T[][],
|
||||||
|
) => {
|
||||||
const sortByName = (a: T, b: T) => a.name.localeCompare(b.name);
|
const sortByName = (a: T, b: T) => a.name.localeCompare(b.name);
|
||||||
|
|
||||||
return entityForSelectArray.flatMap((entity) => entity).sort(sortByName);
|
return entityForSelectArray.flatMap((entity) => entity).sort(sortByName);
|
||||||
}
|
};
|
||||||
|
@ -7,9 +7,9 @@ import {
|
|||||||
ActivityTargetableEntityType,
|
ActivityTargetableEntityType,
|
||||||
} from '../types/ActivityTargetableEntity';
|
} from '../types/ActivityTargetableEntity';
|
||||||
|
|
||||||
export function getRelationData(
|
export const getRelationData = (
|
||||||
entities: ActivityTargetableEntity[],
|
entities: ActivityTargetableEntity[],
|
||||||
): ActivityTargetCreateManyActivityInput[] {
|
): ActivityTargetCreateManyActivityInput[] => {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
const relationData: ActivityTargetCreateManyActivityInput[] = [];
|
const relationData: ActivityTargetCreateManyActivityInput[] = [];
|
||||||
@ -40,4 +40,4 @@ export function getRelationData(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return relationData;
|
return relationData;
|
||||||
}
|
};
|
||||||
|
@ -12,7 +12,7 @@ export interface EventData {
|
|||||||
location: EventLocation;
|
location: EventLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useEventTracker() {
|
export const useEventTracker = () => {
|
||||||
const [telemetry] = useRecoilState(telemetryState);
|
const [telemetry] = useRecoilState(telemetryState);
|
||||||
const [createEventMutation] = useCreateEventMutation();
|
const [createEventMutation] = useCreateEventMutation();
|
||||||
|
|
||||||
@ -29,4 +29,4 @@ export function useEventTracker() {
|
|||||||
},
|
},
|
||||||
[createEventMutation, telemetry],
|
[createEventMutation, telemetry],
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { EventData, useEventTracker } from './useEventTracker';
|
import { EventData, useEventTracker } from './useEventTracker';
|
||||||
|
|
||||||
export function useTrackEvent(eventType: string, eventData: EventData) {
|
export const useTrackEvent = (eventType: string, eventData: EventData) => {
|
||||||
const eventTracker = useEventTracker();
|
const eventTracker = useEventTracker();
|
||||||
|
|
||||||
return eventTracker(eventType, eventData);
|
return eventTracker(eventType, eventData);
|
||||||
}
|
};
|
||||||
|
@ -2,10 +2,10 @@ import { ApolloProvider as ApolloProviderBase } from '@apollo/client';
|
|||||||
|
|
||||||
import { useApolloFactory } from '@/apollo/hooks/useApolloFactory';
|
import { useApolloFactory } from '@/apollo/hooks/useApolloFactory';
|
||||||
|
|
||||||
export function ApolloProvider({ children }: React.PropsWithChildren) {
|
export const ApolloProvider = ({ children }: React.PropsWithChildren) => {
|
||||||
const apolloClient = useApolloFactory();
|
const apolloClient = useApolloFactory();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ApolloProviderBase client={apolloClient}>{children}</ApolloProviderBase>
|
<ApolloProviderBase client={apolloClient}>{children}</ApolloProviderBase>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -12,7 +12,7 @@ import { useUpdateEffect } from '~/hooks/useUpdateEffect';
|
|||||||
|
|
||||||
import { ApolloFactory } from '../services/apollo.factory';
|
import { ApolloFactory } from '../services/apollo.factory';
|
||||||
|
|
||||||
export function useApolloFactory() {
|
export const useApolloFactory = () => {
|
||||||
const apolloRef = useRef<ApolloFactory<NormalizedCacheObject> | null>(null);
|
const apolloRef = useRef<ApolloFactory<NormalizedCacheObject> | null>(null);
|
||||||
const [isDebugMode] = useRecoilState(isDebugModeState);
|
const [isDebugMode] = useRecoilState(isDebugModeState);
|
||||||
|
|
||||||
@ -28,10 +28,10 @@ export function useApolloFactory() {
|
|||||||
Activity: {
|
Activity: {
|
||||||
fields: {
|
fields: {
|
||||||
activityTargets: {
|
activityTargets: {
|
||||||
merge(
|
merge: (
|
||||||
_existing: ActivityTarget[] = [],
|
_existing: ActivityTarget[] = [],
|
||||||
incoming: ActivityTarget[],
|
incoming: ActivityTarget[],
|
||||||
) {
|
) => {
|
||||||
return [...incoming];
|
return [...incoming];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -47,10 +47,10 @@ export function useApolloFactory() {
|
|||||||
connectToDevTools: isDebugMode,
|
connectToDevTools: isDebugMode,
|
||||||
// We don't want to re-create the client on token change or it will cause infinite loop
|
// We don't want to re-create the client on token change or it will cause infinite loop
|
||||||
initialTokenPair: tokenPair,
|
initialTokenPair: tokenPair,
|
||||||
onTokenPairChange(tokenPair) {
|
onTokenPairChange: (tokenPair) => {
|
||||||
setTokenPair(tokenPair);
|
setTokenPair(tokenPair);
|
||||||
},
|
},
|
||||||
onUnauthenticatedError() {
|
onUnauthenticatedError: () => {
|
||||||
setTokenPair(null);
|
setTokenPair(null);
|
||||||
if (
|
if (
|
||||||
!isMatchingLocation(AppPath.Verify) &&
|
!isMatchingLocation(AppPath.Verify) &&
|
||||||
@ -76,4 +76,4 @@ export function useApolloFactory() {
|
|||||||
}, [tokenPair]);
|
}, [tokenPair]);
|
||||||
|
|
||||||
return apolloClient;
|
return apolloClient;
|
||||||
}
|
};
|
||||||
|
@ -13,7 +13,7 @@ import { GetCompaniesQuery, GetPeopleQuery } from '~/generated/graphql';
|
|||||||
import { optimisticEffectState } from '../states/optimisticEffectState';
|
import { optimisticEffectState } from '../states/optimisticEffectState';
|
||||||
import { OptimisticEffectDefinition } from '../types/OptimisticEffectDefinition';
|
import { OptimisticEffectDefinition } from '../types/OptimisticEffectDefinition';
|
||||||
|
|
||||||
export function useOptimisticEffect() {
|
export const useOptimisticEffect = () => {
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
const registerOptimisticEffect = useRecoilCallback(
|
const registerOptimisticEffect = useRecoilCallback(
|
||||||
@ -29,7 +29,7 @@ export function useOptimisticEffect() {
|
|||||||
.getLoadable(optimisticEffectState)
|
.getLoadable(optimisticEffectState)
|
||||||
.getValue();
|
.getValue();
|
||||||
|
|
||||||
function optimisticEffectWriter({
|
const optimisticEffectWriter = ({
|
||||||
cache,
|
cache,
|
||||||
newData,
|
newData,
|
||||||
query,
|
query,
|
||||||
@ -39,7 +39,7 @@ export function useOptimisticEffect() {
|
|||||||
newData: unknown[];
|
newData: unknown[];
|
||||||
variables: OperationVariables;
|
variables: OperationVariables;
|
||||||
query: DocumentNode;
|
query: DocumentNode;
|
||||||
}) {
|
}) => {
|
||||||
const existingData = cache.readQuery({
|
const existingData = cache.readQuery({
|
||||||
query,
|
query,
|
||||||
variables,
|
variables,
|
||||||
@ -76,7 +76,7 @@ export function useOptimisticEffect() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const optimisticEffect = {
|
const optimisticEffect = {
|
||||||
key: definition.key,
|
key: definition.key,
|
||||||
@ -117,4 +117,4 @@ export function useOptimisticEffect() {
|
|||||||
registerOptimisticEffect,
|
registerOptimisticEffect,
|
||||||
triggerOptimisticEffects,
|
triggerOptimisticEffects,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -47,7 +47,7 @@ const StyledMainLogo = styled.div<StyledMainLogoProps>`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function Logo({ workspaceLogo, ...props }: Props) {
|
export const Logo = ({ workspaceLogo, ...props }: Props) => {
|
||||||
if (!workspaceLogo) {
|
if (!workspaceLogo) {
|
||||||
return (
|
return (
|
||||||
<StyledContainer {...props}>
|
<StyledContainer {...props}>
|
||||||
@ -64,4 +64,4 @@ export function Logo({ workspaceLogo, ...props }: Props) {
|
|||||||
</StyledTwentyLogoContainer>
|
</StyledTwentyLogoContainer>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -10,10 +10,8 @@ const StyledContent = styled(UIModal.Content)`
|
|||||||
|
|
||||||
type Props = React.ComponentProps<'div'>;
|
type Props = React.ComponentProps<'div'>;
|
||||||
|
|
||||||
export function AuthModal({ children, ...restProps }: Props) {
|
export const AuthModal = ({ children, ...restProps }: Props) => (
|
||||||
return (
|
<UIModal isOpen={true} {...restProps}>
|
||||||
<UIModal isOpen={true} {...restProps}>
|
<StyledContent>{children}</StyledContent>
|
||||||
<StyledContent>{children}</StyledContent>
|
</UIModal>
|
||||||
</UIModal>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React from 'react';
|
import { JSX, ReactNode } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
children: React.ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledSubTitle = styled.div`
|
const StyledSubTitle = styled.div`
|
||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function SubTitle({ children }: OwnProps): JSX.Element {
|
export const SubTitle = ({ children }: OwnProps): JSX.Element => (
|
||||||
return <StyledSubTitle>{children}</StyledSubTitle>;
|
<StyledSubTitle>{children}</StyledSubTitle>
|
||||||
}
|
);
|
||||||
|
@ -15,7 +15,7 @@ const StyledTitle = styled.div`
|
|||||||
margin-top: ${({ theme }) => theme.spacing(4)};
|
margin-top: ${({ theme }) => theme.spacing(4)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function Title({ children, animate = false }: Props) {
|
export const Title = ({ children, animate = false }: Props) => {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
return (
|
return (
|
||||||
<StyledTitle>
|
<StyledTitle>
|
||||||
@ -25,4 +25,4 @@ export function Title({ children, animate = false }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <StyledTitle>{children}</StyledTitle>;
|
return <StyledTitle>{children}</StyledTitle>;
|
||||||
}
|
};
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
import { currentUserState } from '../states/currentUserState';
|
import { currentUserState } from '../states/currentUserState';
|
||||||
import { tokenPairState } from '../states/tokenPairState';
|
import { tokenPairState } from '../states/tokenPairState';
|
||||||
|
|
||||||
export function useAuth() {
|
export const useAuth = () => {
|
||||||
const [, setTokenPair] = useRecoilState(tokenPairState);
|
const [, setTokenPair] = useRecoilState(tokenPairState);
|
||||||
const [, setCurrentUser] = useRecoilState(currentUserState);
|
const [, setCurrentUser] = useRecoilState(currentUserState);
|
||||||
|
|
||||||
@ -148,4 +148,4 @@ export function useAuth() {
|
|||||||
signInWithCredentials: handleCrendentialsSignIn,
|
signInWithCredentials: handleCrendentialsSignIn,
|
||||||
signInWithGoogle: handleGoogleLogin,
|
signInWithGoogle: handleGoogleLogin,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -2,8 +2,8 @@ import { useRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { tokenPairState } from '../states/tokenPairState';
|
import { tokenPairState } from '../states/tokenPairState';
|
||||||
|
|
||||||
export function useIsLogged(): boolean {
|
export const useIsLogged = (): boolean => {
|
||||||
const [tokenPair] = useRecoilState(tokenPairState);
|
const [tokenPair] = useRecoilState(tokenPairState);
|
||||||
|
|
||||||
return !!tokenPair;
|
return !!tokenPair;
|
||||||
}
|
};
|
||||||
|
@ -7,9 +7,9 @@ import {
|
|||||||
OnboardingStatus,
|
OnboardingStatus,
|
||||||
} from '../utils/getOnboardingStatus';
|
} from '../utils/getOnboardingStatus';
|
||||||
|
|
||||||
export function useOnboardingStatus(): OnboardingStatus | undefined {
|
export const useOnboardingStatus = (): OnboardingStatus | undefined => {
|
||||||
const [currentUser] = useRecoilState(currentUserState);
|
const [currentUser] = useRecoilState(currentUserState);
|
||||||
const isLoggedIn = useIsLogged();
|
const isLoggedIn = useIsLogged();
|
||||||
|
|
||||||
return getOnboardingStatus(isLoggedIn, currentUser);
|
return getOnboardingStatus(isLoggedIn, currentUser);
|
||||||
}
|
};
|
||||||
|
@ -11,6 +11,4 @@ const StyledContainer = styled.div`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function FooterNote(props: Props) {
|
export const FooterNote = (props: Props) => <StyledContainer {...props} />;
|
||||||
return <StyledContainer {...props} />;
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { JSX } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
const StyledSeparator = styled.div`
|
const StyledSeparator = styled.div`
|
||||||
@ -8,6 +9,4 @@ const StyledSeparator = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function HorizontalSeparator(): JSX.Element {
|
export const HorizontalSeparator = (): JSX.Element => <StyledSeparator />;
|
||||||
return <StyledSeparator />;
|
|
||||||
}
|
|
||||||
|
@ -41,7 +41,7 @@ const StyledInputContainer = styled.div`
|
|||||||
margin-bottom: ${({ theme }) => theme.spacing(3)};
|
margin-bottom: ${({ theme }) => theme.spacing(3)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function SignInUpForm() {
|
export const SignInUpForm = () => {
|
||||||
const {
|
const {
|
||||||
authProviders,
|
authProviders,
|
||||||
signInWithGoogle,
|
signInWithGoogle,
|
||||||
@ -220,4 +220,4 @@ export function SignInUpForm() {
|
|||||||
</StyledFooterNote>
|
</StyledFooterNote>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -42,7 +42,7 @@ const validationSchema = Yup.object()
|
|||||||
|
|
||||||
type Form = Yup.InferType<typeof validationSchema>;
|
type Form = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export function useSignInUp() {
|
export const useSignInUp = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const isMatchingLocation = useIsMatchingLocation();
|
const isMatchingLocation = useIsMatchingLocation();
|
||||||
@ -183,4 +183,4 @@ export function useSignInUp() {
|
|||||||
form,
|
form,
|
||||||
workspace: workspace?.findWorkspaceFromInviteHash,
|
workspace: workspace?.findWorkspaceFromInviteHash,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -7,10 +7,10 @@ export enum OnboardingStatus {
|
|||||||
Completed = 'completed',
|
Completed = 'completed',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOnboardingStatus(
|
export const getOnboardingStatus = (
|
||||||
isLoggedIn: boolean,
|
isLoggedIn: boolean,
|
||||||
currentUser: CurrentUser | null,
|
currentUser: CurrentUser | null,
|
||||||
) {
|
) => {
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
return OnboardingStatus.OngoingUserCreation;
|
return OnboardingStatus.OngoingUserCreation;
|
||||||
}
|
}
|
||||||
@ -28,4 +28,4 @@ export function getOnboardingStatus(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return OnboardingStatus.Completed;
|
return OnboardingStatus.Completed;
|
||||||
}
|
};
|
||||||
|
@ -28,7 +28,7 @@ import {
|
|||||||
StyledList,
|
StyledList,
|
||||||
} from './CommandMenuStyles';
|
} from './CommandMenuStyles';
|
||||||
|
|
||||||
export function CommandMenu() {
|
export const CommandMenu = () => {
|
||||||
const { openCommandMenu, closeCommandMenu } = useCommandMenu();
|
const { openCommandMenu, closeCommandMenu } = useCommandMenu();
|
||||||
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
||||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||||
@ -219,4 +219,4 @@ export function CommandMenu() {
|
|||||||
</StyledList>
|
</StyledList>
|
||||||
</StyledDialog>
|
</StyledDialog>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -16,13 +16,13 @@ export type CommandMenuItemProps = {
|
|||||||
shortcuts?: Array<string>;
|
shortcuts?: Array<string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CommandMenuItem({
|
export const CommandMenuItem = ({
|
||||||
label,
|
label,
|
||||||
to,
|
to,
|
||||||
onClick,
|
onClick,
|
||||||
Icon,
|
Icon,
|
||||||
shortcuts,
|
shortcuts,
|
||||||
}: CommandMenuItemProps) {
|
}: CommandMenuItemProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { closeCommandMenu } = useCommandMenu();
|
const { closeCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
@ -51,4 +51,4 @@ export function CommandMenuItem({
|
|||||||
onClick={onItemClick}
|
onClick={onItemClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -8,7 +8,7 @@ import { commandMenuCommandsState } from '../states/commandMenuCommandsState';
|
|||||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||||
import { Command } from '../types/Command';
|
import { Command } from '../types/Command';
|
||||||
|
|
||||||
export function useCommandMenu() {
|
export const useCommandMenu = () => {
|
||||||
const [, setIsCommandMenuOpened] = useRecoilState(isCommandMenuOpenedState);
|
const [, setIsCommandMenuOpened] = useRecoilState(isCommandMenuOpenedState);
|
||||||
const setCommands = useSetRecoilState(commandMenuCommandsState);
|
const setCommands = useSetRecoilState(commandMenuCommandsState);
|
||||||
const {
|
const {
|
||||||
@ -16,23 +16,23 @@ export function useCommandMenu() {
|
|||||||
goBackToPreviousHotkeyScope,
|
goBackToPreviousHotkeyScope,
|
||||||
} = usePreviousHotkeyScope();
|
} = usePreviousHotkeyScope();
|
||||||
|
|
||||||
function openCommandMenu() {
|
const openCommandMenu = () => {
|
||||||
setIsCommandMenuOpened(true);
|
setIsCommandMenuOpened(true);
|
||||||
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenu);
|
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenu);
|
||||||
}
|
};
|
||||||
|
|
||||||
function closeCommandMenu() {
|
const closeCommandMenu = () => {
|
||||||
setIsCommandMenuOpened(false);
|
setIsCommandMenuOpened(false);
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
}
|
};
|
||||||
|
|
||||||
function addToCommandMenu(addCommand: Command[]) {
|
const addToCommandMenu = (addCommand: Command[]) => {
|
||||||
setCommands((prev) => [...prev, ...addCommand]);
|
setCommands((prev) => [...prev, ...addCommand]);
|
||||||
}
|
};
|
||||||
|
|
||||||
function setToIntitialCommandMenu() {
|
const setToIntitialCommandMenu = () => {
|
||||||
setCommands(commandMenuCommands);
|
setCommands(commandMenuCommands);
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
openCommandMenu,
|
openCommandMenu,
|
||||||
@ -40,4 +40,4 @@ export function useCommandMenu() {
|
|||||||
addToCommandMenu,
|
addToCommandMenu,
|
||||||
setToIntitialCommandMenu,
|
setToIntitialCommandMenu,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -38,13 +38,13 @@ const StyledInputContainer = styled.div`
|
|||||||
|
|
||||||
const defaultUsername = { firstName: '', lastName: '' };
|
const defaultUsername = { firstName: '', lastName: '' };
|
||||||
|
|
||||||
export function AddPersonToCompany({
|
export const AddPersonToCompany = ({
|
||||||
companyId,
|
companyId,
|
||||||
peopleIds,
|
peopleIds,
|
||||||
}: {
|
}: {
|
||||||
companyId: string;
|
companyId: string;
|
||||||
peopleIds?: string[];
|
peopleIds?: string[];
|
||||||
}) {
|
}) => {
|
||||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||||
const [isCreationDropdownOpen, setIsCreationDropdownOpen] = useState(false);
|
const [isCreationDropdownOpen, setIsCreationDropdownOpen] = useState(false);
|
||||||
const [username, setUsername] = useState(defaultUsername);
|
const [username, setUsername] = useState(defaultUsername);
|
||||||
@ -60,8 +60,8 @@ export function AddPersonToCompany({
|
|||||||
goBackToPreviousHotkeyScope,
|
goBackToPreviousHotkeyScope,
|
||||||
} = usePreviousHotkeyScope();
|
} = usePreviousHotkeyScope();
|
||||||
|
|
||||||
function handlePersonSelected(companyId: string) {
|
const handlePersonSelected =
|
||||||
return async (newPerson: PersonForSelect | null) => {
|
(companyId: string) => async (newPerson: PersonForSelect | null) => {
|
||||||
if (newPerson) {
|
if (newPerson) {
|
||||||
await updatePerson({
|
await updatePerson({
|
||||||
variables: {
|
variables: {
|
||||||
@ -77,30 +77,31 @@ export function AddPersonToCompany({
|
|||||||
handleClosePicker();
|
handleClosePicker();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function handleClosePicker() {
|
const handleClosePicker = () => {
|
||||||
if (isDropdownOpen) {
|
if (isDropdownOpen) {
|
||||||
setIsDropdownOpen(false);
|
setIsDropdownOpen(false);
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleOpenPicker() {
|
const handleOpenPicker = () => {
|
||||||
if (!isDropdownOpen) {
|
if (!isDropdownOpen) {
|
||||||
setIsDropdownOpen(true);
|
setIsDropdownOpen(true);
|
||||||
setHotkeyScopeAndMemorizePreviousScope(
|
setHotkeyScopeAndMemorizePreviousScope(
|
||||||
RelationPickerHotkeyScope.RelationPicker,
|
RelationPickerHotkeyScope.RelationPicker,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleUsernameChange(type: 'firstName' | 'lastName') {
|
const handleUsernameChange =
|
||||||
return (name: string): void =>
|
(type: 'firstName' | 'lastName') =>
|
||||||
|
(name: string): void =>
|
||||||
setUsername((prevUserName) => ({ ...prevUserName, [type]: name }));
|
setUsername((prevUserName) => ({ ...prevUserName, [type]: name }));
|
||||||
}
|
|
||||||
|
|
||||||
async function handleInputKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
|
const handleInputKeyDown = async (
|
||||||
|
e: React.KeyboardEvent<HTMLInputElement>,
|
||||||
|
) => {
|
||||||
if (e.key !== 'Enter' || (!username.firstName && !username.lastName))
|
if (e.key !== 'Enter' || (!username.firstName && !username.lastName))
|
||||||
return;
|
return;
|
||||||
const newPersonId = v4();
|
const newPersonId = v4();
|
||||||
@ -116,7 +117,7 @@ export function AddPersonToCompany({
|
|||||||
});
|
});
|
||||||
setIsCreationDropdownOpen(false);
|
setIsCreationDropdownOpen(false);
|
||||||
setUsername(defaultUsername);
|
setUsername(defaultUsername);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecoilScope>
|
<RecoilScope>
|
||||||
@ -161,4 +162,4 @@ export function AddPersonToCompany({
|
|||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -100,7 +100,7 @@ const StyledFieldContainer = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function CompanyBoardCard() {
|
export const CompanyBoardCard = () => {
|
||||||
const { BoardRecoilScopeContext } = useBoardContext();
|
const { BoardRecoilScopeContext } = useBoardContext();
|
||||||
|
|
||||||
const { currentCardSelected, setCurrentCardSelected } =
|
const { currentCardSelected, setCurrentCardSelected } =
|
||||||
@ -122,21 +122,19 @@ export function CompanyBoardCard() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function PreventSelectOnClickContainer({
|
const PreventSelectOnClickContainer = ({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) {
|
}) => (
|
||||||
return (
|
<StyledFieldContainer
|
||||||
<StyledFieldContainer
|
onClick={(e) => {
|
||||||
onClick={(e) => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{children}
|
||||||
{children}
|
</StyledFieldContainer>
|
||||||
</StyledFieldContainer>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBoardCardWrapper>
|
<StyledBoardCardWrapper>
|
||||||
@ -185,4 +183,4 @@ export function CompanyBoardCard() {
|
|||||||
</StyledBoardCard>
|
</StyledBoardCard>
|
||||||
</StyledBoardCardWrapper>
|
</StyledBoardCardWrapper>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -7,20 +7,18 @@ type OwnProps = {
|
|||||||
variant?: EntityChipVariant;
|
variant?: EntityChipVariant;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CompanyChip({
|
export const CompanyChip = ({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
pictureUrl,
|
pictureUrl,
|
||||||
variant = EntityChipVariant.Regular,
|
variant = EntityChipVariant.Regular,
|
||||||
}: OwnProps) {
|
}: OwnProps) => (
|
||||||
return (
|
<EntityChip
|
||||||
<EntityChip
|
entityId={id}
|
||||||
entityId={id}
|
linkToEntity={`/companies/${id}`}
|
||||||
linkToEntity={`/companies/${id}`}
|
name={name}
|
||||||
name={name}
|
avatarType="squared"
|
||||||
avatarType="squared"
|
pictureUrl={pictureUrl}
|
||||||
pictureUrl={pictureUrl}
|
variant={variant}
|
||||||
variant={variant}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ export type OwnProps = {
|
|||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CompanyPicker({ companyId, onSubmit, onCancel }: OwnProps) {
|
export const CompanyPicker = ({ companyId, onSubmit, onCancel }: OwnProps) => {
|
||||||
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
|
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
|
||||||
useRecoilScopedState(relationPickerSearchFilterScopedState);
|
useRecoilScopedState(relationPickerSearchFilterScopedState);
|
||||||
|
|
||||||
@ -22,11 +22,11 @@ export function CompanyPicker({ companyId, onSubmit, onCancel }: OwnProps) {
|
|||||||
selectedIds: companyId ? [companyId] : [],
|
selectedIds: companyId ? [companyId] : [],
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleEntitySelected(
|
const handleEntitySelected = async (
|
||||||
selectedCompany: EntityForSelect | null | undefined,
|
selectedCompany: EntityForSelect | null | undefined,
|
||||||
) {
|
) => {
|
||||||
onSubmit(selectedCompany ?? null);
|
onSubmit(selectedCompany ?? null);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRelationPickerSearchFilter('');
|
setRelationPickerSearchFilter('');
|
||||||
@ -41,4 +41,4 @@ export function CompanyPicker({ companyId, onSubmit, onCancel }: OwnProps) {
|
|||||||
selectedEntity={companies.selectedEntities[0]}
|
selectedEntity={companies.selectedEntities[0]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -23,13 +23,13 @@ export type CompanyPickerSelectedCompany = EntityForSelect & {
|
|||||||
domainName: string;
|
domainName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CompanyPickerCell({
|
export const CompanyPickerCell = ({
|
||||||
companyId,
|
companyId,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
createModeEnabled,
|
createModeEnabled,
|
||||||
width,
|
width,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const [isCreateMode, setIsCreateMode] = useRecoilScopedState(
|
const [isCreateMode, setIsCreateMode] = useRecoilScopedState(
|
||||||
isCreateModeScopedState,
|
isCreateModeScopedState,
|
||||||
);
|
);
|
||||||
@ -47,18 +47,18 @@ export function CompanyPickerCell({
|
|||||||
selectedIds: [companyId ?? ''],
|
selectedIds: [companyId ?? ''],
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleCompanySelected(
|
const handleCompanySelected = async (
|
||||||
company: CompanyPickerSelectedCompany | null | undefined,
|
company: CompanyPickerSelectedCompany | null | undefined,
|
||||||
) {
|
) => {
|
||||||
onSubmit(company ?? null);
|
onSubmit(company ?? null);
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleStartCreation() {
|
const handleStartCreation = () => {
|
||||||
setIsCreateMode(true);
|
setIsCreateMode(true);
|
||||||
setHotkeyScope(TableHotkeyScope.CellDoubleTextInput);
|
setHotkeyScope(TableHotkeyScope.CellDoubleTextInput);
|
||||||
}
|
};
|
||||||
|
|
||||||
async function handleCreate(firstValue: string, secondValue: string) {
|
const handleCreate = async (firstValue: string, secondValue: string) => {
|
||||||
const insertCompanyRequest = await insertCompany({
|
const insertCompanyRequest = await insertCompany({
|
||||||
variables: {
|
variables: {
|
||||||
data: {
|
data: {
|
||||||
@ -77,7 +77,7 @@ export function CompanyPickerCell({
|
|||||||
domainName: companyCreated.domainName,
|
domainName: companyCreated.domainName,
|
||||||
});
|
});
|
||||||
setIsCreateMode(false);
|
setIsCreateMode(false);
|
||||||
}
|
};
|
||||||
return isCreateMode ? (
|
return isCreateMode ? (
|
||||||
<DoubleTextCellEdit
|
<DoubleTextCellEdit
|
||||||
firstValue={relationPickerSearchFilter}
|
firstValue={relationPickerSearchFilter}
|
||||||
@ -99,4 +99,4 @@ export function CompanyPickerCell({
|
|||||||
width={width}
|
width={width}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -25,11 +25,11 @@ export type OwnProps = {
|
|||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CompanyProgressPicker({
|
export const CompanyProgressPicker = ({
|
||||||
companyId,
|
companyId,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
}: OwnProps) {
|
}: OwnProps) => {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
||||||
@ -53,16 +53,16 @@ export function CompanyProgressPicker({
|
|||||||
[currentPipeline],
|
[currentPipeline],
|
||||||
);
|
);
|
||||||
|
|
||||||
function handlePipelineStageChange(newPipelineStageId: string) {
|
const handlePipelineStageChange = (newPipelineStageId: string) => {
|
||||||
setSelectedPipelineStageId(newPipelineStageId);
|
setSelectedPipelineStageId(newPipelineStageId);
|
||||||
setIsProgressSelectionUnfolded(false);
|
setIsProgressSelectionUnfolded(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
async function handleEntitySelected(
|
const handleEntitySelected = async (
|
||||||
selectedCompany: EntityForSelect | null | undefined,
|
selectedCompany: EntityForSelect | null | undefined,
|
||||||
) {
|
) => {
|
||||||
onSubmit(selectedCompany ?? null, selectedPipelineStageId);
|
onSubmit(selectedCompany ?? null, selectedPipelineStageId);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentPipelineStages?.[0]?.id) {
|
if (currentPipelineStages?.[0]?.id) {
|
||||||
@ -125,4 +125,4 @@ export function CompanyProgressPicker({
|
|||||||
)}
|
)}
|
||||||
</StyledDropdownMenu>
|
</StyledDropdownMenu>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -42,7 +42,7 @@ const StyledTitle = styled.div`
|
|||||||
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function CompanyTeam({ company }: CompanyTeamPropsType) {
|
export const CompanyTeam = ({ company }: CompanyTeamPropsType) => {
|
||||||
const { data } = useGetPeopleQuery({
|
const { data } = useGetPeopleQuery({
|
||||||
variables: {
|
variables: {
|
||||||
orderBy: [],
|
orderBy: [],
|
||||||
@ -77,4 +77,4 @@ export function CompanyTeam({ company }: CompanyTeamPropsType) {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -7,7 +7,7 @@ import { filterDropdownSelectedEntityIdScopedState } from '@/ui/view-bar/states/
|
|||||||
|
|
||||||
import { useFilteredSearchCompanyQuery } from '../hooks/useFilteredSearchCompanyQuery';
|
import { useFilteredSearchCompanyQuery } from '../hooks/useFilteredSearchCompanyQuery';
|
||||||
|
|
||||||
export function FilterDropdownCompanySearchSelect() {
|
export const FilterDropdownCompanySearchSelect = () => {
|
||||||
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
||||||
|
|
||||||
const filterDropdownSearchInput = useRecoilScopedValue(
|
const filterDropdownSearchInput = useRecoilScopedValue(
|
||||||
@ -30,4 +30,4 @@ export function FilterDropdownCompanySearchSelect() {
|
|||||||
return (
|
return (
|
||||||
<FilterDropdownEntitySearchSelect entitiesForSelect={usersForSelect} />
|
<FilterDropdownEntitySearchSelect entitiesForSelect={usersForSelect} />
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -24,7 +24,7 @@ import { useUpdateCompanyBoardCardIds } from '../hooks/useUpdateBoardCardIds';
|
|||||||
import { useUpdateCompanyBoard } from '../hooks/useUpdateCompanyBoardColumns';
|
import { useUpdateCompanyBoard } from '../hooks/useUpdateCompanyBoardColumns';
|
||||||
import { CompanyBoardRecoilScopeContext } from '../states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
|
import { CompanyBoardRecoilScopeContext } from '../states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
|
||||||
|
|
||||||
export function HooksCompanyBoardEffect() {
|
export const HooksCompanyBoardEffect = () => {
|
||||||
const [, setAvailableFilters] = useRecoilScopedState(
|
const [, setAvailableFilters] = useRecoilScopedState(
|
||||||
availableFiltersScopedState,
|
availableFiltersScopedState,
|
||||||
CompanyBoardRecoilScopeContext,
|
CompanyBoardRecoilScopeContext,
|
||||||
@ -134,4 +134,4 @@ export function HooksCompanyBoardEffect() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
};
|
||||||
|
@ -12,7 +12,7 @@ import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoi
|
|||||||
import { useCreateCompanyProgress } from '../hooks/useCreateCompanyProgress';
|
import { useCreateCompanyProgress } from '../hooks/useCreateCompanyProgress';
|
||||||
import { useFilteredSearchCompanyQuery } from '../hooks/useFilteredSearchCompanyQuery';
|
import { useFilteredSearchCompanyQuery } from '../hooks/useFilteredSearchCompanyQuery';
|
||||||
|
|
||||||
export function NewCompanyProgressButton() {
|
export const NewCompanyProgressButton = () => {
|
||||||
const [isCreatingCard, setIsCreatingCard] = useState(false);
|
const [isCreatingCard, setIsCreatingCard] = useState(false);
|
||||||
const pipelineStageId = useContext(BoardColumnIdContext);
|
const pipelineStageId = useContext(BoardColumnIdContext);
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ export function NewCompanyProgressButton() {
|
|||||||
|
|
||||||
const createCompanyProgress = useCreateCompanyProgress();
|
const createCompanyProgress = useCreateCompanyProgress();
|
||||||
|
|
||||||
function handleEntitySelect(company: any) {
|
const handleEntitySelect = (company: any) => {
|
||||||
setIsCreatingCard(false);
|
setIsCreatingCard(false);
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export function NewCompanyProgressButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createCompanyProgress(company.id, pipelineStageId);
|
createCompanyProgress(company.id, pipelineStageId);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleNewClick = useCallback(() => {
|
const handleNewClick = useCallback(() => {
|
||||||
setIsCreatingCard(true);
|
setIsCreatingCard(true);
|
||||||
@ -47,10 +47,10 @@ export function NewCompanyProgressButton() {
|
|||||||
);
|
);
|
||||||
}, [setIsCreatingCard, setHotkeyScopeAndMemorizePreviousScope]);
|
}, [setIsCreatingCard, setHotkeyScopeAndMemorizePreviousScope]);
|
||||||
|
|
||||||
function handleCancel() {
|
const handleCancel = () => {
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
setIsCreatingCard(false);
|
setIsCreatingCard(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const [relationPickerSearchFilter] = useRecoilScopedState(
|
const [relationPickerSearchFilter] = useRecoilScopedState(
|
||||||
relationPickerSearchFilterScopedState,
|
relationPickerSearchFilterScopedState,
|
||||||
@ -76,4 +76,4 @@ export function NewCompanyProgressButton() {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -33,7 +33,7 @@ const StyledEditableTitleInput = styled.input<{
|
|||||||
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function CompanyNameEditableField({ company }: OwnProps) {
|
export const CompanyNameEditableField = ({ company }: OwnProps) => {
|
||||||
const [internalValue, setInternalValue] = useState(company.name);
|
const [internalValue, setInternalValue] = useState(company.name);
|
||||||
|
|
||||||
const [updateCompany] = useUpdateOneCompanyMutation();
|
const [updateCompany] = useUpdateOneCompanyMutation();
|
||||||
@ -42,11 +42,11 @@ export function CompanyNameEditableField({ company }: OwnProps) {
|
|||||||
setInternalValue(company.name);
|
setInternalValue(company.name);
|
||||||
}, [company.name]);
|
}, [company.name]);
|
||||||
|
|
||||||
async function handleChange(newValue: string) {
|
const handleChange = async (newValue: string) => {
|
||||||
setInternalValue(newValue);
|
setInternalValue(newValue);
|
||||||
}
|
};
|
||||||
|
|
||||||
async function handleSubmit() {
|
const handleSubmit = async () => {
|
||||||
await updateCompany({
|
await updateCompany({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
@ -57,7 +57,7 @@ export function CompanyNameEditableField({ company }: OwnProps) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
||||||
@ -69,4 +69,4 @@ export function CompanyNameEditableField({ company }: OwnProps) {
|
|||||||
/>
|
/>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -3,7 +3,7 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
import { genericEntitiesFamilyState } from '@/ui/editable-field/states/genericEntitiesFamilyState';
|
import { genericEntitiesFamilyState } from '@/ui/editable-field/states/genericEntitiesFamilyState';
|
||||||
import { useGetCompanyQuery } from '~/generated/graphql';
|
import { useGetCompanyQuery } from '~/generated/graphql';
|
||||||
|
|
||||||
export function useCompanyQuery(id: string) {
|
export const useCompanyQuery = (id: string) => {
|
||||||
const updateCompanyShowPage = useSetRecoilState(
|
const updateCompanyShowPage = useSetRecoilState(
|
||||||
genericEntitiesFamilyState(id),
|
genericEntitiesFamilyState(id),
|
||||||
);
|
);
|
||||||
@ -13,4 +13,4 @@ export function useCompanyQuery(id: string) {
|
|||||||
updateCompanyShowPage(data?.findUniqueCompany);
|
updateCompanyShowPage(data?.findUniqueCompany);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
@ -8,15 +8,15 @@ import { ActivityType } from '~/generated/graphql';
|
|||||||
|
|
||||||
import { useDeleteSelectedComapnies } from './useDeleteCompanies';
|
import { useDeleteSelectedComapnies } from './useDeleteCompanies';
|
||||||
|
|
||||||
export function useCompanyTableActionBarEntries() {
|
export const useCompanyTableActionBarEntries = () => {
|
||||||
const setActionBarEntries = useSetRecoilState(actionBarEntriesState);
|
const setActionBarEntries = useSetRecoilState(actionBarEntriesState);
|
||||||
|
|
||||||
const openCreateActivityRightDrawer =
|
const openCreateActivityRightDrawer =
|
||||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
useOpenCreateActivityDrawerForSelectedRowIds();
|
||||||
|
|
||||||
async function handleActivityClick(type: ActivityType) {
|
const handleActivityClick = async (type: ActivityType) => {
|
||||||
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
||||||
}
|
};
|
||||||
|
|
||||||
const deleteSelectedCompanies = useDeleteSelectedComapnies();
|
const deleteSelectedCompanies = useDeleteSelectedComapnies();
|
||||||
return {
|
return {
|
||||||
@ -40,4 +40,4 @@ export function useCompanyTableActionBarEntries() {
|
|||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -8,15 +8,15 @@ import { ActivityType } from '~/generated/graphql';
|
|||||||
|
|
||||||
import { useDeleteSelectedComapnies } from './useDeleteCompanies';
|
import { useDeleteSelectedComapnies } from './useDeleteCompanies';
|
||||||
|
|
||||||
export function useCompanyTableContextMenuEntries() {
|
export const useCompanyTableContextMenuEntries = () => {
|
||||||
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
||||||
|
|
||||||
const openCreateActivityRightDrawer =
|
const openCreateActivityRightDrawer =
|
||||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
useOpenCreateActivityDrawerForSelectedRowIds();
|
||||||
|
|
||||||
async function handleButtonClick(type: ActivityType) {
|
const handleButtonClick = async (type: ActivityType) => {
|
||||||
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
||||||
}
|
};
|
||||||
|
|
||||||
const deleteSelectedCompanies = useDeleteSelectedComapnies();
|
const deleteSelectedCompanies = useDeleteSelectedComapnies();
|
||||||
|
|
||||||
@ -41,4 +41,4 @@ export function useCompanyTableContextMenuEntries() {
|
|||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -8,7 +8,7 @@ import { currentPipelineState } from '@/pipeline/states/currentPipelineState';
|
|||||||
import { boardCardIdsByColumnIdFamilyState } from '@/ui/board/states/boardCardIdsByColumnIdFamilyState';
|
import { boardCardIdsByColumnIdFamilyState } from '@/ui/board/states/boardCardIdsByColumnIdFamilyState';
|
||||||
import { useCreateOneCompanyPipelineProgressMutation } from '~/generated/graphql';
|
import { useCreateOneCompanyPipelineProgressMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
export function useCreateCompanyProgress() {
|
export const useCreateCompanyProgress = () => {
|
||||||
const [createOneCompanyPipelineProgress] =
|
const [createOneCompanyPipelineProgress] =
|
||||||
useCreateOneCompanyPipelineProgressMutation({
|
useCreateOneCompanyPipelineProgressMutation({
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
@ -44,4 +44,4 @@ export function useCreateCompanyProgress() {
|
|||||||
},
|
},
|
||||||
[createOneCompanyPipelineProgress, currentPipeline],
|
[createOneCompanyPipelineProgress, currentPipeline],
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -7,7 +7,7 @@ import { selectedRowIdsSelector } from '@/ui/table/states/selectors/selectedRowI
|
|||||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||||
import { useDeleteManyCompaniesMutation } from '~/generated/graphql';
|
import { useDeleteManyCompaniesMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
export function useDeleteSelectedComapnies() {
|
export const useDeleteSelectedComapnies = () => {
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
||||||
|
|
||||||
const resetRowSelection = useResetTableRowSelection();
|
const resetRowSelection = useResetTableRowSelection();
|
||||||
@ -18,7 +18,7 @@ export function useDeleteSelectedComapnies() {
|
|||||||
|
|
||||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||||
|
|
||||||
async function deleteSelectedCompanies() {
|
const deleteSelectedCompanies = async () => {
|
||||||
const rowIdsToDelete = selectedRowIds;
|
const rowIdsToDelete = selectedRowIds;
|
||||||
|
|
||||||
resetRowSelection();
|
resetRowSelection();
|
||||||
@ -46,7 +46,7 @@ export function useDeleteSelectedComapnies() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return deleteSelectedCompanies;
|
return deleteSelectedCompanies;
|
||||||
}
|
};
|
||||||
|
@ -3,7 +3,7 @@ import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEn
|
|||||||
import { useSearchCompanyQuery } from '~/generated/graphql';
|
import { useSearchCompanyQuery } from '~/generated/graphql';
|
||||||
import { getLogoUrlFromDomainName } from '~/utils';
|
import { getLogoUrlFromDomainName } from '~/utils';
|
||||||
|
|
||||||
export function useFilteredSearchCompanyQuery({
|
export const useFilteredSearchCompanyQuery = ({
|
||||||
searchFilter,
|
searchFilter,
|
||||||
selectedIds = [],
|
selectedIds = [],
|
||||||
limit,
|
limit,
|
||||||
@ -11,7 +11,7 @@ export function useFilteredSearchCompanyQuery({
|
|||||||
searchFilter: string;
|
searchFilter: string;
|
||||||
selectedIds?: string[];
|
selectedIds?: string[];
|
||||||
limit?: number;
|
limit?: number;
|
||||||
}) {
|
}) => {
|
||||||
return useFilteredSearchEntityQuery({
|
return useFilteredSearchEntityQuery({
|
||||||
queryHook: useSearchCompanyQuery,
|
queryHook: useSearchCompanyQuery,
|
||||||
filters: [
|
filters: [
|
||||||
@ -32,4 +32,4 @@ export function useFilteredSearchCompanyQuery({
|
|||||||
selectedIds: selectedIds,
|
selectedIds: selectedIds,
|
||||||
limit,
|
limit,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
@ -9,7 +9,7 @@ import { fieldsForCompany } from '../utils/fieldsForCompany';
|
|||||||
|
|
||||||
export type FieldCompanyMapping = (typeof fieldsForCompany)[number]['key'];
|
export type FieldCompanyMapping = (typeof fieldsForCompany)[number]['key'];
|
||||||
|
|
||||||
export function useSpreadsheetCompanyImport() {
|
export const useSpreadsheetCompanyImport = () => {
|
||||||
const { openSpreadsheetImport } = useSpreadsheetImport<FieldCompanyMapping>();
|
const { openSpreadsheetImport } = useSpreadsheetImport<FieldCompanyMapping>();
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export function useSpreadsheetCompanyImport() {
|
|||||||
) => {
|
) => {
|
||||||
openSpreadsheetImport({
|
openSpreadsheetImport({
|
||||||
...options,
|
...options,
|
||||||
async onSubmit(data) {
|
onSubmit: async (data) => {
|
||||||
// TODO: Add better type checking in spreadsheet import later
|
// TODO: Add better type checking in spreadsheet import later
|
||||||
const createInputs = data.validData.map((company) => ({
|
const createInputs = data.validData.map((company) => ({
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
@ -56,4 +56,4 @@ export function useSpreadsheetCompanyImport() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return { openCompanySpreadsheetImport };
|
return { openCompanySpreadsheetImport };
|
||||||
}
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user