deps: upgrade all dependencies
This commit is contained in:
		@@ -1 +1,2 @@
 | 
				
			|||||||
REACT_APP_ENABLE_POLLING=true
 | 
					REACT_APP_ENABLE_POLLING=true
 | 
				
			||||||
 | 
					ESLINT_NO_DEV_ERRORS=true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@
 | 
				
			|||||||
    "plugin:@typescript-eslint/recommended"
 | 
					    "plugin:@typescript-eslint/recommended"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "rules": {
 | 
					  "rules": {
 | 
				
			||||||
    "prettier/prettier": "error",
 | 
					    "prettier/prettier": "warn",
 | 
				
			||||||
    "no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
 | 
					    "no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
 | 
				
			||||||
    "@typescript-eslint/explicit-function-return-type": "off",
 | 
					    "@typescript-eslint/explicit-function-return-type": "off",
 | 
				
			||||||
    "@typescript-eslint/no-explicit-any": "off",
 | 
					    "@typescript-eslint/no-explicit-any": "off",
 | 
				
			||||||
@@ -48,6 +48,8 @@
 | 
				
			|||||||
        "tsx": "never"
 | 
					        "tsx": "never"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					    "no-use-before-define": "off",
 | 
				
			||||||
 | 
					    "@typescript-eslint/no-use-before-define": ["error"],
 | 
				
			||||||
    "import/no-extraneous-dependencies": [
 | 
					    "import/no-extraneous-dependencies": [
 | 
				
			||||||
      "error",
 | 
					      "error",
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,26 +3,22 @@
 | 
				
			|||||||
  "version": "0.1.0",
 | 
					  "version": "0.1.0",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@apollo/client": "^3.0.0-rc.8",
 | 
					    "@apollo/client": "^3.3.16",
 | 
				
			||||||
    "@apollo/react-common": "^3.1.4",
 | 
					    "@apollo/react-common": "^3.1.4",
 | 
				
			||||||
    "@apollo/react-hooks": "^3.1.3",
 | 
					    "@apollo/react-hooks": "^4.0.0",
 | 
				
			||||||
    "@types/axios": "^0.14.0",
 | 
					 | 
				
			||||||
    "@types/color": "^3.0.1",
 | 
					    "@types/color": "^3.0.1",
 | 
				
			||||||
    "@types/date-fns": "^2.6.0",
 | 
					    "@types/dompurify": "^2.2.2",
 | 
				
			||||||
    "@types/dompurify": "^2.0.4",
 | 
					 | 
				
			||||||
    "@types/emoji-mart": "^3.0.4",
 | 
					    "@types/emoji-mart": "^3.0.4",
 | 
				
			||||||
    "@types/jest": "^24.0.0",
 | 
					    "@types/jest": "^26.0.23",
 | 
				
			||||||
    "@types/jwt-decode": "^2.2.1",
 | 
					    "@types/lodash": "^4.14.168",
 | 
				
			||||||
    "@types/lodash": "^4.14.149",
 | 
					    "@types/node": "^15.0.1",
 | 
				
			||||||
    "@types/node": "^12.0.0",
 | 
					    "@types/react": "^17.0.4",
 | 
				
			||||||
    "@types/query-string": "^6.3.0",
 | 
					    "@types/react-beautiful-dnd": "^13.0.0",
 | 
				
			||||||
    "@types/react": "^16.9.21",
 | 
					    "@types/react-datepicker": "^3.1.8",
 | 
				
			||||||
    "@types/react-beautiful-dnd": "^12.1.1",
 | 
					    "@types/react-dom": "^17.0.3",
 | 
				
			||||||
    "@types/react-datepicker": "^2.11.0",
 | 
					    "@types/react-router": "^5.1.13",
 | 
				
			||||||
    "@types/react-dom": "^16.9.5",
 | 
					    "@types/react-router-dom": "^5.1.7",
 | 
				
			||||||
    "@types/react-router": "^5.1.4",
 | 
					    "@types/react-select": "^4.0.15",
 | 
				
			||||||
    "@types/react-router-dom": "^5.1.3",
 | 
					 | 
				
			||||||
    "@types/react-select": "^3.0.13",
 | 
					 | 
				
			||||||
    "@types/react-timeago": "^4.1.1",
 | 
					    "@types/react-timeago": "^4.1.1",
 | 
				
			||||||
    "@types/styled-components": "^5.1.0",
 | 
					    "@types/styled-components": "^5.1.0",
 | 
				
			||||||
    "apollo-cache-inmemory": "^1.6.5",
 | 
					    "apollo-cache-inmemory": "^1.6.5",
 | 
				
			||||||
@@ -33,39 +29,39 @@
 | 
				
			|||||||
    "apollo-link-state": "^0.4.2",
 | 
					    "apollo-link-state": "^0.4.2",
 | 
				
			||||||
    "apollo-utilities": "^1.3.3",
 | 
					    "apollo-utilities": "^1.3.3",
 | 
				
			||||||
    "axios": "^0.21.1",
 | 
					    "axios": "^0.21.1",
 | 
				
			||||||
    "axios-auth-refresh": "^2.2.7",
 | 
					    "axios-auth-refresh": "^3.1.0",
 | 
				
			||||||
    "color": "^3.1.2",
 | 
					    "color": "^3.1.2",
 | 
				
			||||||
    "date-fns": "^2.14.0",
 | 
					    "date-fns": "^2.21.1",
 | 
				
			||||||
    "dayjs": "^1.9.1",
 | 
					    "dayjs": "^1.10.4",
 | 
				
			||||||
    "dompurify": "^2.2.6",
 | 
					    "dompurify": "^2.2.8",
 | 
				
			||||||
    "emoji-mart": "^3.0.0",
 | 
					    "emoji-mart": "^3.0.1",
 | 
				
			||||||
    "emoticon": "^4.0.0",
 | 
					    "emoticon": "^4.0.0",
 | 
				
			||||||
    "graphql": "^15.0.0",
 | 
					    "graphql": "^15.5.0",
 | 
				
			||||||
    "graphql-tag": "^2.10.3",
 | 
					    "graphql-tag": "^2.12.4",
 | 
				
			||||||
    "history": "^4.10.1",
 | 
					    "history": "^5.0.0",
 | 
				
			||||||
    "immer": "^8.0.1",
 | 
					    "immer": "^9.0.2",
 | 
				
			||||||
    "jwt-decode": "^2.2.0",
 | 
					    "jwt-decode": "^3.1.2",
 | 
				
			||||||
    "lodash": "^4.17.20",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "node-emoji": "^1.10.0",
 | 
					    "node-emoji": "^1.10.0",
 | 
				
			||||||
    "prop-types": "^15.7.2",
 | 
					    "prop-types": "^15.7.2",
 | 
				
			||||||
    "query-string": "^6.13.7",
 | 
					    "query-string": "^7.0.0",
 | 
				
			||||||
    "react": "^16.12.0",
 | 
					    "react": "^17.0.2",
 | 
				
			||||||
    "react-autosize-textarea": "^7.0.0",
 | 
					    "react-autosize-textarea": "^7.0.0",
 | 
				
			||||||
    "react-beautiful-dnd": "^13.0.0",
 | 
					    "react-beautiful-dnd": "^13.1.0",
 | 
				
			||||||
    "react-datepicker": "^2.14.1",
 | 
					    "react-datepicker": "^3.8.0",
 | 
				
			||||||
    "react-dom": "^16.12.0",
 | 
					    "react-dom": "^17.0.2",
 | 
				
			||||||
    "react-emoji-render": "^1.2.4",
 | 
					    "react-emoji-render": "^1.2.4",
 | 
				
			||||||
    "react-hook-form": "^6.0.6",
 | 
					    "react-hook-form": "^7.3.6",
 | 
				
			||||||
    "react-markdown": "^4.3.1",
 | 
					    "react-markdown": "^6.0.1",
 | 
				
			||||||
    "react-router": "^5.1.2",
 | 
					    "react-router": "^5.1.2",
 | 
				
			||||||
    "react-router-dom": "^5.1.2",
 | 
					    "react-router-dom": "^5.1.2",
 | 
				
			||||||
    "react-scripts": "3.4.0",
 | 
					    "react-scripts": "4.0.3",
 | 
				
			||||||
    "react-select": "^3.1.0",
 | 
					    "react-select": "^4.3.0",
 | 
				
			||||||
    "react-timeago": "^4.4.0",
 | 
					    "react-timeago": "^5.2.0",
 | 
				
			||||||
    "react-toastify": "^6.0.8",
 | 
					    "react-toastify": "^7.0.4",
 | 
				
			||||||
    "rich-markdown-editor": "^10.6.5",
 | 
					    "rich-markdown-editor": "^11.0.10",
 | 
				
			||||||
    "styled-components": "^5.1.0",
 | 
					    "styled-components": "^5.2.3",
 | 
				
			||||||
    "typescript": "~3.7.2"
 | 
					    "typescript": "~4.2.4"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "proxy": "http://localhost:3333",
 | 
					  "proxy": "http://localhost:3333",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
@@ -97,16 +93,16 @@
 | 
				
			|||||||
    "@graphql-codegen/typescript": "^1.22.0",
 | 
					    "@graphql-codegen/typescript": "^1.22.0",
 | 
				
			||||||
    "@graphql-codegen/typescript-operations": "^1.17.16",
 | 
					    "@graphql-codegen/typescript-operations": "^1.17.16",
 | 
				
			||||||
    "@graphql-codegen/typescript-react-apollo": "^2.2.4",
 | 
					    "@graphql-codegen/typescript-react-apollo": "^2.2.4",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^2.20.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^4.22.0",
 | 
				
			||||||
    "@typescript-eslint/parser": "^2.20.0",
 | 
					    "@typescript-eslint/parser": "^4.22.0",
 | 
				
			||||||
    "eslint": "^6.8.0",
 | 
					    "eslint": "^7.25.0",
 | 
				
			||||||
    "eslint-config-airbnb": "^18.0.1",
 | 
					    "eslint-config-airbnb": "^18.0.1",
 | 
				
			||||||
    "eslint-config-prettier": "^6.10.0",
 | 
					    "eslint-config-prettier": "^8.3.0",
 | 
				
			||||||
    "eslint-plugin-import": "^2.20.1",
 | 
					    "eslint-plugin-import": "^2.20.1",
 | 
				
			||||||
    "eslint-plugin-jsx-a11y": "^6.2.3",
 | 
					    "eslint-plugin-jsx-a11y": "^6.2.3",
 | 
				
			||||||
    "eslint-plugin-prettier": "^3.1.2",
 | 
					    "eslint-plugin-prettier": "^3.4.0",
 | 
				
			||||||
    "eslint-plugin-react": "^7.18.3",
 | 
					    "eslint-plugin-react": "^7.23.2",
 | 
				
			||||||
    "eslint-plugin-react-hooks": "^1.7.0",
 | 
					    "eslint-plugin-react-hooks": "^4.2.0",
 | 
				
			||||||
    "prettier": "^1.19.1"
 | 
					    "prettier": "^2.2.1"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ import {
 | 
				
			|||||||
  UsersDocument,
 | 
					  UsersDocument,
 | 
				
			||||||
  UsersQuery,
 | 
					  UsersQuery,
 | 
				
			||||||
} from 'shared/generated/graphql';
 | 
					} from 'shared/generated/graphql';
 | 
				
			||||||
import Input from 'shared/components/Input';
 | 
					 | 
				
			||||||
import styled from 'styled-components';
 | 
					import styled from 'styled-components';
 | 
				
			||||||
import Button from 'shared/components/Button';
 | 
					import Button from 'shared/components/Button';
 | 
				
			||||||
import { useForm, Controller } from 'react-hook-form';
 | 
					import { useForm, Controller } from 'react-hook-form';
 | 
				
			||||||
@@ -20,6 +19,7 @@ import updateApolloCache from 'shared/utils/cache';
 | 
				
			|||||||
import { useCurrentUser } from 'App/context';
 | 
					import { useCurrentUser } from 'App/context';
 | 
				
			||||||
import { Redirect } from 'react-router';
 | 
					import { Redirect } from 'react-router';
 | 
				
			||||||
import NOOP from 'shared/utils/noop';
 | 
					import NOOP from 'shared/utils/noop';
 | 
				
			||||||
 | 
					import ControlledInput from 'shared/components/ControlledInput';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DeleteUserWrapper = styled.div`
 | 
					const DeleteUserWrapper = styled.div`
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
@@ -77,12 +77,12 @@ const CreateUserButton = styled(Button)`
 | 
				
			|||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AddUserInput = styled(Input)`
 | 
					const AddUserInput = styled(ControlledInput)`
 | 
				
			||||||
  margin-bottom: 8px;
 | 
					  margin-bottom: 8px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const InputError = styled.span`
 | 
					const InputError = styled.span`
 | 
				
			||||||
  color: ${props => props.theme.colors.danger};
 | 
					  color: ${(props) => props.theme.colors.danger};
 | 
				
			||||||
  font-size: 12px;
 | 
					  font-size: 12px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,7 +91,12 @@ type AddUserPopupProps = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
 | 
					const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
 | 
				
			||||||
  const { register, handleSubmit, errors, control } = useForm<CreateUserData>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					    control,
 | 
				
			||||||
 | 
					  } = useForm<CreateUserData>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const createUser = (data: CreateUserData) => {
 | 
					  const createUser = (data: CreateUserData) => {
 | 
				
			||||||
    onAddUser(data);
 | 
					    onAddUser(data);
 | 
				
			||||||
@@ -102,30 +107,25 @@ const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
 | 
				
			|||||||
        floatingLabel
 | 
					        floatingLabel
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        label="Full Name"
 | 
					        label="Full Name"
 | 
				
			||||||
        id="fullName"
 | 
					 | 
				
			||||||
        name="fullName"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					        variant="alternate"
 | 
				
			||||||
        ref={register({ required: 'Full name is required' })}
 | 
					        {...register('fullName', { required: 'Full name is required' })}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      {errors.fullName && <InputError>{errors.fullName.message}</InputError>}
 | 
					      {errors.fullName && <InputError>{errors.fullName.message}</InputError>}
 | 
				
			||||||
      <AddUserInput
 | 
					      <AddUserInput
 | 
				
			||||||
        floatingLabel
 | 
					        floatingLabel
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        label="Email"
 | 
					        label="Email"
 | 
				
			||||||
        id="email"
 | 
					 | 
				
			||||||
        name="email"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					        variant="alternate"
 | 
				
			||||||
        ref={register({ required: 'Email is required' })}
 | 
					        {...register('email', { required: 'Email is required' })}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <Controller
 | 
					      <Controller
 | 
				
			||||||
        control={control}
 | 
					        control={control}
 | 
				
			||||||
        name="roleCode"
 | 
					        name="roleCode"
 | 
				
			||||||
        rules={{ required: 'Role is required' }}
 | 
					        rules={{ required: 'Role is required' }}
 | 
				
			||||||
        render={({ onChange, value }) => (
 | 
					        render={({ field }) => (
 | 
				
			||||||
          <Select
 | 
					          <Select
 | 
				
			||||||
 | 
					            {...field}
 | 
				
			||||||
            label="Role"
 | 
					            label="Role"
 | 
				
			||||||
            value={value}
 | 
					 | 
				
			||||||
            onChange={onChange}
 | 
					 | 
				
			||||||
            options={[
 | 
					            options={[
 | 
				
			||||||
              { label: 'Admin', value: 'admin' },
 | 
					              { label: 'Admin', value: 'admin' },
 | 
				
			||||||
              { label: 'Member', value: 'member' },
 | 
					              { label: 'Member', value: 'member' },
 | 
				
			||||||
@@ -138,31 +138,25 @@ const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
 | 
				
			|||||||
        floatingLabel
 | 
					        floatingLabel
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        label="Username"
 | 
					        label="Username"
 | 
				
			||||||
        id="username"
 | 
					 | 
				
			||||||
        name="username"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					        variant="alternate"
 | 
				
			||||||
        ref={register({ required: 'Username is required' })}
 | 
					        {...register('username', { required: 'Username is required' })}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      {errors.username && <InputError>{errors.username.message}</InputError>}
 | 
					      {errors.username && <InputError>{errors.username.message}</InputError>}
 | 
				
			||||||
      <AddUserInput
 | 
					      <AddUserInput
 | 
				
			||||||
        floatingLabel
 | 
					        floatingLabel
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        label="Initials"
 | 
					        label="Initials"
 | 
				
			||||||
        id="initials"
 | 
					 | 
				
			||||||
        name="initials"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					        variant="alternate"
 | 
				
			||||||
        ref={register({ required: 'Initials is required' })}
 | 
					        {...register('initials', { required: 'Initials is required' })}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      {errors.initials && <InputError>{errors.initials.message}</InputError>}
 | 
					      {errors.initials && <InputError>{errors.initials.message}</InputError>}
 | 
				
			||||||
      <AddUserInput
 | 
					      <AddUserInput
 | 
				
			||||||
        floatingLabel
 | 
					        floatingLabel
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        label="Password"
 | 
					        label="Password"
 | 
				
			||||||
        id="password"
 | 
					 | 
				
			||||||
        name="password"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					        variant="alternate"
 | 
				
			||||||
        type="password"
 | 
					        type="password"
 | 
				
			||||||
        ref={register({ required: 'Password is required' })}
 | 
					        {...register('password', { required: 'Password is required' })}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      {errors.password && <InputError>{errors.password.message}</InputError>}
 | 
					      {errors.password && <InputError>{errors.password.message}</InputError>}
 | 
				
			||||||
      <CreateUserButton type="submit">Create</CreateUserButton>
 | 
					      <CreateUserButton type="submit">Create</CreateUserButton>
 | 
				
			||||||
@@ -179,10 +173,10 @@ const AdminRoute = () => {
 | 
				
			|||||||
  const { user } = useCurrentUser();
 | 
					  const { user } = useCurrentUser();
 | 
				
			||||||
  const [deleteInvitedUser] = useDeleteInvitedUserAccountMutation({
 | 
					  const [deleteInvitedUser] = useDeleteInvitedUserAccountMutation({
 | 
				
			||||||
    update: (client, response) => {
 | 
					    update: (client, response) => {
 | 
				
			||||||
      updateApolloCache<UsersQuery>(client, UsersDocument, cache =>
 | 
					      updateApolloCache<UsersQuery>(client, UsersDocument, (cache) =>
 | 
				
			||||||
        produce(cache, draftCache => {
 | 
					        produce(cache, (draftCache) => {
 | 
				
			||||||
          draftCache.invitedUsers = cache.invitedUsers.filter(
 | 
					          draftCache.invitedUsers = cache.invitedUsers.filter(
 | 
				
			||||||
            u => u.id !== response.data?.deleteInvitedUserAccount.invitedUser.id,
 | 
					            (u) => u.id !== response.data?.deleteInvitedUserAccount.invitedUser.id,
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -190,9 +184,9 @@ const AdminRoute = () => {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
  const [deleteUser] = useDeleteUserAccountMutation({
 | 
					  const [deleteUser] = useDeleteUserAccountMutation({
 | 
				
			||||||
    update: (client, response) => {
 | 
					    update: (client, response) => {
 | 
				
			||||||
      updateApolloCache<UsersQuery>(client, UsersDocument, cache =>
 | 
					      updateApolloCache<UsersQuery>(client, UsersDocument, (cache) =>
 | 
				
			||||||
        produce(cache, draftCache => {
 | 
					        produce(cache, (draftCache) => {
 | 
				
			||||||
          draftCache.users = cache.users.filter(u => u.id !== response.data?.deleteUserAccount.userAccount.id);
 | 
					          draftCache.users = cache.users.filter((u) => u.id !== response.data?.deleteUserAccount.userAccount.id);
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -234,7 +228,7 @@ TODO: add permision check
 | 
				
			|||||||
          onUpdateUserPassword={() => {
 | 
					          onUpdateUserPassword={() => {
 | 
				
			||||||
            hidePopup();
 | 
					            hidePopup();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onDeleteInvitedUser={invitedUserID => {
 | 
					          onDeleteInvitedUser={(invitedUserID) => {
 | 
				
			||||||
            deleteInvitedUser({ variables: { invitedUserID } });
 | 
					            deleteInvitedUser({ variables: { invitedUserID } });
 | 
				
			||||||
            hidePopup();
 | 
					            hidePopup();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
@@ -242,12 +236,12 @@ TODO: add permision check
 | 
				
			|||||||
            deleteUser({ variables: { userID, newOwnerID } });
 | 
					            deleteUser({ variables: { userID, newOwnerID } });
 | 
				
			||||||
            hidePopup();
 | 
					            hidePopup();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onAddUser={$target => {
 | 
					          onAddUser={($target) => {
 | 
				
			||||||
            showPopup(
 | 
					            showPopup(
 | 
				
			||||||
              $target,
 | 
					              $target,
 | 
				
			||||||
              <Popup tab={0} title="Add member" onClose={() => hidePopup()}>
 | 
					              <Popup tab={0} title="Add member" onClose={() => hidePopup()}>
 | 
				
			||||||
                <AddUserPopup
 | 
					                <AddUserPopup
 | 
				
			||||||
                  onAddUser={u => {
 | 
					                  onAddUser={(u) => {
 | 
				
			||||||
                    const { roleCode, ...userData } = u;
 | 
					                    const { roleCode, ...userData } = u;
 | 
				
			||||||
                    createUser({ variables: { ...userData, roleCode: roleCode.value } });
 | 
					                    createUser({ variables: { ...userData, roleCode: roleCode.value } });
 | 
				
			||||||
                    hidePopup();
 | 
					                    hidePopup();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ type ValidateTokenResponse = {
 | 
				
			|||||||
const UserRequiredRoute: React.FC<any> = ({ children }) => {
 | 
					const UserRequiredRoute: React.FC<any> = ({ children }) => {
 | 
				
			||||||
  const { user } = useCurrentUser();
 | 
					  const { user } = useCurrentUser();
 | 
				
			||||||
  const location = useLocation();
 | 
					  const location = useLocation();
 | 
				
			||||||
 | 
					  console.log('user required', user);
 | 
				
			||||||
  if (user) {
 | 
					  if (user) {
 | 
				
			||||||
    return children;
 | 
					    return children;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -45,18 +46,14 @@ const UserRequiredRoute: React.FC<any> = ({ children }) => {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoutesProps = {
 | 
					const Routes: React.FC = () => {
 | 
				
			||||||
  history: H.History;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const Routes: React.FC<RoutesProps> = () => {
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(true);
 | 
					  const [loading, setLoading] = useState(true);
 | 
				
			||||||
  const { setUser } = useCurrentUser();
 | 
					  const { setUser } = useCurrentUser();
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    fetch('/auth/validate', {
 | 
					    fetch('/auth/validate', {
 | 
				
			||||||
      method: 'POST',
 | 
					      method: 'POST',
 | 
				
			||||||
      credentials: 'include',
 | 
					      credentials: 'include',
 | 
				
			||||||
    }).then(async x => {
 | 
					    }).then(async (x) => {
 | 
				
			||||||
      const response: ValidateTokenResponse = await x.json();
 | 
					      const response: ValidateTokenResponse = await x.json();
 | 
				
			||||||
      const { valid, userID } = response;
 | 
					      const { valid, userID } = response;
 | 
				
			||||||
      if (valid) {
 | 
					      if (valid) {
 | 
				
			||||||
@@ -65,6 +62,7 @@ const Routes: React.FC<RoutesProps> = () => {
 | 
				
			|||||||
      setLoading(false);
 | 
					      setLoading(false);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
 | 
					  console.log('loading', loading);
 | 
				
			||||||
  if (loading) return null;
 | 
					  if (loading) return null;
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Switch>
 | 
					    <Switch>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
import React, { useState, useEffect } from 'react';
 | 
					import React, { useState, useEffect } from 'react';
 | 
				
			||||||
import { createBrowserHistory } from 'history';
 | 
					import { BrowserRouter } from 'react-router-dom';
 | 
				
			||||||
import { Router } from 'react-router';
 | 
					 | 
				
			||||||
import { PopupProvider } from 'shared/components/PopupMenu';
 | 
					import { PopupProvider } from 'shared/components/PopupMenu';
 | 
				
			||||||
import styled, { ThemeProvider } from 'styled-components';
 | 
					import styled, { ThemeProvider } from 'styled-components';
 | 
				
			||||||
import NormalizeStyles from './NormalizeStyles';
 | 
					import NormalizeStyles from './NormalizeStyles';
 | 
				
			||||||
@@ -13,8 +12,6 @@ import { UserContext } from './context';
 | 
				
			|||||||
import 'react-toastify/dist/ReactToastify.css';
 | 
					import 'react-toastify/dist/ReactToastify.css';
 | 
				
			||||||
import './fonts.css';
 | 
					import './fonts.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const history = createBrowserHistory();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const App = () => {
 | 
					const App = () => {
 | 
				
			||||||
  const [user, setUser] = useState<string | null>(null);
 | 
					  const [user, setUser] = useState<string | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,11 +21,11 @@ const App = () => {
 | 
				
			|||||||
        <ThemeProvider theme={theme}>
 | 
					        <ThemeProvider theme={theme}>
 | 
				
			||||||
          <NormalizeStyles />
 | 
					          <NormalizeStyles />
 | 
				
			||||||
          <BaseStyles />
 | 
					          <BaseStyles />
 | 
				
			||||||
          <Router history={history}>
 | 
					          <BrowserRouter>
 | 
				
			||||||
            <PopupProvider>
 | 
					            <PopupProvider>
 | 
				
			||||||
              <Routes history={history} />
 | 
					              <Routes />
 | 
				
			||||||
            </PopupProvider>
 | 
					            </PopupProvider>
 | 
				
			||||||
          </Router>
 | 
					          </BrowserRouter>
 | 
				
			||||||
          <ToastedContainer
 | 
					          <ToastedContainer
 | 
				
			||||||
            position="bottom-right"
 | 
					            position="bottom-right"
 | 
				
			||||||
            autoClose={5000}
 | 
					            autoClose={5000}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ const Auth = () => {
 | 
				
			|||||||
  const history = useHistory();
 | 
					  const history = useHistory();
 | 
				
			||||||
  const location = useLocation<{ redirect: string } | undefined>();
 | 
					  const location = useLocation<{ redirect: string } | undefined>();
 | 
				
			||||||
  const { setUser } = useContext(UserContext);
 | 
					  const { setUser } = useContext(UserContext);
 | 
				
			||||||
 | 
					  console.log('auth');
 | 
				
			||||||
  const login = (
 | 
					  const login = (
 | 
				
			||||||
    data: LoginFormData,
 | 
					    data: LoginFormData,
 | 
				
			||||||
    setComplete: (val: boolean) => void,
 | 
					    setComplete: (val: boolean) => void,
 | 
				
			||||||
@@ -21,7 +22,7 @@ const Auth = () => {
 | 
				
			|||||||
        username: data.username,
 | 
					        username: data.username,
 | 
				
			||||||
        password: data.password,
 | 
					        password: data.password,
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
    }).then(async x => {
 | 
					    }).then(async (x) => {
 | 
				
			||||||
      if (x.status === 401) {
 | 
					      if (x.status === 401) {
 | 
				
			||||||
        setInvalidLoginAttempt(invalidLoginAttempt + 1);
 | 
					        setInvalidLoginAttempt(invalidLoginAttempt + 1);
 | 
				
			||||||
        setError('username', { type: 'error', message: 'Invalid username' });
 | 
					        setError('username', { type: 'error', message: 'Invalid username' });
 | 
				
			||||||
@@ -44,7 +45,7 @@ const Auth = () => {
 | 
				
			|||||||
    fetch('/auth/validate', {
 | 
					    fetch('/auth/validate', {
 | 
				
			||||||
      method: 'POST',
 | 
					      method: 'POST',
 | 
				
			||||||
      credentials: 'include',
 | 
					      credentials: 'include',
 | 
				
			||||||
    }).then(async x => {
 | 
					    }).then(async (x) => {
 | 
				
			||||||
      const response = await x.json();
 | 
					      const response = await x.json();
 | 
				
			||||||
      const { valid, userID } = response;
 | 
					      const { valid, userID } = response;
 | 
				
			||||||
      if (valid) {
 | 
					      if (valid) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@ import useStickyState from 'shared/hooks/useStickyState';
 | 
				
			|||||||
import MyTasksSortPopup from './MyTasksSort';
 | 
					import MyTasksSortPopup from './MyTasksSort';
 | 
				
			||||||
import MyTasksStatusPopup from './MyTasksStatus';
 | 
					import MyTasksStatusPopup from './MyTasksStatus';
 | 
				
			||||||
import TaskEntry from './TaskEntry';
 | 
					import TaskEntry from './TaskEntry';
 | 
				
			||||||
 | 
					import { StaticContext } from 'react-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TaskRouteProps = {
 | 
					type TaskRouteProps = {
 | 
				
			||||||
  taskID: string;
 | 
					  taskID: string;
 | 
				
			||||||
@@ -61,11 +62,7 @@ function prettySort(sort: MyTasksSort) {
 | 
				
			|||||||
  if (sort === MyTasksSort.None) {
 | 
					  if (sort === MyTasksSort.None) {
 | 
				
			||||||
    return 'Sort';
 | 
					    return 'Sort';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return `Sort: ${sort.charAt(0) +
 | 
					  return `Sort: ${sort.charAt(0) + sort.slice(1).toLowerCase().replace(/_/gi, ' ')}`;
 | 
				
			||||||
    sort
 | 
					 | 
				
			||||||
      .slice(1)
 | 
					 | 
				
			||||||
      .toLowerCase()
 | 
					 | 
				
			||||||
      .replace(/_/gi, ' ')}`;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Group = {
 | 
					type Group = {
 | 
				
			||||||
@@ -75,7 +72,7 @@ type Group = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
const DueDateEditorLabel = styled.div`
 | 
					const DueDateEditorLabel = styled.div`
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  font-size: 11px;
 | 
					  font-size: 11px;
 | 
				
			||||||
  padding: 0 8px;
 | 
					  padding: 0 8px;
 | 
				
			||||||
@@ -107,16 +104,16 @@ const ProjectActionWrapper = styled.div<{ disabled?: boolean }>`
 | 
				
			|||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  font-size: 15px;
 | 
					  font-size: 15px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:not(:last-of-type) {
 | 
					  &:not(:last-of-type) {
 | 
				
			||||||
    margin-right: 16px;
 | 
					    margin-right: 16px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    color: ${props => props.theme.colors.text.secondary};
 | 
					    color: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ${props =>
 | 
					  ${(props) =>
 | 
				
			||||||
    props.disabled &&
 | 
					    props.disabled &&
 | 
				
			||||||
    css`
 | 
					    css`
 | 
				
			||||||
      opacity: 0.5;
 | 
					      opacity: 0.5;
 | 
				
			||||||
@@ -150,7 +147,7 @@ const ProjectAction: React.FC<ProjectActionProps> = ({ onClick, disabled = false
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const EditorPositioner = styled.div<{ top: number; left: number }>`
 | 
					const EditorPositioner = styled.div<{ top: number; left: number }>`
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  top: ${p => p.top}px;
 | 
					  top: ${(p) => p.top}px;
 | 
				
			||||||
  justify-content: flex-end;
 | 
					  justify-content: flex-end;
 | 
				
			||||||
  margin-left: -100vw;
 | 
					  margin-left: -100vw;
 | 
				
			||||||
  z-index: 10000;
 | 
					  z-index: 10000;
 | 
				
			||||||
@@ -160,7 +157,7 @@ const EditorPositioner = styled.div<{ top: number; left: number }>`
 | 
				
			|||||||
  height: 0;
 | 
					  height: 0;
 | 
				
			||||||
  position: fixed;
 | 
					  position: fixed;
 | 
				
			||||||
  width: 100vw;
 | 
					  width: 100vw;
 | 
				
			||||||
  left: ${p => p.left}px;
 | 
					  left: ${(p) => p.left}px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EditorPositionerContents = styled.div`
 | 
					const EditorPositionerContents = styled.div`
 | 
				
			||||||
@@ -168,15 +165,15 @@ const EditorPositionerContents = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EditorContainer = styled.div<{ width: number }>`
 | 
					const EditorContainer = styled.div<{ width: number }>`
 | 
				
			||||||
  border: 1px solid ${props => props.theme.colors.primary};
 | 
					  border: 1px solid ${(props) => props.theme.colors.primary};
 | 
				
			||||||
  background: ${props => props.theme.colors.bg.secondary};
 | 
					  background: ${(props) => props.theme.colors.bg.secondary};
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
  width: ${p => p.width}px;
 | 
					  width: ${(p) => p.width}px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EditorCell = styled.div<{ width: number }>`
 | 
					const EditorCell = styled.div<{ width: number }>`
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  width: ${p => p.width}px;
 | 
					  width: ${(p) => p.width}px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TABLE
 | 
					// TABLE
 | 
				
			||||||
@@ -224,7 +221,7 @@ const TaskGroupItems = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectPill = styled.div`
 | 
					const ProjectPill = styled.div`
 | 
				
			||||||
  background-color: ${props => props.theme.colors.bg.primary};
 | 
					  background-color: ${(props) => props.theme.colors.bg.primary};
 | 
				
			||||||
  text-overflow: ellipsis;
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
  border-radius: 10px;
 | 
					  border-radius: 10px;
 | 
				
			||||||
  box-sizing: border-box;
 | 
					  box-sizing: border-box;
 | 
				
			||||||
@@ -250,7 +247,7 @@ const ProjectPillName = styled.span`
 | 
				
			|||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
  text-overflow: ellipsis;
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
  white-space: nowrap;
 | 
					  white-space: nowrap;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectPillColor = styled.svg`
 | 
					const ProjectPillColor = styled.svg`
 | 
				
			||||||
@@ -299,7 +296,7 @@ const OptionTitle = styled.div`
 | 
				
			|||||||
  white-space: nowrap;
 | 
					  white-space: nowrap;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
const OptionSubTitle = styled.div`
 | 
					const OptionSubTitle = styled.div`
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
  font-size: 11px;
 | 
					  font-size: 11px;
 | 
				
			||||||
  margin-left: 8px;
 | 
					  margin-left: 8px;
 | 
				
			||||||
  min-width: 50px;
 | 
					  min-width: 50px;
 | 
				
			||||||
@@ -319,7 +316,7 @@ const Option = ({ innerProps, data }: any) => {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TaskGroupHeaderContents = styled.div<{ width: number }>`
 | 
					const TaskGroupHeaderContents = styled.div<{ width: number }>`
 | 
				
			||||||
  width: ${p => p.width}px;
 | 
					  width: ${(p) => p.width}px;
 | 
				
			||||||
  left: 0;
 | 
					  left: 0;
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
 | 
					  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
 | 
				
			||||||
@@ -356,13 +353,13 @@ const TaskGroupMinify = styled.div`
 | 
				
			|||||||
  transition-property: background, border, box-shadow, fill;
 | 
					  transition-property: background, border, box-shadow, fill;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  svg {
 | 
					  svg {
 | 
				
			||||||
    fill: ${props => props.theme.colors.text.primary};
 | 
					    fill: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
    transition-duration: 0.2s;
 | 
					    transition-duration: 0.2s;
 | 
				
			||||||
    transition-property: background, border, box-shadow, fill;
 | 
					    transition-property: background, border, box-shadow, fill;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover svg {
 | 
					  &:hover svg {
 | 
				
			||||||
    fill: ${props => props.theme.colors.text.secondary};
 | 
					    fill: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
const TaskGroupName = styled.div`
 | 
					const TaskGroupName = styled.div`
 | 
				
			||||||
@@ -371,7 +368,7 @@ const TaskGroupName = styled.div`
 | 
				
			|||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  height: 50px;
 | 
					  height: 50px;
 | 
				
			||||||
  min-width: 1px;
 | 
					  min-width: 1px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.secondary};
 | 
					  color: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
  font-weight: 400;
 | 
					  font-weight: 400;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -393,7 +390,7 @@ const Row = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const RowHeaderLeft = styled.div<{ width: number }>`
 | 
					const RowHeaderLeft = styled.div<{ width: number }>`
 | 
				
			||||||
  width: ${p => p.width}px;
 | 
					  width: ${(p) => p.width}px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  align-items: stretch;
 | 
					  align-items: stretch;
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
@@ -405,7 +402,7 @@ const RowHeaderLeft = styled.div<{ width: number }>`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
const RowHeaderLeftInner = styled.div`
 | 
					const RowHeaderLeftInner = styled.div`
 | 
				
			||||||
  align-items: stretch;
 | 
					  align-items: stretch;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  flex: 1 0 auto;
 | 
					  flex: 1 0 auto;
 | 
				
			||||||
  font-size: 12px;
 | 
					  font-size: 12px;
 | 
				
			||||||
@@ -429,7 +426,7 @@ const RowHeaderLeftNameText = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const RowHeaderRight = styled.div<{ left: number }>`
 | 
					const RowHeaderRight = styled.div<{ left: number }>`
 | 
				
			||||||
  left: ${p => p.left}px;
 | 
					  left: ${(p) => p.left}px;
 | 
				
			||||||
  right: 0px;
 | 
					  right: 0px;
 | 
				
			||||||
  height: 37px;
 | 
					  height: 37px;
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
@@ -461,7 +458,7 @@ const RowHeaderRightContainer = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ItemWrapper = styled.div<{ width: number }>`
 | 
					const ItemWrapper = styled.div<{ width: number }>`
 | 
				
			||||||
  width: ${p => p.width}px;
 | 
					  width: ${(p) => p.width}px;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  border: 1px solid #414561;
 | 
					  border: 1px solid #414561;
 | 
				
			||||||
  border-bottom: 0;
 | 
					  border-bottom: 0;
 | 
				
			||||||
@@ -474,11 +471,11 @@ const ItemWrapper = styled.div<{ width: number }>`
 | 
				
			|||||||
  margin-right: -1px;
 | 
					  margin-right: -1px;
 | 
				
			||||||
  padding: 0 8px;
 | 
					  padding: 0 8px;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
  border-bottom: 1px solid #414561;
 | 
					  border-bottom: 1px solid #414561;
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    background: ${props => props.theme.colors.primary};
 | 
					    background: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
    color: ${props => props.theme.colors.text.secondary};
 | 
					    color: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
const ItemsContainer = styled.div`
 | 
					const ItemsContainer = styled.div`
 | 
				
			||||||
@@ -566,13 +563,13 @@ const Projects = () => {
 | 
				
			|||||||
            onDueDateChange={(task, dueDate, hasTime) => {
 | 
					            onDueDateChange={(task, dueDate, hasTime) => {
 | 
				
			||||||
              if (dateEditor.task) {
 | 
					              if (dateEditor.task) {
 | 
				
			||||||
                updateTaskDueDate({ variables: { taskID: dateEditor.task.id, dueDate, hasTime } });
 | 
					                updateTaskDueDate({ variables: { taskID: dateEditor.task.id, dueDate, hasTime } });
 | 
				
			||||||
                setDateEditor(prev => ({ ...prev, task: { ...task, dueDate: dueDate.toISOString(), hasTime } }));
 | 
					                setDateEditor((prev) => ({ ...prev, task: { ...task, dueDate: dueDate.toISOString(), hasTime } }));
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
            onRemoveDueDate={task => {
 | 
					            onRemoveDueDate={(task) => {
 | 
				
			||||||
              if (dateEditor.task) {
 | 
					              if (dateEditor.task) {
 | 
				
			||||||
                updateTaskDueDate({ variables: { taskID: dateEditor.task.id, dueDate: null, hasTime: false } });
 | 
					                updateTaskDueDate({ variables: { taskID: dateEditor.task.id, dueDate: null, hasTime: false } });
 | 
				
			||||||
                setDateEditor(prev => ({ ...prev, task: { ...task, hasTime: false } }));
 | 
					                setDateEditor((prev) => ({ ...prev, task: { ...task, hasTime: false } }));
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
@@ -587,8 +584,8 @@ const Projects = () => {
 | 
				
			|||||||
      updateApolloCache<MyTasksQuery>(
 | 
					      updateApolloCache<MyTasksQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        MyTasksDocument,
 | 
					        MyTasksDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (newTaskData.data) {
 | 
					            if (newTaskData.data) {
 | 
				
			||||||
              draftCache.myTasks.tasks.unshift(newTaskData.data.createTask);
 | 
					              draftCache.myTasks.tasks.unshift(newTaskData.data.createTask);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -618,7 +615,7 @@ const Projects = () => {
 | 
				
			|||||||
      groups.push({
 | 
					      groups.push({
 | 
				
			||||||
        id: 'recently-assigned',
 | 
					        id: 'recently-assigned',
 | 
				
			||||||
        name: 'Recently Assigned',
 | 
					        name: 'Recently Assigned',
 | 
				
			||||||
        tasks: data.myTasks.tasks.map(task => ({
 | 
					        tasks: data.myTasks.tasks.map((task) => ({
 | 
				
			||||||
          ...task,
 | 
					          ...task,
 | 
				
			||||||
          labels: [],
 | 
					          labels: [],
 | 
				
			||||||
          position: 0,
 | 
					          position: 0,
 | 
				
			||||||
@@ -628,27 +625,27 @@ const Projects = () => {
 | 
				
			|||||||
      let { tasks } = data.myTasks;
 | 
					      let { tasks } = data.myTasks;
 | 
				
			||||||
      if (filters.sort === MyTasksSort.DueDate) {
 | 
					      if (filters.sort === MyTasksSort.DueDate) {
 | 
				
			||||||
        const group: Group = { id: 'due_date', name: null, tasks: [] };
 | 
					        const group: Group = { id: 'due_date', name: null, tasks: [] };
 | 
				
			||||||
        data.myTasks.tasks.forEach(task => {
 | 
					        data.myTasks.tasks.forEach((task) => {
 | 
				
			||||||
          if (task.dueDate) {
 | 
					          if (task.dueDate) {
 | 
				
			||||||
            group.tasks.push({ ...task, labels: [], position: 0 });
 | 
					            group.tasks.push({ ...task, labels: [], position: 0 });
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        groups.push(group);
 | 
					        groups.push(group);
 | 
				
			||||||
        tasks = tasks.filter(t => t.dueDate === null);
 | 
					        tasks = tasks.filter((t) => t.dueDate === null);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      const projects = new Map<string, Array<Task>>();
 | 
					      const projects = new Map<string, Array<Task>>();
 | 
				
			||||||
      data.myTasks.projects.forEach(p => {
 | 
					      data.myTasks.projects.forEach((p) => {
 | 
				
			||||||
        if (!projects.has(p.projectID)) {
 | 
					        if (!projects.has(p.projectID)) {
 | 
				
			||||||
          projects.set(p.projectID, []);
 | 
					          projects.set(p.projectID, []);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const prev = projects.get(p.projectID);
 | 
					        const prev = projects.get(p.projectID);
 | 
				
			||||||
        const task = tasks.find(t => t.id === p.taskID);
 | 
					        const task = tasks.find((t) => t.id === p.taskID);
 | 
				
			||||||
        if (prev && task) {
 | 
					        if (prev && task) {
 | 
				
			||||||
          projects.set(p.projectID, [...prev, { ...task, labels: [], position: 0 }]);
 | 
					          projects.set(p.projectID, [...prev, { ...task, labels: [], position: 0 }]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      for (const [id, pTasks] of projects) {
 | 
					      for (const [id, pTasks] of projects) {
 | 
				
			||||||
        const project = data.projects.find(c => c.id === id);
 | 
					        const project = data.projects.find((c) => c.id === id);
 | 
				
			||||||
        if (pTasks.length === 0) continue;
 | 
					        if (pTasks.length === 0) continue;
 | 
				
			||||||
        if (project) {
 | 
					        if (project) {
 | 
				
			||||||
          groups.push({
 | 
					          groups.push({
 | 
				
			||||||
@@ -681,13 +678,13 @@ const Projects = () => {
 | 
				
			|||||||
          <ProjectActions />
 | 
					          <ProjectActions />
 | 
				
			||||||
          <ProjectActions>
 | 
					          <ProjectActions>
 | 
				
			||||||
            <ProjectAction
 | 
					            <ProjectAction
 | 
				
			||||||
              onClick={$target => {
 | 
					              onClick={($target) => {
 | 
				
			||||||
                showPopup(
 | 
					                showPopup(
 | 
				
			||||||
                  $target,
 | 
					                  $target,
 | 
				
			||||||
                  <MyTasksStatusPopup
 | 
					                  <MyTasksStatusPopup
 | 
				
			||||||
                    status={filters.status}
 | 
					                    status={filters.status}
 | 
				
			||||||
                    onChangeStatus={status => {
 | 
					                    onChangeStatus={(status) => {
 | 
				
			||||||
                      setFilters(prev => ({ ...prev, status }));
 | 
					                      setFilters((prev) => ({ ...prev, status }));
 | 
				
			||||||
                      hidePopup();
 | 
					                      hidePopup();
 | 
				
			||||||
                    }}
 | 
					                    }}
 | 
				
			||||||
                  />,
 | 
					                  />,
 | 
				
			||||||
@@ -699,13 +696,13 @@ const Projects = () => {
 | 
				
			|||||||
              <ProjectActionText>{prettyStatus(filters.status)}</ProjectActionText>
 | 
					              <ProjectActionText>{prettyStatus(filters.status)}</ProjectActionText>
 | 
				
			||||||
            </ProjectAction>
 | 
					            </ProjectAction>
 | 
				
			||||||
            <ProjectAction
 | 
					            <ProjectAction
 | 
				
			||||||
              onClick={$target => {
 | 
					              onClick={($target) => {
 | 
				
			||||||
                showPopup(
 | 
					                showPopup(
 | 
				
			||||||
                  $target,
 | 
					                  $target,
 | 
				
			||||||
                  <MyTasksSortPopup
 | 
					                  <MyTasksSortPopup
 | 
				
			||||||
                    sort={filters.sort}
 | 
					                    sort={filters.sort}
 | 
				
			||||||
                    onChangeSort={sort => {
 | 
					                    onChangeSort={(sort) => {
 | 
				
			||||||
                      setFilters(prev => ({ ...prev, sort }));
 | 
					                      setFilters((prev) => ({ ...prev, sort }));
 | 
				
			||||||
                      hidePopup();
 | 
					                      hidePopup();
 | 
				
			||||||
                    }}
 | 
					                    }}
 | 
				
			||||||
                  />,
 | 
					                  />,
 | 
				
			||||||
@@ -752,8 +749,8 @@ const Projects = () => {
 | 
				
			|||||||
          <VerticalScoller>
 | 
					          <VerticalScoller>
 | 
				
			||||||
            <VerticalScollerInner>
 | 
					            <VerticalScollerInner>
 | 
				
			||||||
              <TableContents>
 | 
					              <TableContents>
 | 
				
			||||||
                {groups.map(group => {
 | 
					                {groups.map((group) => {
 | 
				
			||||||
                  const isMinified = minified.find(m => m === group.id) ?? false;
 | 
					                  const isMinified = minified.find((m) => m === group.id) ?? false;
 | 
				
			||||||
                  return (
 | 
					                  return (
 | 
				
			||||||
                    <TaskGroupContainer key={group.id}>
 | 
					                    <TaskGroupContainer key={group.id}>
 | 
				
			||||||
                      {group.name && (
 | 
					                      {group.name && (
 | 
				
			||||||
@@ -761,9 +758,9 @@ const Projects = () => {
 | 
				
			|||||||
                          <TaskGroupHeaderContents width={leftRow}>
 | 
					                          <TaskGroupHeaderContents width={leftRow}>
 | 
				
			||||||
                            <TaskGroupMinify
 | 
					                            <TaskGroupMinify
 | 
				
			||||||
                              onClick={() => {
 | 
					                              onClick={() => {
 | 
				
			||||||
                                setMinified(prev => {
 | 
					                                setMinified((prev) => {
 | 
				
			||||||
                                  if (isMinified) {
 | 
					                                  if (isMinified) {
 | 
				
			||||||
                                    return prev.filter(c => c !== group.id);
 | 
					                                    return prev.filter((c) => c !== group.id);
 | 
				
			||||||
                                  }
 | 
					                                  }
 | 
				
			||||||
                                  return [...prev, group.id];
 | 
					                                  return [...prev, group.id];
 | 
				
			||||||
                                });
 | 
					                                });
 | 
				
			||||||
@@ -781,14 +778,14 @@ const Projects = () => {
 | 
				
			|||||||
                      )}
 | 
					                      )}
 | 
				
			||||||
                      <TaskGroupItems>
 | 
					                      <TaskGroupItems>
 | 
				
			||||||
                        {!isMinified &&
 | 
					                        {!isMinified &&
 | 
				
			||||||
                          group.tasks.map(task => {
 | 
					                          group.tasks.map((task) => {
 | 
				
			||||||
                            const projectID = data.myTasks.projects.find(t => t.taskID === task.id)?.projectID;
 | 
					                            const projectID = data.myTasks.projects.find((t) => t.taskID === task.id)?.projectID;
 | 
				
			||||||
                            const projectName = data.projects.find(p => p.id === projectID)?.name;
 | 
					                            const projectName = data.projects.find((p) => p.id === projectID)?.name;
 | 
				
			||||||
                            return (
 | 
					                            return (
 | 
				
			||||||
                              <TaskEntry
 | 
					                              <TaskEntry
 | 
				
			||||||
                                key={task.id}
 | 
					                                key={task.id}
 | 
				
			||||||
                                complete={task.complete ?? false}
 | 
					                                complete={task.complete ?? false}
 | 
				
			||||||
                                onToggleComplete={complete => {
 | 
					                                onToggleComplete={(complete) => {
 | 
				
			||||||
                                  setTaskComplete({ variables: { taskID: task.id, complete } });
 | 
					                                  setTaskComplete({ variables: { taskID: task.id, complete } });
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                                onTaskDetails={() => {
 | 
					                                onTaskDetails={() => {
 | 
				
			||||||
@@ -801,9 +798,11 @@ const Projects = () => {
 | 
				
			|||||||
                                dueDate={task.dueDate}
 | 
					                                dueDate={task.dueDate}
 | 
				
			||||||
                                hasTime={task.hasTime ?? false}
 | 
					                                hasTime={task.hasTime ?? false}
 | 
				
			||||||
                                name={task.name}
 | 
					                                name={task.name}
 | 
				
			||||||
                                onEditName={name => updateTaskName({ variables: { taskID: task.id, name } })}
 | 
					                                onEditName={(name) => updateTaskName({ variables: { taskID: task.id, name } })}
 | 
				
			||||||
                                onEditProject={onEditProject}
 | 
					                                onEditProject={onEditProject}
 | 
				
			||||||
                                onEditDueDate={$target => onEditDueDate({ ...task, position: 0, labels: [] }, $target)}
 | 
					                                onEditDueDate={($target) =>
 | 
				
			||||||
 | 
					                                  onEditDueDate({ ...task, position: 0, labels: [] }, $target)
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
                              />
 | 
					                              />
 | 
				
			||||||
                            );
 | 
					                            );
 | 
				
			||||||
                          })}
 | 
					                          })}
 | 
				
			||||||
@@ -856,17 +855,17 @@ const Projects = () => {
 | 
				
			|||||||
        )}
 | 
					        )}
 | 
				
			||||||
        <Route
 | 
					        <Route
 | 
				
			||||||
          path={`${match.path}/c/:taskID`}
 | 
					          path={`${match.path}/c/:taskID`}
 | 
				
			||||||
          render={(routeProps: RouteComponentProps<TaskRouteProps>) => (
 | 
					          render={() => {
 | 
				
			||||||
            <Details
 | 
					            return (
 | 
				
			||||||
              refreshCache={NOOP}
 | 
					              <Details
 | 
				
			||||||
              availableMembers={[]}
 | 
					                refreshCache={NOOP}
 | 
				
			||||||
              projectURL={`${match.url}`}
 | 
					                availableMembers={[]}
 | 
				
			||||||
              taskID={routeProps.match.params.taskID}
 | 
					                projectURL={`${match.url}`}
 | 
				
			||||||
              onTaskNameChange={(updatedTask, newName) => {
 | 
					                onTaskNameChange={(updatedTask, newName) => {
 | 
				
			||||||
                updateTaskName({ variables: { taskID: updatedTask.id, name: newName } });
 | 
					                  updateTaskName({ variables: { taskID: updatedTask.id, name: newName } });
 | 
				
			||||||
              }}
 | 
					                }}
 | 
				
			||||||
              onTaskDescriptionChange={(updatedTask, newDescription) => {
 | 
					                onTaskDescriptionChange={(updatedTask, newDescription) => {
 | 
				
			||||||
                /*
 | 
					                  /*
 | 
				
			||||||
                updateTaskDescription({
 | 
					                updateTaskDescription({
 | 
				
			||||||
                  variables: { taskID: updatedTask.id, description: newDescription },
 | 
					                  variables: { taskID: updatedTask.id, description: newDescription },
 | 
				
			||||||
                  optimisticResponse: {
 | 
					                  optimisticResponse: {
 | 
				
			||||||
@@ -879,13 +878,13 @@ const Projects = () => {
 | 
				
			|||||||
                  },
 | 
					                  },
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                */
 | 
					                */
 | 
				
			||||||
              }}
 | 
					                }}
 | 
				
			||||||
              onDeleteTask={deletedTask => {
 | 
					                onDeleteTask={(deletedTask) => {
 | 
				
			||||||
                // deleteTask({ variables: { taskID: deletedTask.id } });
 | 
					                  // deleteTask({ variables: { taskID: deletedTask.id } });
 | 
				
			||||||
                history.push(`${match.url}`);
 | 
					                  history.push(`${match.url}`);
 | 
				
			||||||
              }}
 | 
					                }}
 | 
				
			||||||
              onOpenAddLabelPopup={(task, $targetRef) => {
 | 
					                onOpenAddLabelPopup={(task, $targetRef) => {
 | 
				
			||||||
                /*
 | 
					                  /*
 | 
				
			||||||
                taskLabelsRef.current = task.labels;
 | 
					                taskLabelsRef.current = task.labels;
 | 
				
			||||||
                showPopup(
 | 
					                showPopup(
 | 
				
			||||||
                  $targetRef,
 | 
					                  $targetRef,
 | 
				
			||||||
@@ -900,9 +899,10 @@ const Projects = () => {
 | 
				
			|||||||
                  />,
 | 
					                  />,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                */
 | 
					                */
 | 
				
			||||||
              }}
 | 
					                }}
 | 
				
			||||||
            />
 | 
					              />
 | 
				
			||||||
          )}
 | 
					            );
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </>
 | 
					      </>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import TaskDetails from 'shared/components/TaskDetails';
 | 
				
			|||||||
import TaskDetailsLoading from 'shared/components/TaskDetails/Loading';
 | 
					import TaskDetailsLoading from 'shared/components/TaskDetails/Loading';
 | 
				
			||||||
import { Popup, usePopup } from 'shared/components/PopupMenu';
 | 
					import { Popup, usePopup } from 'shared/components/PopupMenu';
 | 
				
			||||||
import MemberManager from 'shared/components/MemberManager';
 | 
					import MemberManager from 'shared/components/MemberManager';
 | 
				
			||||||
import { useRouteMatch, useHistory } from 'react-router';
 | 
					import { useRouteMatch, useHistory, useParams } from 'react-router';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  useDeleteTaskChecklistMutation,
 | 
					  useDeleteTaskChecklistMutation,
 | 
				
			||||||
  useUpdateTaskChecklistNameMutation,
 | 
					  useUpdateTaskChecklistNameMutation,
 | 
				
			||||||
@@ -56,7 +56,7 @@ export const ActionItem = styled.li`
 | 
				
			|||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 14px;
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    background: ${props => props.theme.colors.primary};
 | 
					    background: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,10 +166,8 @@ const CreateChecklistPopup: React.FC<CreateChecklistPopupProps> = ({ onCreateChe
 | 
				
			|||||||
        defaultValue="Checklist"
 | 
					        defaultValue="Checklist"
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        label="Name"
 | 
					        label="Name"
 | 
				
			||||||
        id="name"
 | 
					 | 
				
			||||||
        name="name"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					        variant="alternate"
 | 
				
			||||||
        ref={register({ required: 'Checklist name is required' })}
 | 
					        {...register('name', { required: 'Checklist name is required' })}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <CreateChecklistButton type="submit">Create</CreateChecklistButton>
 | 
					      <CreateChecklistButton type="submit">Create</CreateChecklistButton>
 | 
				
			||||||
    </CreateChecklistForm>
 | 
					    </CreateChecklistForm>
 | 
				
			||||||
@@ -177,7 +175,6 @@ const CreateChecklistPopup: React.FC<CreateChecklistPopupProps> = ({ onCreateChe
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DetailsProps = {
 | 
					type DetailsProps = {
 | 
				
			||||||
  taskID: string;
 | 
					 | 
				
			||||||
  projectURL: string;
 | 
					  projectURL: string;
 | 
				
			||||||
  onTaskNameChange: (task: Task, newName: string) => void;
 | 
					  onTaskNameChange: (task: Task, newName: string) => void;
 | 
				
			||||||
  onTaskDescriptionChange: (task: Task, newDescription: string) => void;
 | 
					  onTaskDescriptionChange: (task: Task, newDescription: string) => void;
 | 
				
			||||||
@@ -191,7 +188,6 @@ const initialMemberPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const Details: React.FC<DetailsProps> = ({
 | 
					const Details: React.FC<DetailsProps> = ({
 | 
				
			||||||
  projectURL,
 | 
					  projectURL,
 | 
				
			||||||
  taskID,
 | 
					 | 
				
			||||||
  onTaskNameChange,
 | 
					  onTaskNameChange,
 | 
				
			||||||
  onTaskDescriptionChange,
 | 
					  onTaskDescriptionChange,
 | 
				
			||||||
  onDeleteTask,
 | 
					  onDeleteTask,
 | 
				
			||||||
@@ -200,6 +196,7 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
  refreshCache,
 | 
					  refreshCache,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
  const { user } = useCurrentUser();
 | 
					  const { user } = useCurrentUser();
 | 
				
			||||||
 | 
					  const { taskID } = useParams<{ taskID: string }>();
 | 
				
			||||||
  const { showPopup, hidePopup } = usePopup();
 | 
					  const { showPopup, hidePopup } = usePopup();
 | 
				
			||||||
  const history = useHistory();
 | 
					  const history = useHistory();
 | 
				
			||||||
  const [deleteTaskComment] = useDeleteTaskCommentMutation({
 | 
					  const [deleteTaskComment] = useDeleteTaskCommentMutation({
 | 
				
			||||||
@@ -207,11 +204,11 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (response.data) {
 | 
					            if (response.data) {
 | 
				
			||||||
              draftCache.findTask.comments = cache.findTask.comments.filter(
 | 
					              draftCache.findTask.comments = cache.findTask.comments.filter(
 | 
				
			||||||
                c => c.id !== response.data?.deleteTaskComment.commentID,
 | 
					                (c) => c.id !== response.data?.deleteTaskComment.commentID,
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
@@ -224,8 +221,8 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (response.data) {
 | 
					            if (response.data) {
 | 
				
			||||||
              draftCache.findTask.comments.push({
 | 
					              draftCache.findTask.comments.push({
 | 
				
			||||||
                ...response.data.createTaskComment.comment,
 | 
					                ...response.data.createTaskComment.comment,
 | 
				
			||||||
@@ -242,18 +239,18 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (response.data) {
 | 
					            if (response.data) {
 | 
				
			||||||
              const { prevChecklistID, taskChecklistID, checklistItem } = response.data.updateTaskChecklistItemLocation;
 | 
					              const { prevChecklistID, taskChecklistID, checklistItem } = response.data.updateTaskChecklistItemLocation;
 | 
				
			||||||
              if (taskChecklistID !== prevChecklistID) {
 | 
					              if (taskChecklistID !== prevChecklistID) {
 | 
				
			||||||
                const oldIdx = cache.findTask.checklists.findIndex(c => c.id === prevChecklistID);
 | 
					                const oldIdx = cache.findTask.checklists.findIndex((c) => c.id === prevChecklistID);
 | 
				
			||||||
                const newIdx = cache.findTask.checklists.findIndex(c => c.id === taskChecklistID);
 | 
					                const newIdx = cache.findTask.checklists.findIndex((c) => c.id === taskChecklistID);
 | 
				
			||||||
                if (oldIdx > -1 && newIdx > -1) {
 | 
					                if (oldIdx > -1 && newIdx > -1) {
 | 
				
			||||||
                  const item = cache.findTask.checklists[oldIdx].items.find(i => i.id === checklistItem.id);
 | 
					                  const item = cache.findTask.checklists[oldIdx].items.find((i) => i.id === checklistItem.id);
 | 
				
			||||||
                  if (item) {
 | 
					                  if (item) {
 | 
				
			||||||
                    draftCache.findTask.checklists[oldIdx].items = cache.findTask.checklists[oldIdx].items.filter(
 | 
					                    draftCache.findTask.checklists[oldIdx].items = cache.findTask.checklists[oldIdx].items.filter(
 | 
				
			||||||
                      i => i.id !== checklistItem.id,
 | 
					                      (i) => i.id !== checklistItem.id,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    draftCache.findTask.checklists[newIdx].items.push({
 | 
					                    draftCache.findTask.checklists[newIdx].items.push({
 | 
				
			||||||
                      ...item,
 | 
					                      ...item,
 | 
				
			||||||
@@ -270,12 +267,12 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const [setTaskChecklistItemComplete] = useSetTaskChecklistItemCompleteMutation({
 | 
					  const [setTaskChecklistItemComplete] = useSetTaskChecklistItemCompleteMutation({
 | 
				
			||||||
    update: client => {
 | 
					    update: (client) => {
 | 
				
			||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
					            const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
				
			||||||
            draftCache.findTask.badges.checklist = {
 | 
					            draftCache.findTask.badges.checklist = {
 | 
				
			||||||
              __typename: 'ChecklistBadge',
 | 
					              __typename: 'ChecklistBadge',
 | 
				
			||||||
@@ -292,11 +289,11 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            const { checklists } = cache.findTask;
 | 
					            const { checklists } = cache.findTask;
 | 
				
			||||||
            draftCache.findTask.checklists = checklists.filter(
 | 
					            draftCache.findTask.checklists = checklists.filter(
 | 
				
			||||||
              c => c.id !== deleteData.data?.deleteTaskChecklist.taskChecklist.id,
 | 
					              (c) => c.id !== deleteData.data?.deleteTaskChecklist.taskChecklist.id,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
					            const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
				
			||||||
            draftCache.findTask.badges.checklist = {
 | 
					            draftCache.findTask.badges.checklist = {
 | 
				
			||||||
@@ -318,8 +315,8 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (createData.data) {
 | 
					            if (createData.data) {
 | 
				
			||||||
              const item = createData.data.createTaskChecklist;
 | 
					              const item = createData.data.createTaskChecklist;
 | 
				
			||||||
              draftCache.findTask.checklists.push({ ...item });
 | 
					              draftCache.findTask.checklists.push({ ...item });
 | 
				
			||||||
@@ -335,14 +332,14 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (deleteData.data) {
 | 
					            if (deleteData.data) {
 | 
				
			||||||
              const item = deleteData.data.deleteTaskChecklistItem.taskChecklistItem;
 | 
					              const item = deleteData.data.deleteTaskChecklistItem.taskChecklistItem;
 | 
				
			||||||
              const targetIdx = cache.findTask.checklists.findIndex(c => c.id === item.taskChecklistID);
 | 
					              const targetIdx = cache.findTask.checklists.findIndex((c) => c.id === item.taskChecklistID);
 | 
				
			||||||
              if (targetIdx > -1) {
 | 
					              if (targetIdx > -1) {
 | 
				
			||||||
                draftCache.findTask.checklists[targetIdx].items = cache.findTask.checklists[targetIdx].items.filter(
 | 
					                draftCache.findTask.checklists[targetIdx].items = cache.findTask.checklists[targetIdx].items.filter(
 | 
				
			||||||
                  c => item.id !== c.id,
 | 
					                  (c) => item.id !== c.id,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
					              const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
				
			||||||
@@ -362,12 +359,12 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      updateApolloCache<FindTaskQuery>(
 | 
					      updateApolloCache<FindTaskQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindTaskDocument,
 | 
					        FindTaskDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (newTaskItem.data) {
 | 
					            if (newTaskItem.data) {
 | 
				
			||||||
              const item = newTaskItem.data.createTaskChecklistItem;
 | 
					              const item = newTaskItem.data.createTaskChecklistItem;
 | 
				
			||||||
              const { checklists } = cache.findTask;
 | 
					              const { checklists } = cache.findTask;
 | 
				
			||||||
              const idx = checklists.findIndex(c => c.id === item.taskChecklistID);
 | 
					              const idx = checklists.findIndex((c) => c.id === item.taskChecklistID);
 | 
				
			||||||
              if (idx !== -1) {
 | 
					              if (idx !== -1) {
 | 
				
			||||||
                draftCache.findTask.checklists[idx].items.push({ ...item });
 | 
					                draftCache.findTask.checklists[idx].items.push({ ...item });
 | 
				
			||||||
                const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
					                const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists);
 | 
				
			||||||
@@ -445,7 +442,7 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
              onCreateComment={(task, message) => {
 | 
					              onCreateComment={(task, message) => {
 | 
				
			||||||
                createTaskComment({ variables: { taskID: task.id, message } });
 | 
					                createTaskComment({ variables: { taskID: task.id, message } });
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onChecklistDrop={checklist => {
 | 
					              onChecklistDrop={(checklist) => {
 | 
				
			||||||
                updateTaskChecklistLocation({
 | 
					                updateTaskChecklistLocation({
 | 
				
			||||||
                  variables: { taskChecklistID: checklist.id, position: checklist.position },
 | 
					                  variables: { taskChecklistID: checklist.id, position: checklist.position },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -487,7 +484,7 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onTaskNameChange={onTaskNameChange}
 | 
					              onTaskNameChange={onTaskNameChange}
 | 
				
			||||||
              onTaskDescriptionChange={onTaskDescriptionChange}
 | 
					              onTaskDescriptionChange={onTaskDescriptionChange}
 | 
				
			||||||
              onToggleTaskComplete={task => {
 | 
					              onToggleTaskComplete={(task) => {
 | 
				
			||||||
                setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } });
 | 
					                setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } });
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onDeleteTask={onDeleteTask}
 | 
					              onDeleteTask={onDeleteTask}
 | 
				
			||||||
@@ -532,7 +529,7 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
                createTaskChecklistItem({ variables: { taskChecklistID, name, position } });
 | 
					                createTaskChecklistItem({ variables: { taskChecklistID, name, position } });
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onMemberProfile={($targetRef, memberID) => {
 | 
					              onMemberProfile={($targetRef, memberID) => {
 | 
				
			||||||
                const member = data.findTask.assigned.find(m => m.id === memberID);
 | 
					                const member = data.findTask.assigned.find((m) => m.id === memberID);
 | 
				
			||||||
                if (member) {
 | 
					                if (member) {
 | 
				
			||||||
                  showPopup(
 | 
					                  showPopup(
 | 
				
			||||||
                    $targetRef,
 | 
					                    $targetRef,
 | 
				
			||||||
@@ -582,7 +579,7 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
                    }}
 | 
					                    }}
 | 
				
			||||||
                  >
 | 
					                  >
 | 
				
			||||||
                    <CreateChecklistPopup
 | 
					                    <CreateChecklistPopup
 | 
				
			||||||
                      onCreateChecklist={checklistData => {
 | 
					                      onCreateChecklist={(checklistData) => {
 | 
				
			||||||
                        let position = 65535;
 | 
					                        let position = 65535;
 | 
				
			||||||
                        if (data.findTask.checklists) {
 | 
					                        if (data.findTask.checklists) {
 | 
				
			||||||
                          const [lastChecklist] = data.findTask.checklists.slice(-1);
 | 
					                          const [lastChecklist] = data.findTask.checklists.slice(-1);
 | 
				
			||||||
@@ -632,7 +629,7 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
                  >
 | 
					                  >
 | 
				
			||||||
                    <DueDateManager
 | 
					                    <DueDateManager
 | 
				
			||||||
                      task={task}
 | 
					                      task={task}
 | 
				
			||||||
                      onRemoveDueDate={t => {
 | 
					                      onRemoveDueDate={(t) => {
 | 
				
			||||||
                        updateTaskDueDate({ variables: { taskID: t.id, dueDate: null, hasTime: false } });
 | 
					                        updateTaskDueDate({ variables: { taskID: t.id, dueDate: null, hasTime: false } });
 | 
				
			||||||
                        // hidePopup();
 | 
					                        // hidePopup();
 | 
				
			||||||
                      }}
 | 
					                      }}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,7 +64,7 @@ const Project = () => {
 | 
				
			|||||||
    pollInterval: polling.PROJECT,
 | 
					    pollInterval: polling.PROJECT,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const [toggleTaskLabel] = useToggleTaskLabelMutation({
 | 
					  const [toggleTaskLabel] = useToggleTaskLabelMutation({
 | 
				
			||||||
    onCompleted: newTaskLabel => {
 | 
					    onCompleted: (newTaskLabel) => {
 | 
				
			||||||
      taskLabelsRef.current = newTaskLabel.toggleTaskLabel.task.labels;
 | 
					      taskLabelsRef.current = newTaskLabel.toggleTaskLabel.task.labels;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@@ -73,17 +73,17 @@ const Project = () => {
 | 
				
			|||||||
      updateApolloCache<FindProjectQuery>(
 | 
					      updateApolloCache<FindProjectQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindProjectDocument,
 | 
					        FindProjectDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (resp.data) {
 | 
					            if (resp.data) {
 | 
				
			||||||
              const taskGroupIdx = draftCache.findProject.taskGroups.findIndex(
 | 
					              const taskGroupIdx = draftCache.findProject.taskGroups.findIndex(
 | 
				
			||||||
                tg => tg.tasks.findIndex(t => t.id === resp.data?.deleteTask.taskID) !== -1,
 | 
					                (tg) => tg.tasks.findIndex((t) => t.id === resp.data?.deleteTask.taskID) !== -1,
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              if (taskGroupIdx !== -1) {
 | 
					              if (taskGroupIdx !== -1) {
 | 
				
			||||||
                draftCache.findProject.taskGroups[taskGroupIdx].tasks = cache.findProject.taskGroups[
 | 
					                draftCache.findProject.taskGroups[taskGroupIdx].tasks = cache.findProject.taskGroups[
 | 
				
			||||||
                  taskGroupIdx
 | 
					                  taskGroupIdx
 | 
				
			||||||
                ].tasks.filter(t => t.id !== resp.data?.deleteTask.taskID);
 | 
					                ].tasks.filter((t) => t.id !== resp.data?.deleteTask.taskID);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
@@ -96,8 +96,8 @@ const Project = () => {
 | 
				
			|||||||
      updateApolloCache<FindProjectQuery>(
 | 
					      updateApolloCache<FindProjectQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindProjectDocument,
 | 
					        FindProjectDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            draftCache.findProject.name = newName.data?.updateProjectName.name ?? '';
 | 
					            draftCache.findProject.name = newName.data?.updateProjectName.name ?? '';
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
        { projectID },
 | 
					        { projectID },
 | 
				
			||||||
@@ -110,8 +110,8 @@ const Project = () => {
 | 
				
			|||||||
      updateApolloCache<FindProjectQuery>(
 | 
					      updateApolloCache<FindProjectQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindProjectDocument,
 | 
					        FindProjectDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (response.data) {
 | 
					            if (response.data) {
 | 
				
			||||||
              draftCache.findProject.members = [
 | 
					              draftCache.findProject.members = [
 | 
				
			||||||
                ...cache.findProject.members,
 | 
					                ...cache.findProject.members,
 | 
				
			||||||
@@ -132,10 +132,10 @@ const Project = () => {
 | 
				
			|||||||
      updateApolloCache<FindProjectQuery>(
 | 
					      updateApolloCache<FindProjectQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindProjectDocument,
 | 
					        FindProjectDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            draftCache.findProject.invitedMembers = cache.findProject.invitedMembers.filter(
 | 
					            draftCache.findProject.invitedMembers = cache.findProject.invitedMembers.filter(
 | 
				
			||||||
              m => m.email !== response.data?.deleteInvitedProjectMember.invitedMember.email ?? '',
 | 
					              (m) => m.email !== response.data?.deleteInvitedProjectMember.invitedMember.email ?? '',
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
        { projectID },
 | 
					        { projectID },
 | 
				
			||||||
@@ -147,10 +147,10 @@ const Project = () => {
 | 
				
			|||||||
      updateApolloCache<FindProjectQuery>(
 | 
					      updateApolloCache<FindProjectQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        FindProjectDocument,
 | 
					        FindProjectDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            draftCache.findProject.members = cache.findProject.members.filter(
 | 
					            draftCache.findProject.members = cache.findProject.members.filter(
 | 
				
			||||||
              m => m.id !== response.data?.deleteProjectMember.member.id,
 | 
					              (m) => m.id !== response.data?.deleteProjectMember.member.id,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
        { projectID },
 | 
					        { projectID },
 | 
				
			||||||
@@ -176,23 +176,23 @@ const Project = () => {
 | 
				
			|||||||
          onChangeProjectOwner={() => {
 | 
					          onChangeProjectOwner={() => {
 | 
				
			||||||
            hidePopup();
 | 
					            hidePopup();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onRemoveFromBoard={userID => {
 | 
					          onRemoveFromBoard={(userID) => {
 | 
				
			||||||
            deleteProjectMember({ variables: { userID, projectID } });
 | 
					            deleteProjectMember({ variables: { userID, projectID } });
 | 
				
			||||||
            hidePopup();
 | 
					            hidePopup();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onRemoveInvitedFromBoard={email => {
 | 
					          onRemoveInvitedFromBoard={(email) => {
 | 
				
			||||||
            deleteInvitedProjectMember({ variables: { projectID, email } });
 | 
					            deleteInvitedProjectMember({ variables: { projectID, email } });
 | 
				
			||||||
            hidePopup();
 | 
					            hidePopup();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onSaveProjectName={projectName => {
 | 
					          onSaveProjectName={(projectName) => {
 | 
				
			||||||
            updateProjectName({ variables: { projectID, name: projectName } });
 | 
					            updateProjectName({ variables: { projectID, name: projectName } });
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onInviteUser={$target => {
 | 
					          onInviteUser={($target) => {
 | 
				
			||||||
            showPopup(
 | 
					            showPopup(
 | 
				
			||||||
              $target,
 | 
					              $target,
 | 
				
			||||||
              <UserManagementPopup
 | 
					              <UserManagementPopup
 | 
				
			||||||
                projectID={projectID}
 | 
					                projectID={projectID}
 | 
				
			||||||
                onInviteProjectMembers={members => {
 | 
					                onInviteProjectMembers={(members) => {
 | 
				
			||||||
                  inviteProjectMembers({ variables: { projectID, members } });
 | 
					                  inviteProjectMembers({ variables: { projectID, members } });
 | 
				
			||||||
                  hidePopup();
 | 
					                  hidePopup();
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
@@ -233,50 +233,51 @@ const Project = () => {
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
        <Route
 | 
					        <Route
 | 
				
			||||||
          path={`${match.path}/board/c/:taskID`}
 | 
					          path={`${match.path}/board/c/:taskID`}
 | 
				
			||||||
          render={(routeProps: RouteComponentProps<TaskRouteProps>) => (
 | 
					          render={() => {
 | 
				
			||||||
            <Details
 | 
					            return (
 | 
				
			||||||
              refreshCache={NOOP}
 | 
					              <Details
 | 
				
			||||||
              availableMembers={data.findProject.members}
 | 
					                refreshCache={NOOP}
 | 
				
			||||||
              projectURL={`${match.url}/board`}
 | 
					                availableMembers={data.findProject.members}
 | 
				
			||||||
              taskID={routeProps.match.params.taskID}
 | 
					                projectURL={`${match.url}/board`}
 | 
				
			||||||
              onTaskNameChange={(updatedTask, newName) => {
 | 
					                onTaskNameChange={(updatedTask, newName) => {
 | 
				
			||||||
                updateTaskName({ variables: { taskID: updatedTask.id, name: newName } });
 | 
					                  updateTaskName({ variables: { taskID: updatedTask.id, name: newName } });
 | 
				
			||||||
              }}
 | 
					                }}
 | 
				
			||||||
              onTaskDescriptionChange={(updatedTask, newDescription) => {
 | 
					                onTaskDescriptionChange={(updatedTask, newDescription) => {
 | 
				
			||||||
                updateTaskDescription({
 | 
					                  updateTaskDescription({
 | 
				
			||||||
                  variables: { taskID: updatedTask.id, description: newDescription },
 | 
					                    variables: { taskID: updatedTask.id, description: newDescription },
 | 
				
			||||||
                  optimisticResponse: {
 | 
					                    optimisticResponse: {
 | 
				
			||||||
                    __typename: 'Mutation',
 | 
					                      __typename: 'Mutation',
 | 
				
			||||||
                    updateTaskDescription: {
 | 
					                      updateTaskDescription: {
 | 
				
			||||||
                      __typename: 'Task',
 | 
					                        __typename: 'Task',
 | 
				
			||||||
                      id: updatedTask.id,
 | 
					                        id: updatedTask.id,
 | 
				
			||||||
                      description: newDescription,
 | 
					                        description: newDescription,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                  },
 | 
					                  });
 | 
				
			||||||
                });
 | 
					                }}
 | 
				
			||||||
              }}
 | 
					                onDeleteTask={(deletedTask) => {
 | 
				
			||||||
              onDeleteTask={deletedTask => {
 | 
					                  deleteTask({ variables: { taskID: deletedTask.id } });
 | 
				
			||||||
                deleteTask({ variables: { taskID: deletedTask.id } });
 | 
					                  history.push(`${match.url}/board`);
 | 
				
			||||||
                history.push(`${match.url}/board`);
 | 
					                }}
 | 
				
			||||||
              }}
 | 
					                onOpenAddLabelPopup={(task, $targetRef) => {
 | 
				
			||||||
              onOpenAddLabelPopup={(task, $targetRef) => {
 | 
					                  taskLabelsRef.current = task.labels;
 | 
				
			||||||
                taskLabelsRef.current = task.labels;
 | 
					                  showPopup(
 | 
				
			||||||
                showPopup(
 | 
					                    $targetRef,
 | 
				
			||||||
                  $targetRef,
 | 
					                    <LabelManagerEditor
 | 
				
			||||||
                  <LabelManagerEditor
 | 
					                      onLabelToggle={(labelID) => {
 | 
				
			||||||
                    onLabelToggle={labelID => {
 | 
					                        toggleTaskLabel({ variables: { taskID: task.id, projectLabelID: labelID } });
 | 
				
			||||||
                      toggleTaskLabel({ variables: { taskID: task.id, projectLabelID: labelID } });
 | 
					                      }}
 | 
				
			||||||
                    }}
 | 
					                      taskID={task.id}
 | 
				
			||||||
                    taskID={task.id}
 | 
					                      labelColors={data.labelColors}
 | 
				
			||||||
                    labelColors={data.labelColors}
 | 
					                      labels={labelsRef}
 | 
				
			||||||
                    labels={labelsRef}
 | 
					                      taskLabels={taskLabelsRef}
 | 
				
			||||||
                    taskLabels={taskLabelsRef}
 | 
					                      projectID={projectID}
 | 
				
			||||||
                    projectID={projectID}
 | 
					                    />,
 | 
				
			||||||
                  />,
 | 
					                  );
 | 
				
			||||||
                );
 | 
					                }}
 | 
				
			||||||
              }}
 | 
					              />
 | 
				
			||||||
            />
 | 
					            );
 | 
				
			||||||
          )}
 | 
					          }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </>
 | 
					      </>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,15 +16,15 @@ import { useCurrentUser } from 'App/context';
 | 
				
			|||||||
import Button from 'shared/components/Button';
 | 
					import Button from 'shared/components/Button';
 | 
				
			||||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
 | 
					import { usePopup, Popup } from 'shared/components/PopupMenu';
 | 
				
			||||||
import { useForm } from 'react-hook-form';
 | 
					import { useForm } from 'react-hook-form';
 | 
				
			||||||
import Input from 'shared/components/Input';
 | 
					import ControlledInput from 'shared/components/ControlledInput';
 | 
				
			||||||
import updateApolloCache from 'shared/utils/cache';
 | 
					import updateApolloCache from 'shared/utils/cache';
 | 
				
			||||||
import produce from 'immer';
 | 
					import produce from 'immer';
 | 
				
			||||||
import NOOP from 'shared/utils/noop';
 | 
					import NOOP from 'shared/utils/noop';
 | 
				
			||||||
import theme from 'App/ThemeStyles';
 | 
					import theme from 'App/ThemeStyles';
 | 
				
			||||||
import { mixin } from '../shared/utils/styles';
 | 
					 | 
				
			||||||
import polling from 'shared/utils/polling';
 | 
					import polling from 'shared/utils/polling';
 | 
				
			||||||
 | 
					import { mixin } from '../shared/utils/styles';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CreateTeamData = { teamName: string };
 | 
					type CreateTeamData = { name: string };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CreateTeamFormProps = {
 | 
					type CreateTeamFormProps = {
 | 
				
			||||||
  onCreateTeam: (teamName: string) => void;
 | 
					  onCreateTeam: (teamName: string) => void;
 | 
				
			||||||
@@ -36,28 +36,30 @@ const CreateTeamButton = styled(Button)`
 | 
				
			|||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ErrorText = styled.span`
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  color: ${(props) => props.theme.colors.danger};
 | 
				
			||||||
 | 
					`;
 | 
				
			||||||
const CreateTeamForm: React.FC<CreateTeamFormProps> = ({ onCreateTeam }) => {
 | 
					const CreateTeamForm: React.FC<CreateTeamFormProps> = ({ onCreateTeam }) => {
 | 
				
			||||||
  const { register, handleSubmit } = useForm<CreateTeamData>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					  } = useForm<CreateTeamData>();
 | 
				
			||||||
  const createTeam = (data: CreateTeamData) => {
 | 
					  const createTeam = (data: CreateTeamData) => {
 | 
				
			||||||
    onCreateTeam(data.teamName);
 | 
					    onCreateTeam(data.name);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <CreateTeamFormContainer onSubmit={handleSubmit(createTeam)}>
 | 
					    <CreateTeamFormContainer onSubmit={handleSubmit(createTeam)}>
 | 
				
			||||||
      <Input
 | 
					      {errors.name && <ErrorText>{errors.name.message}</ErrorText>}
 | 
				
			||||||
        width="100%"
 | 
					      <ControlledInput width="100%" label="Team name" variant="alternate" {...register('name')} />
 | 
				
			||||||
        label="Team name"
 | 
					 | 
				
			||||||
        id="teamName"
 | 
					 | 
				
			||||||
        name="teamName"
 | 
					 | 
				
			||||||
        variant="alternate"
 | 
					 | 
				
			||||||
        ref={register({ required: 'Team name is required' })}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <CreateTeamButton type="submit">Create</CreateTeamButton>
 | 
					      <CreateTeamButton type="submit">Create</CreateTeamButton>
 | 
				
			||||||
    </CreateTeamFormContainer>
 | 
					    </CreateTeamFormContainer>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectAddTile = styled.div`
 | 
					const ProjectAddTile = styled.div`
 | 
				
			||||||
  background-color: ${props => mixin.rgba(props.theme.colors.bg.primary, 0.4)};
 | 
					  background-color: ${(props) => mixin.rgba(props.theme.colors.bg.primary, 0.4)};
 | 
				
			||||||
  background-size: cover;
 | 
					  background-size: cover;
 | 
				
			||||||
  background-position: 50%;
 | 
					  background-position: 50%;
 | 
				
			||||||
  color: #fff;
 | 
					  color: #fff;
 | 
				
			||||||
@@ -71,7 +73,7 @@ const ProjectAddTile = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectTile = styled(Link)<{ color: string }>`
 | 
					const ProjectTile = styled(Link)<{ color: string }>`
 | 
				
			||||||
  background-color: ${props => props.color};
 | 
					  background-color: ${(props) => props.color};
 | 
				
			||||||
  background-size: cover;
 | 
					  background-size: cover;
 | 
				
			||||||
  background-position: 50%;
 | 
					  background-position: 50%;
 | 
				
			||||||
  color: #fff;
 | 
					  color: #fff;
 | 
				
			||||||
@@ -142,7 +144,7 @@ const ProjectTileName = styled.div<{ centered?: boolean }>`
 | 
				
			|||||||
  max-height: 40px;
 | 
					  max-height: 40px;
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  word-wrap: break-word;
 | 
					  word-wrap: break-word;
 | 
				
			||||||
  ${props => props.centered && 'text-align: center;'}
 | 
					  ${(props) => props.centered && 'text-align: center;'}
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Wrapper = styled.div`
 | 
					const Wrapper = styled.div`
 | 
				
			||||||
@@ -180,7 +182,7 @@ const SectionActionLink = styled(Link)`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const ProjectSectionTitle = styled.h3`
 | 
					const ProjectSectionTitle = styled.h3`
 | 
				
			||||||
  font-size: 16px;
 | 
					  font-size: 16px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectsContainer = styled.div`
 | 
					const ProjectsContainer = styled.div`
 | 
				
			||||||
@@ -210,8 +212,8 @@ const Projects = () => {
 | 
				
			|||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
  const [createProject] = useCreateProjectMutation({
 | 
					  const [createProject] = useCreateProjectMutation({
 | 
				
			||||||
    update: (client, newProject) => {
 | 
					    update: (client, newProject) => {
 | 
				
			||||||
      updateApolloCache<GetProjectsQuery>(client, GetProjectsDocument, cache =>
 | 
					      updateApolloCache<GetProjectsQuery>(client, GetProjectsDocument, (cache) =>
 | 
				
			||||||
        produce(cache, draftCache => {
 | 
					        produce(cache, (draftCache) => {
 | 
				
			||||||
          if (newProject.data) {
 | 
					          if (newProject.data) {
 | 
				
			||||||
            draftCache.projects.push({ ...newProject.data.createProject });
 | 
					            draftCache.projects.push({ ...newProject.data.createProject });
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@@ -224,8 +226,8 @@ const Projects = () => {
 | 
				
			|||||||
  const { user } = useCurrentUser();
 | 
					  const { user } = useCurrentUser();
 | 
				
			||||||
  const [createTeam] = useCreateTeamMutation({
 | 
					  const [createTeam] = useCreateTeamMutation({
 | 
				
			||||||
    update: (client, createData) => {
 | 
					    update: (client, createData) => {
 | 
				
			||||||
      updateApolloCache<GetProjectsQuery>(client, GetProjectsDocument, cache =>
 | 
					      updateApolloCache<GetProjectsQuery>(client, GetProjectsDocument, (cache) =>
 | 
				
			||||||
        produce(cache, draftCache => {
 | 
					        produce(cache, (draftCache) => {
 | 
				
			||||||
          if (createData.data) {
 | 
					          if (createData.data) {
 | 
				
			||||||
            draftCache.teams.push({ ...createData.data?.createTeam });
 | 
					            draftCache.teams.push({ ...createData.data?.createTeam });
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@@ -239,7 +241,7 @@ const Projects = () => {
 | 
				
			|||||||
    const { projects, teams, organizations } = data;
 | 
					    const { projects, teams, organizations } = data;
 | 
				
			||||||
    const organizationID = organizations[0].id ?? null;
 | 
					    const organizationID = organizations[0].id ?? null;
 | 
				
			||||||
    const personalProjects = projects
 | 
					    const personalProjects = projects
 | 
				
			||||||
      .filter(p => p.team === null)
 | 
					      .filter((p) => p.team === null)
 | 
				
			||||||
      .sort((a, b) => {
 | 
					      .sort((a, b) => {
 | 
				
			||||||
        const textA = a.name.toUpperCase();
 | 
					        const textA = a.name.toUpperCase();
 | 
				
			||||||
        const textB = b.name.toUpperCase();
 | 
					        const textB = b.name.toUpperCase();
 | 
				
			||||||
@@ -251,12 +253,12 @@ const Projects = () => {
 | 
				
			|||||||
        const textB = b.name.toUpperCase();
 | 
					        const textB = b.name.toUpperCase();
 | 
				
			||||||
        return textA < textB ? -1 : textA > textB ? 1 : 0; // eslint-disable-line no-nested-ternary
 | 
					        return textA < textB ? -1 : textA > textB ? 1 : 0; // eslint-disable-line no-nested-ternary
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .map(team => {
 | 
					      .map((team) => {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
          id: team.id,
 | 
					          id: team.id,
 | 
				
			||||||
          name: team.name,
 | 
					          name: team.name,
 | 
				
			||||||
          projects: projects
 | 
					          projects: projects
 | 
				
			||||||
            .filter(project => project.team && project.team.id === team.id)
 | 
					            .filter((project) => project.team && project.team.id === team.id)
 | 
				
			||||||
            .sort((a, b) => {
 | 
					            .sort((a, b) => {
 | 
				
			||||||
              const textA = a.name.toUpperCase();
 | 
					              const textA = a.name.toUpperCase();
 | 
				
			||||||
              const textB = b.name.toUpperCase();
 | 
					              const textB = b.name.toUpperCase();
 | 
				
			||||||
@@ -272,7 +274,7 @@ const Projects = () => {
 | 
				
			|||||||
            {true && ( // TODO: add permision check
 | 
					            {true && ( // TODO: add permision check
 | 
				
			||||||
              <AddTeamButton
 | 
					              <AddTeamButton
 | 
				
			||||||
                variant="outline"
 | 
					                variant="outline"
 | 
				
			||||||
                onClick={$target => {
 | 
					                onClick={($target) => {
 | 
				
			||||||
                  showPopup(
 | 
					                  showPopup(
 | 
				
			||||||
                    $target,
 | 
					                    $target,
 | 
				
			||||||
                    <Popup
 | 
					                    <Popup
 | 
				
			||||||
@@ -283,7 +285,7 @@ const Projects = () => {
 | 
				
			|||||||
                      }}
 | 
					                      }}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                      <CreateTeamForm
 | 
					                      <CreateTeamForm
 | 
				
			||||||
                        onCreateTeam={teamName => {
 | 
					                        onCreateTeam={(teamName) => {
 | 
				
			||||||
                          if (organizationID) {
 | 
					                          if (organizationID) {
 | 
				
			||||||
                            createTeam({ variables: { name: teamName, organizationID } });
 | 
					                            createTeam({ variables: { name: teamName, organizationID } });
 | 
				
			||||||
                            hidePopup();
 | 
					                            hidePopup();
 | 
				
			||||||
@@ -326,7 +328,7 @@ const Projects = () => {
 | 
				
			|||||||
                </ProjectListItem>
 | 
					                </ProjectListItem>
 | 
				
			||||||
              </ProjectList>
 | 
					              </ProjectList>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            {projectTeams.map(team => {
 | 
					            {projectTeams.map((team) => {
 | 
				
			||||||
              return (
 | 
					              return (
 | 
				
			||||||
                <div key={team.id}>
 | 
					                <div key={team.id}>
 | 
				
			||||||
                  <ProjectSectionTitleWrapper>
 | 
					                  <ProjectSectionTitleWrapper>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ const UsersRegister = () => {
 | 
				
			|||||||
                  },
 | 
					                  },
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
              })
 | 
					              })
 | 
				
			||||||
                .then(async x => {
 | 
					                .then(async (x) => {
 | 
				
			||||||
                  const response = await x.json();
 | 
					                  const response = await x.json();
 | 
				
			||||||
                  const { setup } = response;
 | 
					                  const { setup } = response;
 | 
				
			||||||
                  console.log(response);
 | 
					                  console.log(response);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,7 @@ const UserMember = styled(Member)`
 | 
				
			|||||||
  padding: 4px 0;
 | 
					  padding: 4px 0;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    background: ${props => mixin.rgba(props.theme.colors.bg.primary, 0.4)};
 | 
					    background: ${(props) => mixin.rgba(props.theme.colors.bg.primary, 0.4)};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  border-radius: 6px;
 | 
					  border-radius: 6px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
@@ -57,8 +57,8 @@ const UserManagementPopup: React.FC<UserManagementPopupProps> = ({ users, teamMe
 | 
				
			|||||||
      <SearchInput width="100%" variant="alternate" placeholder="Email address or name" name="search" />
 | 
					      <SearchInput width="100%" variant="alternate" placeholder="Email address or name" name="search" />
 | 
				
			||||||
      <TeamMemberList>
 | 
					      <TeamMemberList>
 | 
				
			||||||
        {users
 | 
					        {users
 | 
				
			||||||
          .filter(u => u.id !== teamMembers.find(p => p.id === u.id)?.id)
 | 
					          .filter((u) => u.id !== teamMembers.find((p) => p.id === u.id)?.id)
 | 
				
			||||||
          .map(user => (
 | 
					          .map((user) => (
 | 
				
			||||||
            <UserMember
 | 
					            <UserMember
 | 
				
			||||||
              key={user.id}
 | 
					              key={user.id}
 | 
				
			||||||
              onCardMemberClick={() => onAddTeamMember(user.id)}
 | 
					              onCardMemberClick={() => onAddTeamMember(user.id)}
 | 
				
			||||||
@@ -116,7 +116,7 @@ export const MiniProfileActionItem = styled.span<{ disabled?: boolean }>`
 | 
				
			|||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
  text-decoration: none;
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ${props =>
 | 
					  ${(props) =>
 | 
				
			||||||
    props.disabled
 | 
					    props.disabled
 | 
				
			||||||
      ? css`
 | 
					      ? css`
 | 
				
			||||||
          user-select: none;
 | 
					          user-select: none;
 | 
				
			||||||
@@ -137,7 +137,7 @@ export const Content = styled.div`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const CurrentPermission = styled.span`
 | 
					export const CurrentPermission = styled.span`
 | 
				
			||||||
  margin-left: 4px;
 | 
					  margin-left: 4px;
 | 
				
			||||||
  color: ${props => mixin.rgba(props.theme.colors.text.secondary, 0.4)};
 | 
					  color: ${(props) => mixin.rgba(props.theme.colors.text.secondary, 0.4)};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Separator = styled.div`
 | 
					export const Separator = styled.div`
 | 
				
			||||||
@@ -148,13 +148,13 @@ export const Separator = styled.div`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const WarningText = styled.span`
 | 
					export const WarningText = styled.span`
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  color: ${props => mixin.rgba(props.theme.colors.text.primary, 0.4)};
 | 
					  color: ${(props) => mixin.rgba(props.theme.colors.text.primary, 0.4)};
 | 
				
			||||||
  padding: 6px;
 | 
					  padding: 6px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DeleteDescription = styled.div`
 | 
					export const DeleteDescription = styled.div`
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 14px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const RemoveMemberButton = styled(Button)`
 | 
					export const RemoveMemberButton = styled(Button)`
 | 
				
			||||||
@@ -221,13 +221,13 @@ const TeamRoleManagerPopup: React.FC<TeamRoleManagerPopupProps> = ({
 | 
				
			|||||||
        <MiniProfileActions>
 | 
					        <MiniProfileActions>
 | 
				
			||||||
          <MiniProfileActionWrapper>
 | 
					          <MiniProfileActionWrapper>
 | 
				
			||||||
            {permissions
 | 
					            {permissions
 | 
				
			||||||
              .filter(p => (subject.role && subject.role.code === 'owner') || p.code !== 'owner')
 | 
					              .filter((p) => (subject.role && subject.role.code === 'owner') || p.code !== 'owner')
 | 
				
			||||||
              .map(perm => (
 | 
					              .map((perm) => (
 | 
				
			||||||
                <MiniProfileActionItem
 | 
					                <MiniProfileActionItem
 | 
				
			||||||
                  disabled={subject.role && perm.code !== subject.role.code && !canChangeRole}
 | 
					                  disabled={subject.role && perm.code !== subject.role.code && !canChangeRole}
 | 
				
			||||||
                  key={perm.code}
 | 
					                  key={perm.code}
 | 
				
			||||||
                  onClick={() => {
 | 
					                  onClick={() => {
 | 
				
			||||||
                    if (onChangeRole && subject.role && perm.code !== subject.role.code) {
 | 
					                    if (subject.role && perm.code !== subject.role.code) {
 | 
				
			||||||
                      switch (perm.code) {
 | 
					                      switch (perm.code) {
 | 
				
			||||||
                        case 'owner':
 | 
					                        case 'owner':
 | 
				
			||||||
                          onChangeRole(RoleCode.Owner);
 | 
					                          onChangeRole(RoleCode.Owner);
 | 
				
			||||||
@@ -276,8 +276,8 @@ const TeamRoleManagerPopup: React.FC<TeamRoleManagerPopupProps> = ({
 | 
				
			|||||||
              <Select
 | 
					              <Select
 | 
				
			||||||
                label="New projects owner"
 | 
					                label="New projects owner"
 | 
				
			||||||
                value={orphanedProjectOwner}
 | 
					                value={orphanedProjectOwner}
 | 
				
			||||||
                onChange={value => setOrphanedProjectOwner(value)}
 | 
					                onChange={(value) => setOrphanedProjectOwner(value)}
 | 
				
			||||||
                options={members.filter(m => m.id !== subject.id).map(m => ({ label: m.fullName, value: m.id }))}
 | 
					                options={members.filter((m) => m.id !== subject.id).map((m) => ({ label: m.fullName, value: m.id }))}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            </>
 | 
					            </>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
@@ -307,14 +307,14 @@ const MemberItemOption = styled(Button)`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MemberList = styled.div`
 | 
					const MemberList = styled.div`
 | 
				
			||||||
  border-top: 1px solid ${props => props.theme.colors.border};
 | 
					  border-top: 1px solid ${(props) => props.theme.colors.border};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MemberListItem = styled.div`
 | 
					const MemberListItem = styled.div`
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  flex-flow: row wrap;
 | 
					  flex-flow: row wrap;
 | 
				
			||||||
  justify-content: space-between;
 | 
					  justify-content: space-between;
 | 
				
			||||||
  border-bottom: 1px solid ${props => props.theme.colors.border};
 | 
					  border-bottom: 1px solid ${(props) => props.theme.colors.border};
 | 
				
			||||||
  min-height: 40px;
 | 
					  min-height: 40px;
 | 
				
			||||||
  padding: 12px 0 12px 40px;
 | 
					  padding: 12px 0 12px 40px;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
@@ -338,11 +338,11 @@ const MemberProfile = styled(TaskAssignee)`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MemberItemName = styled.p`
 | 
					const MemberItemName = styled.p`
 | 
				
			||||||
  color: ${props => props.theme.colors.text.secondary};
 | 
					  color: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MemberItemUsername = styled.p`
 | 
					const MemberItemUsername = styled.p`
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MemberListHeader = styled.div`
 | 
					const MemberListHeader = styled.div`
 | 
				
			||||||
@@ -351,12 +351,12 @@ const MemberListHeader = styled.div`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
const ListTitle = styled.h3`
 | 
					const ListTitle = styled.h3`
 | 
				
			||||||
  font-size: 18px;
 | 
					  font-size: 18px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.secondary};
 | 
					  color: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
  margin-bottom: 12px;
 | 
					  margin-bottom: 12px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
const ListDesc = styled.span`
 | 
					const ListDesc = styled.span`
 | 
				
			||||||
  font-size: 16px;
 | 
					  font-size: 16px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
const FilterSearch = styled(Input)`
 | 
					const FilterSearch = styled(Input)`
 | 
				
			||||||
  margin: 0;
 | 
					  margin: 0;
 | 
				
			||||||
@@ -388,11 +388,11 @@ const FilterTabItem = styled.li`
 | 
				
			|||||||
  font-weight: 700;
 | 
					  font-weight: 700;
 | 
				
			||||||
  text-decoration: none;
 | 
					  text-decoration: none;
 | 
				
			||||||
  padding: 6px 8px;
 | 
					  padding: 6px 8px;
 | 
				
			||||||
  color: ${props => props.theme.colors.text.primary};
 | 
					  color: ${(props) => props.theme.colors.text.primary};
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    border-radius: 6px;
 | 
					    border-radius: 6px;
 | 
				
			||||||
    background: ${props => props.theme.colors.primary};
 | 
					    background: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
    color: ${props => props.theme.colors.text.secondary};
 | 
					    color: ${(props) => props.theme.colors.text.secondary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -433,8 +433,8 @@ const Members: React.FC<MembersProps> = ({ teamID }) => {
 | 
				
			|||||||
      updateApolloCache<GetTeamQuery>(
 | 
					      updateApolloCache<GetTeamQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        GetTeamDocument,
 | 
					        GetTeamDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            if (response.data) {
 | 
					            if (response.data) {
 | 
				
			||||||
              draftCache.findTeam.members.push({
 | 
					              draftCache.findTeam.members.push({
 | 
				
			||||||
                ...response.data.createTeamMember.teamMember,
 | 
					                ...response.data.createTeamMember.teamMember,
 | 
				
			||||||
@@ -453,10 +453,10 @@ const Members: React.FC<MembersProps> = ({ teamID }) => {
 | 
				
			|||||||
      updateApolloCache<GetTeamQuery>(
 | 
					      updateApolloCache<GetTeamQuery>(
 | 
				
			||||||
        client,
 | 
					        client,
 | 
				
			||||||
        GetTeamDocument,
 | 
					        GetTeamDocument,
 | 
				
			||||||
        cache =>
 | 
					        (cache) =>
 | 
				
			||||||
          produce(cache, draftCache => {
 | 
					          produce(cache, (draftCache) => {
 | 
				
			||||||
            draftCache.findTeam.members = cache.findTeam.members.filter(
 | 
					            draftCache.findTeam.members = cache.findTeam.members.filter(
 | 
				
			||||||
              member => member.id !== response.data?.deleteTeamMember.userID,
 | 
					              (member) => member.id !== response.data?.deleteTeamMember.userID,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
        { teamID },
 | 
					        { teamID },
 | 
				
			||||||
@@ -484,13 +484,13 @@ const Members: React.FC<MembersProps> = ({ teamID }) => {
 | 
				
			|||||||
              <FilterSearch width="250px" variant="alternate" placeholder="Filter by name" />
 | 
					              <FilterSearch width="250px" variant="alternate" placeholder="Filter by name" />
 | 
				
			||||||
              {true && ( // TODO: add permission check
 | 
					              {true && ( // TODO: add permission check
 | 
				
			||||||
                <InviteMemberButton
 | 
					                <InviteMemberButton
 | 
				
			||||||
                  onClick={$target => {
 | 
					                  onClick={($target) => {
 | 
				
			||||||
                    showPopup(
 | 
					                    showPopup(
 | 
				
			||||||
                      $target,
 | 
					                      $target,
 | 
				
			||||||
                      <UserManagementPopup
 | 
					                      <UserManagementPopup
 | 
				
			||||||
                        users={data.users}
 | 
					                        users={data.users}
 | 
				
			||||||
                        teamMembers={data.findTeam.members}
 | 
					                        teamMembers={data.findTeam.members}
 | 
				
			||||||
                        onAddTeamMember={userID => {
 | 
					                        onAddTeamMember={(userID) => {
 | 
				
			||||||
                          createTeamMember({ variables: { userID, teamID } });
 | 
					                          createTeamMember({ variables: { userID, teamID } });
 | 
				
			||||||
                        }}
 | 
					                        }}
 | 
				
			||||||
                      />,
 | 
					                      />,
 | 
				
			||||||
@@ -504,7 +504,7 @@ const Members: React.FC<MembersProps> = ({ teamID }) => {
 | 
				
			|||||||
            </ListActions>
 | 
					            </ListActions>
 | 
				
			||||||
          </MemberListHeader>
 | 
					          </MemberListHeader>
 | 
				
			||||||
          <MemberList>
 | 
					          <MemberList>
 | 
				
			||||||
            {data.findTeam.members.map(member => (
 | 
					            {data.findTeam.members.map((member) => (
 | 
				
			||||||
              <MemberListItem>
 | 
					              <MemberListItem>
 | 
				
			||||||
                <MemberProfile showRoleIcons size={32} onMemberProfile={NOOP} member={member} />
 | 
					                <MemberProfile showRoleIcons size={32} onMemberProfile={NOOP} member={member} />
 | 
				
			||||||
                <MemberListItemDetails>
 | 
					                <MemberListItemDetails>
 | 
				
			||||||
@@ -515,7 +515,7 @@ const Members: React.FC<MembersProps> = ({ teamID }) => {
 | 
				
			|||||||
                  <MemberItemOption variant="flat">On 2 projects</MemberItemOption>
 | 
					                  <MemberItemOption variant="flat">On 2 projects</MemberItemOption>
 | 
				
			||||||
                  <MemberItemOption
 | 
					                  <MemberItemOption
 | 
				
			||||||
                    variant="outline"
 | 
					                    variant="outline"
 | 
				
			||||||
                    onClick={$target => {
 | 
					                    onClick={($target) => {
 | 
				
			||||||
                      showPopup(
 | 
					                      showPopup(
 | 
				
			||||||
                        $target,
 | 
					                        $target,
 | 
				
			||||||
                        <TeamRoleManagerPopup
 | 
					                        <TeamRoleManagerPopup
 | 
				
			||||||
@@ -525,13 +525,13 @@ const Members: React.FC<MembersProps> = ({ teamID }) => {
 | 
				
			|||||||
                          warning={member.role && member.role.code === 'owner' ? warning : null}
 | 
					                          warning={member.role && member.role.code === 'owner' ? warning : null}
 | 
				
			||||||
                          // canChangeRole={user.isAdmin(PermissionLevel.TEAM, PermissionObjectType.TEAM, teamID)} TODO: add permission check
 | 
					                          // canChangeRole={user.isAdmin(PermissionLevel.TEAM, PermissionObjectType.TEAM, teamID)} TODO: add permission check
 | 
				
			||||||
                          canChangeRole={true}
 | 
					                          canChangeRole={true}
 | 
				
			||||||
                          onChangeRole={roleCode => {
 | 
					                          onChangeRole={(roleCode) => {
 | 
				
			||||||
                            updateTeamMemberRole({ variables: { userID: member.id, teamID, roleCode } });
 | 
					                            updateTeamMemberRole({ variables: { userID: member.id, teamID, roleCode } });
 | 
				
			||||||
                          }}
 | 
					                          }}
 | 
				
			||||||
                          onRemoveFromTeam={
 | 
					                          onRemoveFromTeam={
 | 
				
			||||||
                            member.role && member.role.code === 'owner'
 | 
					                            member.role && member.role.code === 'owner'
 | 
				
			||||||
                              ? undefined
 | 
					                              ? undefined
 | 
				
			||||||
                              : newOwnerID => {
 | 
					                              : (newOwnerID) => {
 | 
				
			||||||
                                  deleteTeamMember({ variables: { teamID, newOwnerID, userID: member.id } });
 | 
					                                  deleteTeamMember({ variables: { teamID, newOwnerID, userID: member.id } });
 | 
				
			||||||
                                  hidePopup();
 | 
					                                  hidePopup();
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ const InputWrapper = styled.div<{ width: string }>`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const InputLabel = styled.span<{ width: string }>`
 | 
					const InputLabel = styled.span<{ width: string }>`
 | 
				
			||||||
  width: ${props => props.width};
 | 
					  width: ${(props) => props.width};
 | 
				
			||||||
  padding: 0.7rem !important;
 | 
					  padding: 0.7rem !important;
 | 
				
			||||||
  color: #c2c6dc;
 | 
					  color: #c2c6dc;
 | 
				
			||||||
  left: 0;
 | 
					  left: 0;
 | 
				
			||||||
@@ -40,13 +40,13 @@ const InputInput = styled.input<{
 | 
				
			|||||||
  focusBg: string;
 | 
					  focusBg: string;
 | 
				
			||||||
  borderColor: string;
 | 
					  borderColor: string;
 | 
				
			||||||
}>`
 | 
					}>`
 | 
				
			||||||
  width: ${props => props.width};
 | 
					  width: ${(props) => props.width};
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 14px;
 | 
				
			||||||
  border: 1px solid rgba(0, 0, 0, 0.2);
 | 
					  border: 1px solid rgba(0, 0, 0, 0.2);
 | 
				
			||||||
  border-color: ${props => props.borderColor};
 | 
					  border-color: ${(props) => props.borderColor};
 | 
				
			||||||
  background: #262c49;
 | 
					  background: #262c49;
 | 
				
			||||||
  box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.15);
 | 
					  box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.15);
 | 
				
			||||||
  ${props => (props.hasIcon ? 'padding: 0.7rem 1rem 0.7rem 3rem;' : 'padding: 0.7rem;')}
 | 
					  ${(props) => (props.hasIcon ? 'padding: 0.7rem 1rem 0.7rem 3rem;' : 'padding: 0.7rem;')}
 | 
				
			||||||
  line-height: 16px;
 | 
					  line-height: 16px;
 | 
				
			||||||
  color: #c2c6dc;
 | 
					  color: #c2c6dc;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
@@ -55,13 +55,13 @@ const InputInput = styled.input<{
 | 
				
			|||||||
  &:focus {
 | 
					  &:focus {
 | 
				
			||||||
    box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.15);
 | 
					    box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.15);
 | 
				
			||||||
    border: 1px solid rgba(115, 103, 240);
 | 
					    border: 1px solid rgba(115, 103, 240);
 | 
				
			||||||
    background: ${props => props.focusBg};
 | 
					    background: ${(props) => props.focusBg};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  &:focus ~ ${InputLabel} {
 | 
					  &:focus ~ ${InputLabel} {
 | 
				
			||||||
    color: ${props => props.theme.colors.primary};
 | 
					    color: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
    transform: translate(-3px, -90%);
 | 
					    transform: translate(-3px, -90%);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ${props =>
 | 
					  ${(props) =>
 | 
				
			||||||
    props.hasValue &&
 | 
					    props.hasValue &&
 | 
				
			||||||
    css`
 | 
					    css`
 | 
				
			||||||
      & ~ ${InputLabel} {
 | 
					      & ~ ${InputLabel} {
 | 
				
			||||||
@@ -94,11 +94,13 @@ type ControlledInputProps = {
 | 
				
			|||||||
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
 | 
					  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
 | 
				
			||||||
  value?: string;
 | 
					  value?: string;
 | 
				
			||||||
  onClick?: (e: React.MouseEvent<HTMLInputElement>) => void;
 | 
					  onClick?: (e: React.MouseEvent<HTMLInputElement>) => void;
 | 
				
			||||||
 | 
					  disabled?: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ControlledInput = ({
 | 
					const ControlledInput = ({
 | 
				
			||||||
  width = 'auto',
 | 
					  width = 'auto',
 | 
				
			||||||
  variant = 'normal',
 | 
					  variant = 'normal',
 | 
				
			||||||
 | 
					  disabled = false,
 | 
				
			||||||
  type = 'text',
 | 
					  type = 'text',
 | 
				
			||||||
  autocomplete,
 | 
					  autocomplete,
 | 
				
			||||||
  autoFocus = false,
 | 
					  autoFocus = false,
 | 
				
			||||||
@@ -126,8 +128,9 @@ const ControlledInput = ({
 | 
				
			|||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <InputWrapper className={className} width={width}>
 | 
					    <InputWrapper className={className} width={width}>
 | 
				
			||||||
      <InputInput
 | 
					      <InputInput
 | 
				
			||||||
 | 
					        disabled={disabled}
 | 
				
			||||||
        hasValue={hasValue}
 | 
					        hasValue={hasValue}
 | 
				
			||||||
        onChange={e => {
 | 
					        onChange={(e) => {
 | 
				
			||||||
          if (onChange) {
 | 
					          if (onChange) {
 | 
				
			||||||
            setHasValue(e.currentTarget.value !== '' || floatingLabel);
 | 
					            setHasValue(e.currentTarget.value !== '' || floatingLabel);
 | 
				
			||||||
            onChange(e);
 | 
					            onChange(e);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,7 @@ const HeaderSelectLabel = styled.div`
 | 
				
			|||||||
  color: #c2c6dc;
 | 
					  color: #c2c6dc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    background: ${props => props.theme.colors.primary};
 | 
					    background: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
    color: #c2c6dc;
 | 
					    color: #c2c6dc;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
@@ -78,12 +78,12 @@ const HeaderSelect = styled.select`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  & option {
 | 
					  & option {
 | 
				
			||||||
    color: #c2c6dc;
 | 
					    color: #c2c6dc;
 | 
				
			||||||
    background: ${props => props.theme.colors.bg.primary};
 | 
					    background: ${(props) => props.theme.colors.bg.primary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  & option:hover {
 | 
					  & option:hover {
 | 
				
			||||||
    background: ${props => props.theme.colors.bg.secondary};
 | 
					    background: ${(props) => props.theme.colors.bg.secondary};
 | 
				
			||||||
    border: 1px solid ${props => props.theme.colors.primary};
 | 
					    border: 1px solid ${(props) => props.theme.colors.primary};
 | 
				
			||||||
    outline: none !important;
 | 
					    outline: none !important;
 | 
				
			||||||
    box-shadow: none;
 | 
					    box-shadow: none;
 | 
				
			||||||
    color: #c2c6dc;
 | 
					    color: #c2c6dc;
 | 
				
			||||||
@@ -115,7 +115,7 @@ const HeaderButton = styled.button`
 | 
				
			|||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
  border-radius: 3px;
 | 
					  border-radius: 3px;
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    background: ${props => props.theme.colors.primary};
 | 
					    background: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
    color: #fff;
 | 
					    color: #fff;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
@@ -133,7 +133,14 @@ const HeaderActions = styled.div`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange, onRemoveDueDate, onCancel }) => {
 | 
					const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange, onRemoveDueDate, onCancel }) => {
 | 
				
			||||||
  const currentDueDate = task.dueDate ? dayjs(task.dueDate).toDate() : null;
 | 
					  const currentDueDate = task.dueDate ? dayjs(task.dueDate).toDate() : null;
 | 
				
			||||||
  const { register, handleSubmit, errors, setValue, setError, formState, control } = useForm<DueDateFormData>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    setValue,
 | 
				
			||||||
 | 
					    setError,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					    control,
 | 
				
			||||||
 | 
					  } = useForm<DueDateFormData>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [startDate, setStartDate] = useState<Date | null>(currentDueDate);
 | 
					  const [startDate, setStartDate] = useState<Date | null>(currentDueDate);
 | 
				
			||||||
  const [endDate, setEndDate] = useState<Date | null>(currentDueDate);
 | 
					  const [endDate, setEndDate] = useState<Date | null>(currentDueDate);
 | 
				
			||||||
@@ -203,7 +210,11 @@ const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange,
 | 
				
			|||||||
      <DateRangeInputs>
 | 
					      <DateRangeInputs>
 | 
				
			||||||
        <DatePicker
 | 
					        <DatePicker
 | 
				
			||||||
          selected={startDate}
 | 
					          selected={startDate}
 | 
				
			||||||
          onChange={date => setStartDate(date)}
 | 
					          onChange={(date) => {
 | 
				
			||||||
 | 
					            if (!Array.isArray(date)) {
 | 
				
			||||||
 | 
					              setStartDate(date);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
          popperClassName="picker-hidden"
 | 
					          popperClassName="picker-hidden"
 | 
				
			||||||
          dateFormat="yyyy-MM-dd"
 | 
					          dateFormat="yyyy-MM-dd"
 | 
				
			||||||
          disabledKeyboardNavigation
 | 
					          disabledKeyboardNavigation
 | 
				
			||||||
@@ -214,7 +225,11 @@ const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange,
 | 
				
			|||||||
          <DatePicker
 | 
					          <DatePicker
 | 
				
			||||||
            selected={startDate}
 | 
					            selected={startDate}
 | 
				
			||||||
            isClearable
 | 
					            isClearable
 | 
				
			||||||
            onChange={date => setStartDate(date)}
 | 
					            onChange={(date) => {
 | 
				
			||||||
 | 
					              if (!Array.isArray(date)) {
 | 
				
			||||||
 | 
					                setStartDate(date);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
            popperClassName="picker-hidden"
 | 
					            popperClassName="picker-hidden"
 | 
				
			||||||
            dateFormat="yyyy-MM-dd"
 | 
					            dateFormat="yyyy-MM-dd"
 | 
				
			||||||
            placeholderText="Select from date"
 | 
					            placeholderText="Select from date"
 | 
				
			||||||
@@ -225,7 +240,11 @@ const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange,
 | 
				
			|||||||
      </DateRangeInputs>
 | 
					      </DateRangeInputs>
 | 
				
			||||||
      <DatePicker
 | 
					      <DatePicker
 | 
				
			||||||
        selected={startDate}
 | 
					        selected={startDate}
 | 
				
			||||||
        onChange={date => setStartDate(date)}
 | 
					        onChange={(date) => {
 | 
				
			||||||
 | 
					          if (!Array.isArray(date)) {
 | 
				
			||||||
 | 
					            setStartDate(date);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
        startDate={startDate}
 | 
					        startDate={startDate}
 | 
				
			||||||
        useWeekdaysShort
 | 
					        useWeekdaysShort
 | 
				
			||||||
        renderCustomHeader={({
 | 
					        renderCustomHeader={({
 | 
				
			||||||
@@ -247,7 +266,7 @@ const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange,
 | 
				
			|||||||
                value={months[getMonth(date)]}
 | 
					                value={months[getMonth(date)]}
 | 
				
			||||||
                onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}
 | 
					                onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                {months.map(option => (
 | 
					                {months.map((option) => (
 | 
				
			||||||
                  <option key={option} value={option}>
 | 
					                  <option key={option} value={option}>
 | 
				
			||||||
                    {option}
 | 
					                    {option}
 | 
				
			||||||
                  </option>
 | 
					                  </option>
 | 
				
			||||||
@@ -257,7 +276,7 @@ const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange,
 | 
				
			|||||||
            <HeaderSelectLabel>
 | 
					            <HeaderSelectLabel>
 | 
				
			||||||
              {date.getFullYear()}
 | 
					              {date.getFullYear()}
 | 
				
			||||||
              <HeaderSelect value={getYear(date)} onChange={({ target: { value } }) => changeYear(parseInt(value, 10))}>
 | 
					              <HeaderSelect value={getYear(date)} onChange={({ target: { value } }) => changeYear(parseInt(value, 10))}>
 | 
				
			||||||
                {years.map(option => (
 | 
					                {years.map((option) => (
 | 
				
			||||||
                  <option key={option} value={option}>
 | 
					                  <option key={option} value={option}>
 | 
				
			||||||
                    {option}
 | 
					                    {option}
 | 
				
			||||||
                  </option>
 | 
					                  </option>
 | 
				
			||||||
@@ -279,8 +298,10 @@ const DueDateManager: React.FC<DueDateManagerProps> = ({ task, onDueDateChange,
 | 
				
			|||||||
          <ActionLabel>Due Time</ActionLabel>
 | 
					          <ActionLabel>Due Time</ActionLabel>
 | 
				
			||||||
          <DatePicker
 | 
					          <DatePicker
 | 
				
			||||||
            selected={startDate}
 | 
					            selected={startDate}
 | 
				
			||||||
            onChange={date => {
 | 
					            onChange={(date) => {
 | 
				
			||||||
              setStartDate(date);
 | 
					              if (!Array.isArray(date)) {
 | 
				
			||||||
 | 
					                setStartDate(date);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
            showTimeSelect
 | 
					            showTimeSelect
 | 
				
			||||||
            showTimeSelectOnly
 | 
					            showTimeSelectOnly
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,12 @@ import {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const Login = ({ onSubmit }: LoginProps) => {
 | 
					const Login = ({ onSubmit }: LoginProps) => {
 | 
				
			||||||
  const [isComplete, setComplete] = useState(true);
 | 
					  const [isComplete, setComplete] = useState(true);
 | 
				
			||||||
  const { register, handleSubmit, errors, setError, formState } = useForm<LoginFormData>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    setError,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					  } = useForm<LoginFormData>();
 | 
				
			||||||
  const loginSubmit = (data: LoginFormData) => {
 | 
					  const loginSubmit = (data: LoginFormData) => {
 | 
				
			||||||
    setComplete(false);
 | 
					    setComplete(false);
 | 
				
			||||||
    onSubmit(data, setComplete, setError);
 | 
					    onSubmit(data, setComplete, setError);
 | 
				
			||||||
@@ -47,12 +52,7 @@ const Login = ({ onSubmit }: LoginProps) => {
 | 
				
			|||||||
            <Form onSubmit={handleSubmit(loginSubmit)}>
 | 
					            <Form onSubmit={handleSubmit(loginSubmit)}>
 | 
				
			||||||
              <FormLabel htmlFor="username">
 | 
					              <FormLabel htmlFor="username">
 | 
				
			||||||
                Username
 | 
					                Username
 | 
				
			||||||
                <FormTextInput
 | 
					                <FormTextInput type="text" {...register('username', { required: 'Username is required' })} />
 | 
				
			||||||
                  type="text"
 | 
					 | 
				
			||||||
                  id="username"
 | 
					 | 
				
			||||||
                  name="username"
 | 
					 | 
				
			||||||
                  ref={register({ required: 'Username is required' })}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <FormIcon>
 | 
					                <FormIcon>
 | 
				
			||||||
                  <User width={20} height={20} />
 | 
					                  <User width={20} height={20} />
 | 
				
			||||||
                </FormIcon>
 | 
					                </FormIcon>
 | 
				
			||||||
@@ -60,12 +60,7 @@ const Login = ({ onSubmit }: LoginProps) => {
 | 
				
			|||||||
              {errors.username && <FormError>{errors.username.message}</FormError>}
 | 
					              {errors.username && <FormError>{errors.username.message}</FormError>}
 | 
				
			||||||
              <FormLabel htmlFor="password">
 | 
					              <FormLabel htmlFor="password">
 | 
				
			||||||
                Password
 | 
					                Password
 | 
				
			||||||
                <FormTextInput
 | 
					                <FormTextInput type="password" {...register('password', { required: 'Password is required' })} />
 | 
				
			||||||
                  type="password"
 | 
					 | 
				
			||||||
                  id="password"
 | 
					 | 
				
			||||||
                  name="password"
 | 
					 | 
				
			||||||
                  ref={register({ required: 'Password is required' })}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <FormIcon>
 | 
					                <FormIcon>
 | 
				
			||||||
                  <Lock width={20} height={20} />
 | 
					                  <Lock width={20} height={20} />
 | 
				
			||||||
                </FormIcon>
 | 
					                </FormIcon>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,12 @@ const INITIALS_PATTERN = /[a-zA-Z]{2,3}/i;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
					const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			||||||
  const [isComplete, setComplete] = useState(true);
 | 
					  const [isComplete, setComplete] = useState(true);
 | 
				
			||||||
  const { register, handleSubmit, errors, setError } = useForm<RegisterFormData>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					    setError,
 | 
				
			||||||
 | 
					  } = useForm<RegisterFormData>();
 | 
				
			||||||
  const loginSubmit = (data: RegisterFormData) => {
 | 
					  const loginSubmit = (data: RegisterFormData) => {
 | 
				
			||||||
    setComplete(false);
 | 
					    setComplete(false);
 | 
				
			||||||
    onSubmit(data, setComplete, setError);
 | 
					    onSubmit(data, setComplete, setError);
 | 
				
			||||||
@@ -55,12 +60,7 @@ const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			|||||||
                <Form onSubmit={handleSubmit(loginSubmit)}>
 | 
					                <Form onSubmit={handleSubmit(loginSubmit)}>
 | 
				
			||||||
                  <FormLabel htmlFor="fullname">
 | 
					                  <FormLabel htmlFor="fullname">
 | 
				
			||||||
                    Full name
 | 
					                    Full name
 | 
				
			||||||
                    <FormTextInput
 | 
					                    <FormTextInput type="text" {...register('fullname', { required: 'Full name is required' })} />
 | 
				
			||||||
                      type="text"
 | 
					 | 
				
			||||||
                      id="fullname"
 | 
					 | 
				
			||||||
                      name="fullname"
 | 
					 | 
				
			||||||
                      ref={register({ required: 'Full name is required' })}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <FormIcon>
 | 
					                    <FormIcon>
 | 
				
			||||||
                      <User width={20} height={20} />
 | 
					                      <User width={20} height={20} />
 | 
				
			||||||
                    </FormIcon>
 | 
					                    </FormIcon>
 | 
				
			||||||
@@ -68,12 +68,7 @@ const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			|||||||
                  {errors.username && <FormError>{errors.username.message}</FormError>}
 | 
					                  {errors.username && <FormError>{errors.username.message}</FormError>}
 | 
				
			||||||
                  <FormLabel htmlFor="username">
 | 
					                  <FormLabel htmlFor="username">
 | 
				
			||||||
                    Username
 | 
					                    Username
 | 
				
			||||||
                    <FormTextInput
 | 
					                    <FormTextInput type="text" {...register('username', { required: 'Username is required' })} />
 | 
				
			||||||
                      type="text"
 | 
					 | 
				
			||||||
                      id="username"
 | 
					 | 
				
			||||||
                      name="username"
 | 
					 | 
				
			||||||
                      ref={register({ required: 'Username is required' })}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <FormIcon>
 | 
					                    <FormIcon>
 | 
				
			||||||
                      <User width={20} height={20} />
 | 
					                      <User width={20} height={20} />
 | 
				
			||||||
                    </FormIcon>
 | 
					                    </FormIcon>
 | 
				
			||||||
@@ -83,9 +78,7 @@ const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			|||||||
                    Email
 | 
					                    Email
 | 
				
			||||||
                    <FormTextInput
 | 
					                    <FormTextInput
 | 
				
			||||||
                      type="text"
 | 
					                      type="text"
 | 
				
			||||||
                      id="email"
 | 
					                      {...register('email', {
 | 
				
			||||||
                      name="email"
 | 
					 | 
				
			||||||
                      ref={register({
 | 
					 | 
				
			||||||
                        required: 'Email is required',
 | 
					                        required: 'Email is required',
 | 
				
			||||||
                        pattern: { value: EMAIL_PATTERN, message: 'Must be a valid email' },
 | 
					                        pattern: { value: EMAIL_PATTERN, message: 'Must be a valid email' },
 | 
				
			||||||
                      })}
 | 
					                      })}
 | 
				
			||||||
@@ -99,9 +92,7 @@ const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			|||||||
                    Initials
 | 
					                    Initials
 | 
				
			||||||
                    <FormTextInput
 | 
					                    <FormTextInput
 | 
				
			||||||
                      type="text"
 | 
					                      type="text"
 | 
				
			||||||
                      id="initials"
 | 
					                      {...register('initials', {
 | 
				
			||||||
                      name="initials"
 | 
					 | 
				
			||||||
                      ref={register({
 | 
					 | 
				
			||||||
                        required: 'Initials is required',
 | 
					                        required: 'Initials is required',
 | 
				
			||||||
                        pattern: {
 | 
					                        pattern: {
 | 
				
			||||||
                          value: INITIALS_PATTERN,
 | 
					                          value: INITIALS_PATTERN,
 | 
				
			||||||
@@ -116,12 +107,7 @@ const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			|||||||
                  {errors.initials && <FormError>{errors.initials.message}</FormError>}
 | 
					                  {errors.initials && <FormError>{errors.initials.message}</FormError>}
 | 
				
			||||||
                  <FormLabel htmlFor="password">
 | 
					                  <FormLabel htmlFor="password">
 | 
				
			||||||
                    Password
 | 
					                    Password
 | 
				
			||||||
                    <FormTextInput
 | 
					                    <FormTextInput type="password" {...register('password', { required: 'Password is required' })} />
 | 
				
			||||||
                      type="password"
 | 
					 | 
				
			||||||
                      id="password"
 | 
					 | 
				
			||||||
                      name="password"
 | 
					 | 
				
			||||||
                      ref={register({ required: 'Password is required' })}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <FormIcon>
 | 
					                    <FormIcon>
 | 
				
			||||||
                      <Lock width={20} height={20} />
 | 
					                      <Lock width={20} height={20} />
 | 
				
			||||||
                    </FormIcon>
 | 
					                    </FormIcon>
 | 
				
			||||||
@@ -131,9 +117,7 @@ const Register = ({ onSubmit, registered = false }: RegisterProps) => {
 | 
				
			|||||||
                    Password (Confirm)
 | 
					                    Password (Confirm)
 | 
				
			||||||
                    <FormTextInput
 | 
					                    <FormTextInput
 | 
				
			||||||
                      type="password"
 | 
					                      type="password"
 | 
				
			||||||
                      id="password_confirm"
 | 
					                      {...register('password_confirm', { required: 'Password (confirm) is required' })}
 | 
				
			||||||
                      name="password_confirm"
 | 
					 | 
				
			||||||
                      ref={register({ required: 'Password (confirm) is required' })}
 | 
					 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                    <FormIcon>
 | 
					                    <FormIcon>
 | 
				
			||||||
                      <Lock width={20} height={20} />
 | 
					                      <Lock width={20} height={20} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,23 @@
 | 
				
			|||||||
import React, { useState, useRef } from 'react';
 | 
					import React, { useState, useRef } from 'react';
 | 
				
			||||||
import styled from 'styled-components';
 | 
					import styled from 'styled-components';
 | 
				
			||||||
import { User } from 'shared/icons';
 | 
					import { User } from 'shared/icons';
 | 
				
			||||||
import Input from 'shared/components/Input';
 | 
					 | 
				
			||||||
import Button from 'shared/components/Button';
 | 
					import Button from 'shared/components/Button';
 | 
				
			||||||
import { useForm } from 'react-hook-form';
 | 
					import { useForm } from 'react-hook-form';
 | 
				
			||||||
 | 
					import ControlledInput from 'shared/components/ControlledInput';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PasswordInput = styled(Input)`
 | 
					const PasswordInput = styled(ControlledInput)`
 | 
				
			||||||
  margin-top: 30px;
 | 
					  margin-top: 30px;
 | 
				
			||||||
  margin-bottom: 0;
 | 
					  margin-bottom: 0;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const UserInfoInput = styled(Input)`
 | 
					const UserInfoInput = styled(ControlledInput)`
 | 
				
			||||||
  margin-top: 30px;
 | 
					  margin-top: 30px;
 | 
				
			||||||
  margin-bottom: 0;
 | 
					  margin-bottom: 0;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FormError = styled.span`
 | 
					const FormError = styled.span`
 | 
				
			||||||
  font-size: 12px;
 | 
					  font-size: 12px;
 | 
				
			||||||
  color: ${props => props.theme.colors.warning};
 | 
					  color: ${(props) => props.theme.colors.warning};
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProfileContainer = styled.div`
 | 
					const ProfileContainer = styled.div`
 | 
				
			||||||
@@ -42,7 +42,7 @@ const AvatarMask = styled.div<{ background: string }>`
 | 
				
			|||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  height: 100%;
 | 
					  height: 100%;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
  background: ${props => props.background};
 | 
					  background: ${(props) => props.background};
 | 
				
			||||||
  border-radius: 50%;
 | 
					  border-radius: 50%;
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
@@ -152,12 +152,12 @@ const TabNavItemButton = styled.button<{ active: boolean }>`
 | 
				
			|||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  color: ${props => (props.active ? `${props.theme.colors.primary}` : '#c2c6dc')};
 | 
					  color: ${(props) => (props.active ? `${props.theme.colors.primary}` : '#c2c6dc')};
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    color: ${props => props.theme.colors.primary};
 | 
					    color: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  &:hover svg {
 | 
					  &:hover svg {
 | 
				
			||||||
    fill: ${props => props.theme.colors.primary};
 | 
					    fill: ${(props) => props.theme.colors.primary};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -173,10 +173,14 @@ const TabNavLine = styled.span<{ top: number }>`
 | 
				
			|||||||
  width: 2px;
 | 
					  width: 2px;
 | 
				
			||||||
  height: 48px;
 | 
					  height: 48px;
 | 
				
			||||||
  transform: scaleX(1);
 | 
					  transform: scaleX(1);
 | 
				
			||||||
  top: ${props => props.top}px;
 | 
					  top: ${(props) => props.top}px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  background: linear-gradient(30deg, ${props => props.theme.colors.primary}, ${props => props.theme.colors.primary});
 | 
					  background: linear-gradient(
 | 
				
			||||||
  box-shadow: 0 0 8px 0 ${props => props.theme.colors.primary};
 | 
					    30deg,
 | 
				
			||||||
 | 
					    ${(props) => props.theme.colors.primary},
 | 
				
			||||||
 | 
					    ${(props) => props.theme.colors.primary}
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  box-shadow: 0 0 8px 0 ${(props) => props.theme.colors.primary};
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  transition: all 0.2s ease;
 | 
					  transition: all 0.2s ease;
 | 
				
			||||||
@@ -267,36 +271,36 @@ type ResetPasswordTabProps = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
const ResetPasswordTab: React.FC<ResetPasswordTabProps> = ({ onResetPassword }) => {
 | 
					const ResetPasswordTab: React.FC<ResetPasswordTabProps> = ({ onResetPassword }) => {
 | 
				
			||||||
  const [active, setActive] = useState(true);
 | 
					  const [active, setActive] = useState(true);
 | 
				
			||||||
  const { register, handleSubmit, errors, setError, reset } = useForm<{ password: string; password_confirm: string }>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					    setError,
 | 
				
			||||||
 | 
					    reset,
 | 
				
			||||||
 | 
					  } = useForm<{ password: string; passwordConfirm: string }>();
 | 
				
			||||||
  const done = () => {
 | 
					  const done = () => {
 | 
				
			||||||
    reset();
 | 
					    reset();
 | 
				
			||||||
    setActive(true);
 | 
					    setActive(true);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <form
 | 
					    <form
 | 
				
			||||||
      onSubmit={handleSubmit(data => {
 | 
					      onSubmit={handleSubmit((data) => {
 | 
				
			||||||
        if (data.password !== data.password_confirm) {
 | 
					        if (data.password !== data.passwordConfirm) {
 | 
				
			||||||
          setError('password', { message: 'Passwords must match!', type: 'error' });
 | 
					          setError('password', { message: 'Passwords must match!', type: 'error' });
 | 
				
			||||||
          setError('password_confirm', { message: 'Passwords must match!', type: 'error' });
 | 
					          setError('passwordConfirm', { message: 'Passwords must match!', type: 'error' });
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          onResetPassword(data.password, done);
 | 
					          onResetPassword(data.password, done);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      })}
 | 
					      })}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <PasswordInput
 | 
					      <PasswordInput width="100%" {...register('password', { required: 'Password is required' })} label="Password" />
 | 
				
			||||||
        width="100%"
 | 
					 | 
				
			||||||
        ref={register({ required: 'Password is required' })}
 | 
					 | 
				
			||||||
        label="Password"
 | 
					 | 
				
			||||||
        name="password"
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      {errors.password && <FormError>{errors.password.message}</FormError>}
 | 
					      {errors.password && <FormError>{errors.password.message}</FormError>}
 | 
				
			||||||
      <PasswordInput
 | 
					      <PasswordInput
 | 
				
			||||||
        width="100%"
 | 
					        width="100%"
 | 
				
			||||||
        ref={register({ required: 'Password is required' })}
 | 
					        {...register('passwordConfirm', { required: 'Password is required' })}
 | 
				
			||||||
        label="Password (confirm)"
 | 
					        label="Password (confirm)"
 | 
				
			||||||
        name="password_confirm"
 | 
					 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      {errors.password_confirm && <FormError>{errors.password_confirm.message}</FormError>}
 | 
					      {errors.passwordConfirm && <FormError>{errors.passwordConfirm.message}</FormError>}
 | 
				
			||||||
      <SettingActions>
 | 
					      <SettingActions>
 | 
				
			||||||
        <SaveButton disabled={!active} type="submit">
 | 
					        <SaveButton disabled={!active} type="submit">
 | 
				
			||||||
          Save Change
 | 
					          Save Change
 | 
				
			||||||
@@ -329,7 +333,11 @@ const UserInfoTab: React.FC<UserInfoTabProps> = ({
 | 
				
			|||||||
  onChangeUserInfo,
 | 
					  onChangeUserInfo,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
  const [active, setActive] = useState(true);
 | 
					  const [active, setActive] = useState(true);
 | 
				
			||||||
  const { register, handleSubmit, errors } = useForm<UserInfoData>();
 | 
					  const {
 | 
				
			||||||
 | 
					    register,
 | 
				
			||||||
 | 
					    handleSubmit,
 | 
				
			||||||
 | 
					    formState: { errors },
 | 
				
			||||||
 | 
					  } = useForm<UserInfoData>();
 | 
				
			||||||
  const done = () => {
 | 
					  const done = () => {
 | 
				
			||||||
    setActive(true);
 | 
					    setActive(true);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -341,14 +349,13 @@ const UserInfoTab: React.FC<UserInfoTabProps> = ({
 | 
				
			|||||||
        profile={profile.profileIcon}
 | 
					        profile={profile.profileIcon}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <form
 | 
					      <form
 | 
				
			||||||
        onSubmit={handleSubmit(data => {
 | 
					        onSubmit={handleSubmit((data) => {
 | 
				
			||||||
          setActive(false);
 | 
					          setActive(false);
 | 
				
			||||||
          onChangeUserInfo(data, done);
 | 
					          onChangeUserInfo(data, done);
 | 
				
			||||||
        })}
 | 
					        })}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <UserInfoInput
 | 
					        <UserInfoInput
 | 
				
			||||||
          ref={register({ required: 'Full name is required' })}
 | 
					          {...register('full_name', { required: 'Full name is required' })}
 | 
				
			||||||
          name="full_name"
 | 
					 | 
				
			||||||
          defaultValue={profile.fullName}
 | 
					          defaultValue={profile.fullName}
 | 
				
			||||||
          width="100%"
 | 
					          width="100%"
 | 
				
			||||||
          label="Name"
 | 
					          label="Name"
 | 
				
			||||||
@@ -356,11 +363,10 @@ const UserInfoTab: React.FC<UserInfoTabProps> = ({
 | 
				
			|||||||
        {errors.full_name && <FormError>{errors.full_name.message}</FormError>}
 | 
					        {errors.full_name && <FormError>{errors.full_name.message}</FormError>}
 | 
				
			||||||
        <UserInfoInput
 | 
					        <UserInfoInput
 | 
				
			||||||
          defaultValue={profile.profileIcon && profile.profileIcon.initials ? profile.profileIcon.initials : ''}
 | 
					          defaultValue={profile.profileIcon && profile.profileIcon.initials ? profile.profileIcon.initials : ''}
 | 
				
			||||||
          ref={register({
 | 
					          {...register('initials', {
 | 
				
			||||||
            required: 'Initials is required',
 | 
					            required: 'Initials is required',
 | 
				
			||||||
            pattern: { value: INITIALS_PATTERN, message: 'Intials must be between two to four characters' },
 | 
					            pattern: { value: INITIALS_PATTERN, message: 'Intials must be between two to four characters' },
 | 
				
			||||||
          })}
 | 
					          })}
 | 
				
			||||||
          name="initials"
 | 
					 | 
				
			||||||
          width="100%"
 | 
					          width="100%"
 | 
				
			||||||
          label="Initials "
 | 
					          label="Initials "
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
@@ -368,8 +374,7 @@ const UserInfoTab: React.FC<UserInfoTabProps> = ({
 | 
				
			|||||||
        <UserInfoInput disabled defaultValue={profile.username ?? ''} width="100%" label="Username " />
 | 
					        <UserInfoInput disabled defaultValue={profile.username ?? ''} width="100%" label="Username " />
 | 
				
			||||||
        <UserInfoInput
 | 
					        <UserInfoInput
 | 
				
			||||||
          width="100%"
 | 
					          width="100%"
 | 
				
			||||||
          name="email"
 | 
					          {...register('email', {
 | 
				
			||||||
          ref={register({
 | 
					 | 
				
			||||||
            required: 'Email is required',
 | 
					            required: 'Email is required',
 | 
				
			||||||
            pattern: { value: EMAIL_PATTERN, message: 'Must be a valid email' },
 | 
					            pattern: { value: EMAIL_PATTERN, message: 'Must be a valid email' },
 | 
				
			||||||
          })}
 | 
					          })}
 | 
				
			||||||
@@ -377,7 +382,7 @@ const UserInfoTab: React.FC<UserInfoTabProps> = ({
 | 
				
			|||||||
          label="Email"
 | 
					          label="Email"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        {errors.email && <FormError>{errors.email.message}</FormError>}
 | 
					        {errors.email && <FormError>{errors.email.message}</FormError>}
 | 
				
			||||||
        <UserInfoInput width="100%" name="bio" ref={register()} defaultValue={profile.bio ?? ''} label="Bio" />
 | 
					        <UserInfoInput width="100%" {...register('bio')} defaultValue={profile.bio ?? ''} label="Bio" />
 | 
				
			||||||
        {errors.bio && <FormError>{errors.bio.message}</FormError>}
 | 
					        {errors.bio && <FormError>{errors.bio.message}</FormError>}
 | 
				
			||||||
        <SettingActions>
 | 
					        <SettingActions>
 | 
				
			||||||
          <SaveButton disabled={!active} type="submit">
 | 
					          <SaveButton disabled={!active} type="submit">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,7 +136,7 @@ const StreamComment: React.FC<StreamCommentProps> = ({
 | 
				
			|||||||
                  onCreateComment={onUpdateComment}
 | 
					                  onCreateComment={onUpdateComment}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              ) : (
 | 
					              ) : (
 | 
				
			||||||
                <ReactMarkdown escapeHtml={false} plugins={[em]}>
 | 
					                <ReactMarkdown skipHtml plugins={[em]}>
 | 
				
			||||||
                  {DOMPurify.sanitize(comment.message, { FORBID_TAGS: ['style', 'img'] })}
 | 
					                  {DOMPurify.sanitize(comment.message, { FORBID_TAGS: ['style', 'img'] })}
 | 
				
			||||||
                </ReactMarkdown>
 | 
					                </ReactMarkdown>
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
@@ -300,7 +300,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
  const activityStream: Array<{ id: string; data: { time: string; type: 'comment' | 'activity' } }> = [];
 | 
					  const activityStream: Array<{ id: string; data: { time: string; type: 'comment' | 'activity' } }> = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (task.activity) {
 | 
					  if (task.activity) {
 | 
				
			||||||
    task.activity.forEach(activity => {
 | 
					    task.activity.forEach((activity) => {
 | 
				
			||||||
      activityStream.push({
 | 
					      activityStream.push({
 | 
				
			||||||
        id: activity.id,
 | 
					        id: activity.id,
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
@@ -312,7 +312,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (task.comments) {
 | 
					  if (task.comments) {
 | 
				
			||||||
    task.comments.forEach(comment => {
 | 
					    task.comments.forEach((comment) => {
 | 
				
			||||||
      activityStream.push({
 | 
					      activityStream.push({
 | 
				
			||||||
        id: comment.id,
 | 
					        id: comment.id,
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
@@ -358,12 +358,12 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
            <DueDateTitle>MEMBERS</DueDateTitle>
 | 
					            <DueDateTitle>MEMBERS</DueDateTitle>
 | 
				
			||||||
            {task.assigned && task.assigned.length !== 0 ? (
 | 
					            {task.assigned && task.assigned.length !== 0 ? (
 | 
				
			||||||
              <MemberList>
 | 
					              <MemberList>
 | 
				
			||||||
                {task.assigned.map(m => (
 | 
					                {task.assigned.map((m) => (
 | 
				
			||||||
                  <TaskMember
 | 
					                  <TaskMember
 | 
				
			||||||
                    key={m.id}
 | 
					                    key={m.id}
 | 
				
			||||||
                    member={m}
 | 
					                    member={m}
 | 
				
			||||||
                    size={32}
 | 
					                    size={32}
 | 
				
			||||||
                    onMemberProfile={$target => {
 | 
					                    onMemberProfile={($target) => {
 | 
				
			||||||
                      if (user) {
 | 
					                      if (user) {
 | 
				
			||||||
                        onMemberProfile($target, m.id);
 | 
					                        onMemberProfile($target, m.id);
 | 
				
			||||||
                      }
 | 
					                      }
 | 
				
			||||||
@@ -401,7 +401,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
            <ExtraActionsSection>
 | 
					            <ExtraActionsSection>
 | 
				
			||||||
              <DueDateTitle>ACTIONS</DueDateTitle>
 | 
					              <DueDateTitle>ACTIONS</DueDateTitle>
 | 
				
			||||||
              <ActionButton
 | 
					              <ActionButton
 | 
				
			||||||
                onClick={$target => {
 | 
					                onClick={($target) => {
 | 
				
			||||||
                  onOpenAddLabelPopup(task, $target);
 | 
					                  onOpenAddLabelPopup(task, $target);
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
                icon={<Tags width={12} height={12} />}
 | 
					                icon={<Tags width={12} height={12} />}
 | 
				
			||||||
@@ -409,7 +409,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
                Labels
 | 
					                Labels
 | 
				
			||||||
              </ActionButton>
 | 
					              </ActionButton>
 | 
				
			||||||
              <ActionButton
 | 
					              <ActionButton
 | 
				
			||||||
                onClick={$target => {
 | 
					                onClick={($target) => {
 | 
				
			||||||
                  onOpenAddChecklistPopup(task, $target);
 | 
					                  onOpenAddChecklistPopup(task, $target);
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
                icon={<CheckSquareOutline width={12} height={12} />}
 | 
					                icon={<CheckSquareOutline width={12} height={12} />}
 | 
				
			||||||
@@ -460,7 +460,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
              value={taskName}
 | 
					              value={taskName}
 | 
				
			||||||
              ref={$detailsTitle}
 | 
					              ref={$detailsTitle}
 | 
				
			||||||
              disabled={user === null}
 | 
					              disabled={user === null}
 | 
				
			||||||
              onKeyDown={e => {
 | 
					              onKeyDown={(e) => {
 | 
				
			||||||
                if (e.keyCode === 13) {
 | 
					                if (e.keyCode === 13) {
 | 
				
			||||||
                  e.preventDefault();
 | 
					                  e.preventDefault();
 | 
				
			||||||
                  if ($detailsTitle && $detailsTitle.current) {
 | 
					                  if ($detailsTitle && $detailsTitle.current) {
 | 
				
			||||||
@@ -468,7 +468,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
                  }
 | 
					                  }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onChange={e => {
 | 
					              onChange={(e) => {
 | 
				
			||||||
                setTaskName(e.currentTarget.value);
 | 
					                setTaskName(e.currentTarget.value);
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onBlur={() => {
 | 
					              onBlur={() => {
 | 
				
			||||||
@@ -481,12 +481,12 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
          <Labels>
 | 
					          <Labels>
 | 
				
			||||||
            {task.labels.length !== 0 && (
 | 
					            {task.labels.length !== 0 && (
 | 
				
			||||||
              <MetaDetailContent>
 | 
					              <MetaDetailContent>
 | 
				
			||||||
                {task.labels.map(label => {
 | 
					                {task.labels.map((label) => {
 | 
				
			||||||
                  return (
 | 
					                  return (
 | 
				
			||||||
                    <TaskLabelItem
 | 
					                    <TaskLabelItem
 | 
				
			||||||
                      key={label.projectLabel.id}
 | 
					                      key={label.projectLabel.id}
 | 
				
			||||||
                      label={label}
 | 
					                      label={label}
 | 
				
			||||||
                      onClick={$target => {
 | 
					                      onClick={($target) => {
 | 
				
			||||||
                        onOpenAddLabelPopup(task, $target);
 | 
					                        onOpenAddLabelPopup(task, $target);
 | 
				
			||||||
                      }}
 | 
					                      }}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
@@ -505,7 +505,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
              <TaskDetailsEditor value={taskDescriptionRef.current} />
 | 
					              <TaskDetailsEditor value={taskDescriptionRef.current} />
 | 
				
			||||||
            ) : (
 | 
					            ) : (
 | 
				
			||||||
              <EditorContainer
 | 
					              <EditorContainer
 | 
				
			||||||
                onClick={e => {
 | 
					                onClick={(e) => {
 | 
				
			||||||
                  if (!editTaskDescription) {
 | 
					                  if (!editTaskDescription) {
 | 
				
			||||||
                    setEditTaskDescription(true);
 | 
					                    setEditTaskDescription(true);
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
@@ -513,10 +513,10 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
              >
 | 
					              >
 | 
				
			||||||
                <Editor
 | 
					                <Editor
 | 
				
			||||||
                  defaultValue={task.description ?? ''}
 | 
					                  defaultValue={task.description ?? ''}
 | 
				
			||||||
                  theme={dark}
 | 
					 | 
				
			||||||
                  readOnly={user === null || !editTaskDescription}
 | 
					                  readOnly={user === null || !editTaskDescription}
 | 
				
			||||||
                  autoFocus
 | 
					                  autoFocus
 | 
				
			||||||
                  onChange={value => {
 | 
					                  theme={dark}
 | 
				
			||||||
 | 
					                  onChange={(value) => {
 | 
				
			||||||
                    setSaveTimeout(() => {
 | 
					                    setSaveTimeout(() => {
 | 
				
			||||||
                      clearTimeout(saveTimeout);
 | 
					                      clearTimeout(saveTimeout);
 | 
				
			||||||
                      return setTimeout(saveDescription, 2000);
 | 
					                      return setTimeout(saveDescription, 2000);
 | 
				
			||||||
@@ -531,9 +531,9 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
            <ViewRawButton onClick={() => setShowRaw(!showRaw)}>{showRaw ? 'Show editor' : 'Show raw'}</ViewRawButton>
 | 
					            <ViewRawButton onClick={() => setShowRaw(!showRaw)}>{showRaw ? 'Show editor' : 'Show raw'}</ViewRawButton>
 | 
				
			||||||
          </DescriptionContainer>
 | 
					          </DescriptionContainer>
 | 
				
			||||||
          <ChecklistSection>
 | 
					          <ChecklistSection>
 | 
				
			||||||
            <DragDropContext onDragEnd={result => onDragEnd(result, task, onChecklistDrop, onChecklistItemDrop)}>
 | 
					            <DragDropContext onDragEnd={(result) => onDragEnd(result, task, onChecklistDrop, onChecklistItemDrop)}>
 | 
				
			||||||
              <Droppable direction="vertical" type="checklist" droppableId="root">
 | 
					              <Droppable direction="vertical" type="checklist" droppableId="root">
 | 
				
			||||||
                {dropProvided => (
 | 
					                {(dropProvided) => (
 | 
				
			||||||
                  <ChecklistContainer {...dropProvided.droppableProps} ref={dropProvided.innerRef}>
 | 
					                  <ChecklistContainer {...dropProvided.droppableProps} ref={dropProvided.innerRef}>
 | 
				
			||||||
                    {task.checklists &&
 | 
					                    {task.checklists &&
 | 
				
			||||||
                      task.checklists
 | 
					                      task.checklists
 | 
				
			||||||
@@ -541,7 +541,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
                        .sort((a, b) => a.position - b.position)
 | 
					                        .sort((a, b) => a.position - b.position)
 | 
				
			||||||
                        .map((checklist, idx) => (
 | 
					                        .map((checklist, idx) => (
 | 
				
			||||||
                          <Draggable key={checklist.id} draggableId={checklist.id} index={idx}>
 | 
					                          <Draggable key={checklist.id} draggableId={checklist.id} index={idx}>
 | 
				
			||||||
                            {provided => (
 | 
					                            {(provided) => (
 | 
				
			||||||
                              <Checklist
 | 
					                              <Checklist
 | 
				
			||||||
                                ref={provided.innerRef}
 | 
					                                ref={provided.innerRef}
 | 
				
			||||||
                                wrapperProps={provided.draggableProps}
 | 
					                                wrapperProps={provided.draggableProps}
 | 
				
			||||||
@@ -551,10 +551,10 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
                                checklistID={checklist.id}
 | 
					                                checklistID={checklist.id}
 | 
				
			||||||
                                items={checklist.items}
 | 
					                                items={checklist.items}
 | 
				
			||||||
                                onDeleteChecklist={onDeleteChecklist}
 | 
					                                onDeleteChecklist={onDeleteChecklist}
 | 
				
			||||||
                                onChangeName={newName => onChangeChecklistName(checklist.id, newName)}
 | 
					                                onChangeName={(newName) => onChangeChecklistName(checklist.id, newName)}
 | 
				
			||||||
                                onToggleItem={onToggleChecklistItem}
 | 
					                                onToggleItem={onToggleChecklistItem}
 | 
				
			||||||
                                onDeleteItem={onDeleteItem}
 | 
					                                onDeleteItem={onDeleteItem}
 | 
				
			||||||
                                onAddItem={n => {
 | 
					                                onAddItem={(n) => {
 | 
				
			||||||
                                  if (task.checklists) {
 | 
					                                  if (task.checklists) {
 | 
				
			||||||
                                    let position = 65535;
 | 
					                                    let position = 65535;
 | 
				
			||||||
                                    const [lastItem] = checklist.items
 | 
					                                    const [lastItem] = checklist.items
 | 
				
			||||||
@@ -569,7 +569,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
                                onChangeItemName={onChangeItemName}
 | 
					                                onChangeItemName={onChangeItemName}
 | 
				
			||||||
                              >
 | 
					                              >
 | 
				
			||||||
                                <Droppable direction="vertical" type="checklistItem" droppableId={checklist.id}>
 | 
					                                <Droppable direction="vertical" type="checklistItem" droppableId={checklist.id}>
 | 
				
			||||||
                                  {checklistDrop => (
 | 
					                                  {(checklistDrop) => (
 | 
				
			||||||
                                    <>
 | 
					                                    <>
 | 
				
			||||||
                                      <ChecklistItems ref={checklistDrop.innerRef} {...checklistDrop.droppableProps}>
 | 
					                                      <ChecklistItems ref={checklistDrop.innerRef} {...checklistDrop.droppableProps}>
 | 
				
			||||||
                                        {checklist.items
 | 
					                                        {checklist.items
 | 
				
			||||||
@@ -577,7 +577,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
                                          .sort((a, b) => a.position - b.position)
 | 
					                                          .sort((a, b) => a.position - b.position)
 | 
				
			||||||
                                          .map((item, itemIdx) => (
 | 
					                                          .map((item, itemIdx) => (
 | 
				
			||||||
                                            <Draggable key={item.id} draggableId={item.id} index={itemIdx}>
 | 
					                                            <Draggable key={item.id} draggableId={item.id} index={itemIdx}>
 | 
				
			||||||
                                              {itemDrop => (
 | 
					                                              {(itemDrop) => (
 | 
				
			||||||
                                                <ChecklistItem
 | 
					                                                <ChecklistItem
 | 
				
			||||||
                                                  key={item.id}
 | 
					                                                  key={item.id}
 | 
				
			||||||
                                                  itemID={item.id}
 | 
					                                                  itemID={item.id}
 | 
				
			||||||
@@ -615,17 +615,19 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
            <TabBarItem>Activity</TabBarItem>
 | 
					            <TabBarItem>Activity</TabBarItem>
 | 
				
			||||||
          </TabBarSection>
 | 
					          </TabBarSection>
 | 
				
			||||||
          <ActivitySection>
 | 
					          <ActivitySection>
 | 
				
			||||||
            {activityStream.map(stream =>
 | 
					            {activityStream.map((stream) =>
 | 
				
			||||||
              stream.data.type === 'comment' ? (
 | 
					              stream.data.type === 'comment' ? (
 | 
				
			||||||
                <StreamComment
 | 
					                <StreamComment
 | 
				
			||||||
                  onExtraActions={onCommentShowActions}
 | 
					                  onExtraActions={onCommentShowActions}
 | 
				
			||||||
                  onCancelCommentEdit={onCancelCommentEdit}
 | 
					                  onCancelCommentEdit={onCancelCommentEdit}
 | 
				
			||||||
                  onUpdateComment={message => onUpdateComment(stream.id, message)}
 | 
					                  onUpdateComment={(message) => onUpdateComment(stream.id, message)}
 | 
				
			||||||
                  editable={stream.id === editableComment}
 | 
					                  editable={stream.id === editableComment}
 | 
				
			||||||
                  comment={task.comments && task.comments.find(comment => comment.id === stream.id)}
 | 
					                  comment={task.comments && task.comments.find((comment) => comment.id === stream.id)}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              ) : (
 | 
					              ) : (
 | 
				
			||||||
                <StreamActivity activity={task.activity && task.activity.find(activity => activity.id === stream.id)} />
 | 
					                <StreamActivity
 | 
				
			||||||
 | 
					                  activity={task.activity && task.activity.find((activity) => activity.id === stream.id)}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
          </ActivitySection>
 | 
					          </ActivitySection>
 | 
				
			||||||
@@ -634,7 +636,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
          <CommentContainer>
 | 
					          <CommentContainer>
 | 
				
			||||||
            <CommentCreator
 | 
					            <CommentCreator
 | 
				
			||||||
              me={me}
 | 
					              me={me}
 | 
				
			||||||
              onCreateComment={message => onCreateComment(task, message)}
 | 
					              onCreateComment={(message) => onCreateComment(task, message)}
 | 
				
			||||||
              onMemberProfile={onMemberProfile}
 | 
					              onMemberProfile={onMemberProfile}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </CommentContainer>
 | 
					          </CommentContainer>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,15 @@
 | 
				
			|||||||
import theme from 'App/ThemeStyles';
 | 
					import theme from 'App/ThemeStyles';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const colors = {
 | 
					const colors = {
 | 
				
			||||||
  almostBlack: '#181A1B',
 | 
					  almostBlack: 'rgb(38, 44, 73)',
 | 
				
			||||||
  lightBlack: '#2F3336',
 | 
					  lightBlack: 'rgb(16, 22, 58)',
 | 
				
			||||||
  almostWhite: '#E6E6E6',
 | 
					  bgPrimary: 'rgb(16, 22, 58)',
 | 
				
			||||||
 | 
					  almostWhite: 'rgb(194, 198, 220)',
 | 
				
			||||||
  white: '#FFF',
 | 
					  white: '#FFF',
 | 
				
			||||||
  white10: 'rgba(255, 255, 255, 0.1)',
 | 
					  white10: 'rgb(194, 198, 220)',
 | 
				
			||||||
  black: '#000',
 | 
					  black: '#000',
 | 
				
			||||||
  black10: 'rgba(0, 0, 0, 0.1)',
 | 
					  black10: 'rgba(0, 0, 0, 0.1)',
 | 
				
			||||||
  primary: '#1AB6FF',
 | 
					  primary: 'rgb(115, 103, 240)',
 | 
				
			||||||
  greyLight: '#F4F7FA',
 | 
					  greyLight: '#F4F7FA',
 | 
				
			||||||
  grey: '#E8EBED',
 | 
					  grey: '#E8EBED',
 | 
				
			||||||
  greyMid: '#C5CCD3',
 | 
					  greyMid: '#C5CCD3',
 | 
				
			||||||
@@ -17,15 +18,16 @@ const colors = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const base = {
 | 
					export const base = {
 | 
				
			||||||
  ...colors,
 | 
					  ...colors,
 | 
				
			||||||
  fontFamily: "'Open Sans', sans-serif",
 | 
					  fontFamily: 'Open Sans',
 | 
				
			||||||
  fontFamilyMono: "'SFMono-Regular',Consolas,'Liberation Mono', Menlo, Courier,monospace",
 | 
					  fontFamilyMono: "'SFMono-Regular',Consolas,'Liberation Mono', Menlo, Courier,monospace",
 | 
				
			||||||
  fontWeight: 400,
 | 
					  fontWeight: 400,
 | 
				
			||||||
  zIndex: 10000,
 | 
					  zIndex: 1000000,
 | 
				
			||||||
  link: colors.primary,
 | 
					  link: colors.primary,
 | 
				
			||||||
  placeholder: '#B1BECC',
 | 
					  placeholder: '#B1BECC',
 | 
				
			||||||
  textSecondary: '#4E5C6E',
 | 
					  textSecondary: '#fff',
 | 
				
			||||||
  textLight: colors.white,
 | 
					  textLight: colors.white,
 | 
				
			||||||
  textHighlight: '#b3e7ff',
 | 
					  textHighlight: '#b3e7ff',
 | 
				
			||||||
 | 
					  textHighlightForeground: colors.white,
 | 
				
			||||||
  selected: colors.primary,
 | 
					  selected: colors.primary,
 | 
				
			||||||
  codeComment: '#6a737d',
 | 
					  codeComment: '#6a737d',
 | 
				
			||||||
  codePunctuation: '#5e6687',
 | 
					  codePunctuation: '#5e6687',
 | 
				
			||||||
@@ -43,13 +45,13 @@ export const base = {
 | 
				
			|||||||
  codeInserted: '#202746',
 | 
					  codeInserted: '#202746',
 | 
				
			||||||
  codeImportant: '#c94922',
 | 
					  codeImportant: '#c94922',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  blockToolbarBackground: colors.white,
 | 
					  blockToolbarBackground: colors.bgPrimary,
 | 
				
			||||||
  blockToolbarTrigger: colors.greyMid,
 | 
					  blockToolbarTrigger: colors.white,
 | 
				
			||||||
  blockToolbarTriggerIcon: colors.white,
 | 
					  blockToolbarTriggerIcon: colors.white,
 | 
				
			||||||
  blockToolbarItem: colors.almostBlack,
 | 
					  blockToolbarItem: colors.white,
 | 
				
			||||||
  blockToolbarText: colors.almostBlack,
 | 
					  blockToolbarText: colors.white,
 | 
				
			||||||
  blockToolbarHoverBackground: colors.greyLight,
 | 
					  blockToolbarHoverBackground: colors.primary,
 | 
				
			||||||
  blockToolbarDivider: colors.greyMid,
 | 
					  blockToolbarDivider: colors.almostWhite,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  noticeInfoBackground: '#F5BE31',
 | 
					  noticeInfoBackground: '#F5BE31',
 | 
				
			||||||
  noticeInfoText: colors.almostBlack,
 | 
					  noticeInfoText: colors.almostBlack,
 | 
				
			||||||
@@ -58,18 +60,20 @@ export const base = {
 | 
				
			|||||||
  noticeWarningBackground: '#FF5C80',
 | 
					  noticeWarningBackground: '#FF5C80',
 | 
				
			||||||
  noticeWarningText: colors.white,
 | 
					  noticeWarningText: colors.white,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const dark = {
 | 
					export const dark = {
 | 
				
			||||||
  ...base,
 | 
					  ...base,
 | 
				
			||||||
  background: 'transparent',
 | 
					  background: colors.almostBlack,
 | 
				
			||||||
  text: `${theme.colors.text.primary}`,
 | 
					  text: colors.almostWhite,
 | 
				
			||||||
  code: `${theme.colors.text.primary}`,
 | 
					  code: colors.almostWhite,
 | 
				
			||||||
  cursor: `${theme.colors.text.primary}`,
 | 
					  cursor: colors.white,
 | 
				
			||||||
  divider: '#4E5C6E',
 | 
					  divider: '#4E5C6E',
 | 
				
			||||||
  placeholder: '#52657A',
 | 
					  placeholder: '#52657A',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  toolbarBackground: colors.white,
 | 
					  toolbarBackground: colors.bgPrimary,
 | 
				
			||||||
  toolbarInput: colors.black10,
 | 
					  toolbarHoverBackground: colors.primary,
 | 
				
			||||||
  toolbarItem: colors.lightBlack,
 | 
					  toolbarInput: colors.almostWhite,
 | 
				
			||||||
 | 
					  toolbarItem: colors.white,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  tableDivider: colors.lightBlack,
 | 
					  tableDivider: colors.lightBlack,
 | 
				
			||||||
  tableSelected: colors.primary,
 | 
					  tableSelected: colors.primary,
 | 
				
			||||||
@@ -81,6 +85,9 @@ export const dark = {
 | 
				
			|||||||
  codeString: '#3d8fd1',
 | 
					  codeString: '#3d8fd1',
 | 
				
			||||||
  horizontalRule: colors.lightBlack,
 | 
					  horizontalRule: colors.lightBlack,
 | 
				
			||||||
  imageErrorBackground: 'rgba(0, 0, 0, 0.5)',
 | 
					  imageErrorBackground: 'rgba(0, 0, 0, 0.5)',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  scrollbarBackground: colors.black,
 | 
				
			||||||
 | 
					  scrollbarThumb: colors.lightBlack,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default dark;
 | 
					export default dark;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,9 @@
 | 
				
			|||||||
    "resolveJsonModule": true,
 | 
					    "resolveJsonModule": true,
 | 
				
			||||||
    "isolatedModules": true,
 | 
					    "isolatedModules": true,
 | 
				
			||||||
    "noEmit": true,
 | 
					    "noEmit": true,
 | 
				
			||||||
    "jsx": "react",
 | 
					    "jsx": "react-jsx",
 | 
				
			||||||
    "baseUrl": "src"
 | 
					    "baseUrl": "src",
 | 
				
			||||||
 | 
					    "noFallthroughCasesInSwitch": true
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "include": [
 | 
					  "include": [
 | 
				
			||||||
    "src"
 | 
					    "src"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9047
									
								
								frontend/yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										9047
									
								
								frontend/yarn.lock
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user