Compare commits
	
		
			2 Commits
		
	
	
		
			feat/updat
			...
			feat/list-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0eb9c0db94 | ||
| 
						 | 
					cdcccbfb4a | 
@@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 | 
				
			|||||||
### Added
 | 
					### Added
 | 
				
			||||||
- Task sorting & filtering
 | 
					- Task sorting & filtering
 | 
				
			||||||
- Redesigned the Task Details UI
 | 
					- Redesigned the Task Details UI
 | 
				
			||||||
- Implement task group actions (duplicate/delete all tasks/sort)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Fixed
 | 
					### Fixed
 | 
				
			||||||
- removed CORS middleware to fix security issue
 | 
					- removed CORS middleware to fix security issue
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,8 +21,6 @@ Was this project useful? Please consider <a href="https://www.buymeacoffee.com/j
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
**Please note that this project is still in active development. Some options may not work yet! For updates on development, join the Discord server**
 | 
					**Please note that this project is still in active development. Some options may not work yet! For updates on development, join the Discord server**
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Features
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Currently Taskcafe only offers basic task tracking through a Kanban board.
 | 
					Currently Taskcafe only offers basic task tracking through a Kanban board.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -171,7 +171,7 @@ const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const AdminRoute = () => {
 | 
					const AdminRoute = () => {
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    document.title = 'Admin | Taskcafé';
 | 
					    document.title = 'Taskcafé | Admin';
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
  const { loading, data } = useUsersQuery();
 | 
					  const { loading, data } = useUsersQuery();
 | 
				
			||||||
  const { showPopup, hidePopup } = usePopup();
 | 
					  const { showPopup, hidePopup } = usePopup();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,20 +3,11 @@ import styled from 'styled-components/macro';
 | 
				
			|||||||
import GlobalTopNavbar from 'App/TopNavbar';
 | 
					import GlobalTopNavbar from 'App/TopNavbar';
 | 
				
			||||||
import { getAccessToken } from 'shared/utils/accessToken';
 | 
					import { getAccessToken } from 'shared/utils/accessToken';
 | 
				
			||||||
import Settings from 'shared/components/Settings';
 | 
					import Settings from 'shared/components/Settings';
 | 
				
			||||||
import {
 | 
					import { useMeQuery, useClearProfileAvatarMutation, useUpdateUserPasswordMutation } from 'shared/generated/graphql';
 | 
				
			||||||
  useMeQuery,
 | 
					 | 
				
			||||||
  useClearProfileAvatarMutation,
 | 
					 | 
				
			||||||
  useUpdateUserPasswordMutation,
 | 
					 | 
				
			||||||
  useUpdateUserInfoMutation,
 | 
					 | 
				
			||||||
  MeQuery,
 | 
					 | 
				
			||||||
  MeDocument,
 | 
					 | 
				
			||||||
} from 'shared/generated/graphql';
 | 
					 | 
				
			||||||
import axios from 'axios';
 | 
					import axios from 'axios';
 | 
				
			||||||
import { useCurrentUser } from 'App/context';
 | 
					import { useCurrentUser } from 'App/context';
 | 
				
			||||||
import NOOP from 'shared/utils/noop';
 | 
					import NOOP from 'shared/utils/noop';
 | 
				
			||||||
import { toast } from 'react-toastify';
 | 
					import { toast } from 'react-toastify';
 | 
				
			||||||
import updateApolloCache from 'shared/utils/cache';
 | 
					 | 
				
			||||||
import produce from 'immer';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MainContent = styled.div`
 | 
					const MainContent = styled.div`
 | 
				
			||||||
  padding: 0 0 50px 80px;
 | 
					  padding: 0 0 50px 80px;
 | 
				
			||||||
@@ -28,7 +19,6 @@ const Projects = () => {
 | 
				
			|||||||
  const $fileUpload = useRef<HTMLInputElement>(null);
 | 
					  const $fileUpload = useRef<HTMLInputElement>(null);
 | 
				
			||||||
  const [clearProfileAvatar] = useClearProfileAvatarMutation();
 | 
					  const [clearProfileAvatar] = useClearProfileAvatarMutation();
 | 
				
			||||||
  const { user } = useCurrentUser();
 | 
					  const { user } = useCurrentUser();
 | 
				
			||||||
  const [updateUserInfo] = useUpdateUserInfoMutation();
 | 
					 | 
				
			||||||
  const [updateUserPassword] = useUpdateUserPasswordMutation();
 | 
					  const [updateUserPassword] = useUpdateUserPasswordMutation();
 | 
				
			||||||
  const { loading, data, refetch } = useMeQuery();
 | 
					  const { loading, data, refetch } = useMeQuery();
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
@@ -79,13 +69,6 @@ const Projects = () => {
 | 
				
			|||||||
            toast('Password was changed!');
 | 
					            toast('Password was changed!');
 | 
				
			||||||
            done();
 | 
					            done();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onChangeUserInfo={(d, done) => {
 | 
					 | 
				
			||||||
            updateUserInfo({
 | 
					 | 
				
			||||||
              variables: { name: d.full_name, bio: d.bio, email: d.email, initials: d.initials },
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            toast('User info was saved!');
 | 
					 | 
				
			||||||
            done();
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
          onProfileAvatarRemove={() => {
 | 
					          onProfileAvatarRemove={() => {
 | 
				
			||||||
            clearProfileAvatar();
 | 
					            clearProfileAvatar();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -323,7 +323,6 @@ const ProjectBoard: React.FC<ProjectBoardProps> = ({ projectID, onCardLabelClick
 | 
				
			|||||||
  const [updateTaskGroupName] = useUpdateTaskGroupNameMutation({});
 | 
					  const [updateTaskGroupName] = useUpdateTaskGroupNameMutation({});
 | 
				
			||||||
  const { loading, data } = useFindProjectQuery({
 | 
					  const { loading, data } = useFindProjectQuery({
 | 
				
			||||||
    variables: { projectID },
 | 
					    variables: { projectID },
 | 
				
			||||||
    pollInterval: 5000,
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const [deleteTaskGroupTasks] = useDeleteTaskGroupTasksMutation({
 | 
					  const [deleteTaskGroupTasks] = useDeleteTaskGroupTasksMutation({
 | 
				
			||||||
    update: (client, resp) =>
 | 
					    update: (client, resp) =>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import Modal from 'shared/components/Modal';
 | 
				
			|||||||
import TaskDetails from 'shared/components/TaskDetails';
 | 
					import TaskDetails from 'shared/components/TaskDetails';
 | 
				
			||||||
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, Redirect } from 'react-router';
 | 
					import { useRouteMatch, useHistory } from 'react-router';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  useDeleteTaskChecklistMutation,
 | 
					  useDeleteTaskChecklistMutation,
 | 
				
			||||||
  useUpdateTaskChecklistNameMutation,
 | 
					  useUpdateTaskChecklistNameMutation,
 | 
				
			||||||
@@ -32,7 +32,6 @@ import Input from 'shared/components/Input';
 | 
				
			|||||||
import { useForm } from 'react-hook-form';
 | 
					import { useForm } from 'react-hook-form';
 | 
				
			||||||
import updateApolloCache from 'shared/utils/cache';
 | 
					import updateApolloCache from 'shared/utils/cache';
 | 
				
			||||||
import NOOP from 'shared/utils/noop';
 | 
					import NOOP from 'shared/utils/noop';
 | 
				
			||||||
import hasNotFoundError from 'shared/utils/error';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const calculateChecklistBadge = (checklists: Array<TaskChecklist>) => {
 | 
					const calculateChecklistBadge = (checklists: Array<TaskChecklist>) => {
 | 
				
			||||||
  const total = checklists.reduce((prev: any, next: any) => {
 | 
					  const total = checklists.reduce((prev: any, next: any) => {
 | 
				
			||||||
@@ -270,8 +269,8 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const { loading, data, refetch, error } = useFindTaskQuery({ variables: { taskID }, pollInterval: 5000 });
 | 
					  const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
 | 
				
			||||||
  const [setTaskComplete, { error: setTaskCompleteError }] = useSetTaskCompleteMutation();
 | 
					  const [setTaskComplete] = useSetTaskCompleteMutation();
 | 
				
			||||||
  const [updateTaskDueDate] = useUpdateTaskDueDateMutation({
 | 
					  const [updateTaskDueDate] = useUpdateTaskDueDateMutation({
 | 
				
			||||||
    onCompleted: () => {
 | 
					    onCompleted: () => {
 | 
				
			||||||
      refetch();
 | 
					      refetch();
 | 
				
			||||||
@@ -290,13 +289,9 @@ const Details: React.FC<DetailsProps> = ({
 | 
				
			|||||||
      refreshCache();
 | 
					      refreshCache();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  if (hasNotFoundError(error, setTaskCompleteError)) {
 | 
					  if (loading) {
 | 
				
			||||||
    return <Redirect to={projectURL} />;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (setTaskCompleteError && setTaskCompleteError)
 | 
					 | 
				
			||||||
    if (loading) {
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  if (!data) {
 | 
					  if (!data) {
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -351,11 +346,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 } }).catch(r => {
 | 
					                setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } });
 | 
				
			||||||
                  if (hasNotFoundError(r)) {
 | 
					 | 
				
			||||||
                    history.push(projectURL);
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              onDeleteTask={onDeleteTask}
 | 
					              onDeleteTask={onDeleteTask}
 | 
				
			||||||
              onChangeItemName={(itemID, itemName) => {
 | 
					              onChangeItemName={(itemID, itemName) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -234,7 +234,7 @@ type ShowNewProject = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const Projects = () => {
 | 
					const Projects = () => {
 | 
				
			||||||
  const { showPopup, hidePopup } = usePopup();
 | 
					  const { showPopup, hidePopup } = usePopup();
 | 
				
			||||||
  const { loading, data } = useGetProjectsQuery({ fetchPolicy: 'network-only', pollInterval: 5000 });
 | 
					  const { loading, data } = useGetProjectsQuery({ fetchPolicy: 'network-only' });
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    document.title = 'Taskcafé';
 | 
					    document.title = 'Taskcafé';
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
@@ -260,7 +260,11 @@ const Projects = () => {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  if (loading) {
 | 
					  if (loading) {
 | 
				
			||||||
    return <GlobalTopNavbar onSaveProjectName={NOOP} projectID={null} name={null} />;
 | 
					    return (
 | 
				
			||||||
 | 
					      <>
 | 
				
			||||||
 | 
					        <span>loading</span>
 | 
				
			||||||
 | 
					      </>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const colors = ['#e362e3', '#7a6ff0', '#37c5ab', '#aa62e3', '#e8384f'];
 | 
					  const colors = ['#e362e3', '#7a6ff0', '#37c5ab', '#aa62e3', '#e8384f'];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -154,7 +154,7 @@ type TeamProjectsProps = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TeamProjects: React.FC<TeamProjectsProps> = ({ teamID }) => {
 | 
					const TeamProjects: React.FC<TeamProjectsProps> = ({ teamID }) => {
 | 
				
			||||||
  const { loading, data } = useGetTeamQuery({ variables: { teamID }, pollInterval: 5000 });
 | 
					  const { loading, data } = useGetTeamQuery({ variables: { teamID } });
 | 
				
			||||||
  if (loading) {
 | 
					  if (loading) {
 | 
				
			||||||
    return <span>loading</span>;
 | 
					    return <span>loading</span>;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,30 +85,18 @@ type TeamsRouteProps = {
 | 
				
			|||||||
const Teams = () => {
 | 
					const Teams = () => {
 | 
				
			||||||
  const { teamID } = useParams<TeamsRouteProps>();
 | 
					  const { teamID } = useParams<TeamsRouteProps>();
 | 
				
			||||||
  const history = useHistory();
 | 
					  const history = useHistory();
 | 
				
			||||||
  const { loading, data } = useGetTeamQuery({
 | 
					  const { loading, data } = useGetTeamQuery({ variables: { teamID } });
 | 
				
			||||||
    variables: { teamID },
 | 
					 | 
				
			||||||
    onCompleted: resp => {
 | 
					 | 
				
			||||||
      document.title = `${resp.findTeam.name} | Taskcafé`;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  const { user } = useCurrentUser();
 | 
					  const { user } = useCurrentUser();
 | 
				
			||||||
  const [currentTab, setCurrentTab] = useState(0);
 | 
					  const [currentTab, setCurrentTab] = useState(0);
 | 
				
			||||||
  const match = useRouteMatch();
 | 
					  const match = useRouteMatch();
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    document.title = 'Teams | Taskcafé';
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
  if (loading) {
 | 
					  if (loading) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <GlobalTopNavbar
 | 
					      <>
 | 
				
			||||||
        menuType={[
 | 
					        <span>loading</span>
 | 
				
			||||||
          { name: 'Projects', link: `${match.url}` },
 | 
					      </>
 | 
				
			||||||
          { name: 'Members', link: `${match.url}/members` },
 | 
					 | 
				
			||||||
        ]}
 | 
					 | 
				
			||||||
        currentTab={currentTab}
 | 
					 | 
				
			||||||
        onSetTab={tab => {
 | 
					 | 
				
			||||||
          setCurrentTab(tab);
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
        onSaveProjectName={NOOP}
 | 
					 | 
				
			||||||
        projectID={null}
 | 
					 | 
				
			||||||
        name={null}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (data && user) {
 | 
					  if (data && user) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -557,7 +557,6 @@ const Admin: React.FC<AdminProps> = ({
 | 
				
			|||||||
        <TabNavContent>
 | 
					        <TabNavContent>
 | 
				
			||||||
          {items.map((item, idx) => (
 | 
					          {items.map((item, idx) => (
 | 
				
			||||||
            <NavItem
 | 
					            <NavItem
 | 
				
			||||||
              key={item.name}
 | 
					 | 
				
			||||||
              onClick={(tab, top) => {
 | 
					              onClick={(tab, top) => {
 | 
				
			||||||
                if ($tabNav && $tabNav.current) {
 | 
					                if ($tabNav && $tabNav.current) {
 | 
				
			||||||
                  const pos = $tabNav.current.getBoundingClientRect();
 | 
					                  const pos = $tabNav.current.getBoundingClientRect();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,11 +147,6 @@ export const ListCardLabelText = styled.span`
 | 
				
			|||||||
  line-height: 16px;
 | 
					  line-height: 16px;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ListCardLabelsWrapper = styled.div`
 | 
					 | 
				
			||||||
  overflow: auto;
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const ListCardLabel = styled.span<{ variant: 'small' | 'large' }>`
 | 
					export const ListCardLabel = styled.span<{ variant: 'small' | 'large' }>`
 | 
				
			||||||
  ${props =>
 | 
					  ${props =>
 | 
				
			||||||
    props.variant === 'small'
 | 
					    props.variant === 'small'
 | 
				
			||||||
@@ -183,6 +178,8 @@ export const ListCardLabel = styled.span<{ variant: 'small' | 'large' }>`
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ListCardLabels = styled.div<{ toggleLabels: boolean; toggleDirection: 'expand' | 'shrink' }>`
 | 
					export const ListCardLabels = styled.div<{ toggleLabels: boolean; toggleDirection: 'expand' | 'shrink' }>`
 | 
				
			||||||
 | 
					  overflow: auto;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    opacity: 0.8;
 | 
					    opacity: 0.8;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,6 @@ import {
 | 
				
			|||||||
  ListCardLabels,
 | 
					  ListCardLabels,
 | 
				
			||||||
  ListCardLabel,
 | 
					  ListCardLabel,
 | 
				
			||||||
  ListCardLabelText,
 | 
					  ListCardLabelText,
 | 
				
			||||||
  ListCardLabelsWrapper,
 | 
					 | 
				
			||||||
  ListCardOperation,
 | 
					  ListCardOperation,
 | 
				
			||||||
  CardTitle,
 | 
					  CardTitle,
 | 
				
			||||||
  CardMembers,
 | 
					  CardMembers,
 | 
				
			||||||
@@ -159,38 +158,35 @@ const Card = React.forwardRef(
 | 
				
			|||||||
            </ListCardOperation>
 | 
					            </ListCardOperation>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
          <ListCardDetails complete={complete ?? false}>
 | 
					          <ListCardDetails complete={complete ?? false}>
 | 
				
			||||||
            {labels && labels.length !== 0 && (
 | 
					            <ListCardLabels
 | 
				
			||||||
              <ListCardLabelsWrapper>
 | 
					              toggleLabels={toggleLabels}
 | 
				
			||||||
                <ListCardLabels
 | 
					              toggleDirection={toggleDirection}
 | 
				
			||||||
                  toggleLabels={toggleLabels}
 | 
					              onClick={e => {
 | 
				
			||||||
                  toggleDirection={toggleDirection}
 | 
					                e.stopPropagation();
 | 
				
			||||||
                  onClick={e => {
 | 
					                if (onCardLabelClick) {
 | 
				
			||||||
                    e.stopPropagation();
 | 
					                  onCardLabelClick();
 | 
				
			||||||
                    if (onCardLabelClick) {
 | 
					                }
 | 
				
			||||||
                      onCardLabelClick();
 | 
					              }}
 | 
				
			||||||
                    }
 | 
					            >
 | 
				
			||||||
                  }}
 | 
					              {labels &&
 | 
				
			||||||
                >
 | 
					                labels
 | 
				
			||||||
                  {labels
 | 
					                  .slice()
 | 
				
			||||||
                    .slice()
 | 
					                  .sort((a, b) => a.labelColor.position - b.labelColor.position)
 | 
				
			||||||
                    .sort((a, b) => a.labelColor.position - b.labelColor.position)
 | 
					                  .map(label => (
 | 
				
			||||||
                    .map(label => (
 | 
					                    <ListCardLabel
 | 
				
			||||||
                      <ListCardLabel
 | 
					                      onAnimationEnd={() => {
 | 
				
			||||||
                        onAnimationEnd={() => {
 | 
					                        if (setToggleLabels) {
 | 
				
			||||||
                          if (setToggleLabels) {
 | 
					                          setToggleLabels(false);
 | 
				
			||||||
                            setToggleLabels(false);
 | 
					                        }
 | 
				
			||||||
                          }
 | 
					                      }}
 | 
				
			||||||
                        }}
 | 
					                      variant={labelVariant ?? 'large'}
 | 
				
			||||||
                        variant={labelVariant ?? 'large'}
 | 
					                      color={label.labelColor.colorHex}
 | 
				
			||||||
                        color={label.labelColor.colorHex}
 | 
					                      key={label.id}
 | 
				
			||||||
                        key={label.id}
 | 
					                    >
 | 
				
			||||||
                      >
 | 
					                      <ListCardLabelText>{label.name}</ListCardLabelText>
 | 
				
			||||||
                        <ListCardLabelText>{label.name}</ListCardLabelText>
 | 
					                    </ListCardLabel>
 | 
				
			||||||
                      </ListCardLabel>
 | 
					                  ))}
 | 
				
			||||||
                    ))}
 | 
					            </ListCardLabels>
 | 
				
			||||||
                </ListCardLabels>
 | 
					 | 
				
			||||||
              </ListCardLabelsWrapper>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
            {editable ? (
 | 
					            {editable ? (
 | 
				
			||||||
              <EditorContent>
 | 
					              <EditorContent>
 | 
				
			||||||
                {complete && <CompleteIcon width={16} height={16} />}
 | 
					                {complete && <CompleteIcon width={16} height={16} />}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,6 @@ const Icon = styled.div`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type InputProps = {
 | 
					type InputProps = {
 | 
				
			||||||
  variant?: 'normal' | 'alternate';
 | 
					  variant?: 'normal' | 'alternate';
 | 
				
			||||||
  disabled?: boolean;
 | 
					 | 
				
			||||||
  label?: string;
 | 
					  label?: string;
 | 
				
			||||||
  width?: string;
 | 
					  width?: string;
 | 
				
			||||||
  floatingLabel?: boolean;
 | 
					  floatingLabel?: boolean;
 | 
				
			||||||
@@ -117,7 +116,6 @@ function useCombinedRefs(...refs: any) {
 | 
				
			|||||||
const Input = React.forwardRef(
 | 
					const Input = React.forwardRef(
 | 
				
			||||||
  (
 | 
					  (
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      disabled = false,
 | 
					 | 
				
			||||||
      width = 'auto',
 | 
					      width = 'auto',
 | 
				
			||||||
      variant = 'normal',
 | 
					      variant = 'normal',
 | 
				
			||||||
      type = 'text',
 | 
					      type = 'text',
 | 
				
			||||||
@@ -162,7 +160,6 @@ const Input = React.forwardRef(
 | 
				
			|||||||
          onChange={e => {
 | 
					          onChange={e => {
 | 
				
			||||||
            setHasValue((e.currentTarget.value !== '' || floatingLabel) ?? false);
 | 
					            setHasValue((e.currentTarget.value !== '' || floatingLabel) ?? false);
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          disabled={disabled}
 | 
					 | 
				
			||||||
          hasValue={hasValue}
 | 
					          hasValue={hasValue}
 | 
				
			||||||
          ref={combinedRef}
 | 
					          ref={combinedRef}
 | 
				
			||||||
          id={id}
 | 
					          id={id}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,6 @@ export const Default = () => {
 | 
				
			|||||||
      <BaseStyles />
 | 
					      <BaseStyles />
 | 
				
			||||||
      <Settings
 | 
					      <Settings
 | 
				
			||||||
        profile={profile}
 | 
					        profile={profile}
 | 
				
			||||||
        onChangeUserInfo={action('change user info')}
 | 
					 | 
				
			||||||
        onResetPassword={action('reset password')}
 | 
					        onResetPassword={action('reset password')}
 | 
				
			||||||
        onProfileAvatarRemove={action('remove')}
 | 
					        onProfileAvatarRemove={action('remove')}
 | 
				
			||||||
        onProfileAvatarChange={action('profile avatar change')}
 | 
					        onProfileAvatarChange={action('profile avatar change')}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,11 +10,6 @@ const PasswordInput = styled(Input)`
 | 
				
			|||||||
  margin-bottom: 0;
 | 
					  margin-bottom: 0;
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const UserInfoInput = styled(Input)`
 | 
					 | 
				
			||||||
  margin-top: 30px;
 | 
					 | 
				
			||||||
  margin-bottom: 0;
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const FormError = styled.span`
 | 
					const FormError = styled.span`
 | 
				
			||||||
  font-size: 12px;
 | 
					  font-size: 12px;
 | 
				
			||||||
  color: rgba(${props => props.theme.colors.warning});
 | 
					  color: rgba(${props => props.theme.colors.warning});
 | 
				
			||||||
@@ -245,7 +240,6 @@ const SaveButton = styled(Button)`
 | 
				
			|||||||
type SettingsProps = {
 | 
					type SettingsProps = {
 | 
				
			||||||
  onProfileAvatarChange: () => void;
 | 
					  onProfileAvatarChange: () => void;
 | 
				
			||||||
  onProfileAvatarRemove: () => void;
 | 
					  onProfileAvatarRemove: () => void;
 | 
				
			||||||
  onChangeUserInfo: (data: UserInfoData, done: () => void) => void;
 | 
					 | 
				
			||||||
  onResetPassword: (password: string, done: () => void) => void;
 | 
					  onResetPassword: (password: string, done: () => void) => void;
 | 
				
			||||||
  profile: TaskUser;
 | 
					  profile: TaskUser;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -306,93 +300,9 @@ const ResetPasswordTab: React.FC<ResetPasswordTabProps> = ({ onResetPassword })
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UserInfoData = {
 | 
					 | 
				
			||||||
  full_name: string;
 | 
					 | 
				
			||||||
  bio: string;
 | 
					 | 
				
			||||||
  initials: string;
 | 
					 | 
				
			||||||
  email: string;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
type UserInfoTabProps = {
 | 
					 | 
				
			||||||
  profile: TaskUser;
 | 
					 | 
				
			||||||
  onProfileAvatarChange: () => void;
 | 
					 | 
				
			||||||
  onProfileAvatarRemove: () => void;
 | 
					 | 
				
			||||||
  onChangeUserInfo: (data: UserInfoData, done: () => void) => void;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const EMAIL_PATTERN = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i;
 | 
					 | 
				
			||||||
const INITIALS_PATTERN = /^[a-zA-Z]{2,3}$/i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const UserInfoTab: React.FC<UserInfoTabProps> = ({
 | 
					 | 
				
			||||||
  profile,
 | 
					 | 
				
			||||||
  onProfileAvatarRemove,
 | 
					 | 
				
			||||||
  onProfileAvatarChange,
 | 
					 | 
				
			||||||
  onChangeUserInfo,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [active, setActive] = useState(true);
 | 
					 | 
				
			||||||
  const { register, handleSubmit, errors } = useForm<UserInfoData>();
 | 
					 | 
				
			||||||
  const done = () => {
 | 
					 | 
				
			||||||
    setActive(true);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <AvatarSettings
 | 
					 | 
				
			||||||
        onProfileAvatarRemove={onProfileAvatarRemove}
 | 
					 | 
				
			||||||
        onProfileAvatarChange={onProfileAvatarChange}
 | 
					 | 
				
			||||||
        profile={profile.profileIcon}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <form
 | 
					 | 
				
			||||||
        onSubmit={handleSubmit(data => {
 | 
					 | 
				
			||||||
          setActive(false);
 | 
					 | 
				
			||||||
          onChangeUserInfo(data, done);
 | 
					 | 
				
			||||||
        })}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <UserInfoInput
 | 
					 | 
				
			||||||
          ref={register({ required: 'Full name is required' })}
 | 
					 | 
				
			||||||
          name="full_name"
 | 
					 | 
				
			||||||
          defaultValue={profile.fullName}
 | 
					 | 
				
			||||||
          width="100%"
 | 
					 | 
				
			||||||
          label="Name"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        {errors.full_name && <FormError>{errors.full_name.message}</FormError>}
 | 
					 | 
				
			||||||
        <UserInfoInput
 | 
					 | 
				
			||||||
          defaultValue={profile.profileIcon && profile.profileIcon.initials ? profile.profileIcon.initials : ''}
 | 
					 | 
				
			||||||
          ref={register({
 | 
					 | 
				
			||||||
            required: 'Initials is required',
 | 
					 | 
				
			||||||
            pattern: { value: INITIALS_PATTERN, message: 'Intials must be between two to four characters' },
 | 
					 | 
				
			||||||
          })}
 | 
					 | 
				
			||||||
          name="initials"
 | 
					 | 
				
			||||||
          width="100%"
 | 
					 | 
				
			||||||
          label="Initials "
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        {errors.initials && <FormError>{errors.initials.message}</FormError>}
 | 
					 | 
				
			||||||
        <UserInfoInput disabled defaultValue={profile.username ?? ''} width="100%" label="Username " />
 | 
					 | 
				
			||||||
        <UserInfoInput
 | 
					 | 
				
			||||||
          width="100%"
 | 
					 | 
				
			||||||
          name="email"
 | 
					 | 
				
			||||||
          ref={register({
 | 
					 | 
				
			||||||
            required: 'Email is required',
 | 
					 | 
				
			||||||
            pattern: { value: EMAIL_PATTERN, message: 'Must be a valid email' },
 | 
					 | 
				
			||||||
          })}
 | 
					 | 
				
			||||||
          defaultValue={profile.email ?? ''}
 | 
					 | 
				
			||||||
          label="Email"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        {errors.email && <FormError>{errors.email.message}</FormError>}
 | 
					 | 
				
			||||||
        <UserInfoInput width="100%" name="bio" ref={register()} defaultValue={profile.bio ?? ''} label="Bio" />
 | 
					 | 
				
			||||||
        {errors.bio && <FormError>{errors.bio.message}</FormError>}
 | 
					 | 
				
			||||||
        <SettingActions>
 | 
					 | 
				
			||||||
          <SaveButton disabled={!active} type="submit">
 | 
					 | 
				
			||||||
            Save Change
 | 
					 | 
				
			||||||
          </SaveButton>
 | 
					 | 
				
			||||||
        </SettingActions>
 | 
					 | 
				
			||||||
      </form>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const Settings: React.FC<SettingsProps> = ({
 | 
					const Settings: React.FC<SettingsProps> = ({
 | 
				
			||||||
  onProfileAvatarRemove,
 | 
					  onProfileAvatarRemove,
 | 
				
			||||||
  onProfileAvatarChange,
 | 
					  onProfileAvatarChange,
 | 
				
			||||||
  onChangeUserInfo,
 | 
					 | 
				
			||||||
  onResetPassword,
 | 
					  onResetPassword,
 | 
				
			||||||
  profile,
 | 
					  profile,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
@@ -405,7 +315,6 @@ const Settings: React.FC<SettingsProps> = ({
 | 
				
			|||||||
        <TabNavContent>
 | 
					        <TabNavContent>
 | 
				
			||||||
          {items.map((item, idx) => (
 | 
					          {items.map((item, idx) => (
 | 
				
			||||||
            <NavItem
 | 
					            <NavItem
 | 
				
			||||||
              key={item.name}
 | 
					 | 
				
			||||||
              onClick={(tab, top) => {
 | 
					              onClick={(tab, top) => {
 | 
				
			||||||
                if ($tabNav && $tabNav.current) {
 | 
					                if ($tabNav && $tabNav.current) {
 | 
				
			||||||
                  const pos = $tabNav.current.getBoundingClientRect();
 | 
					                  const pos = $tabNav.current.getBoundingClientRect();
 | 
				
			||||||
@@ -423,12 +332,23 @@ const Settings: React.FC<SettingsProps> = ({
 | 
				
			|||||||
      </TabNav>
 | 
					      </TabNav>
 | 
				
			||||||
      <TabContentWrapper>
 | 
					      <TabContentWrapper>
 | 
				
			||||||
        <Tab tab={0} currentTab={currentTab}>
 | 
					        <Tab tab={0} currentTab={currentTab}>
 | 
				
			||||||
          <UserInfoTab
 | 
					          <AvatarSettings
 | 
				
			||||||
            onProfileAvatarChange={onProfileAvatarChange}
 | 
					 | 
				
			||||||
            onProfileAvatarRemove={onProfileAvatarRemove}
 | 
					            onProfileAvatarRemove={onProfileAvatarRemove}
 | 
				
			||||||
            profile={profile}
 | 
					            onProfileAvatarChange={onProfileAvatarChange}
 | 
				
			||||||
            onChangeUserInfo={onChangeUserInfo}
 | 
					            profile={profile.profileIcon}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					          <Input defaultValue={profile.fullName} width="100%" label="Name" />
 | 
				
			||||||
 | 
					          <Input
 | 
				
			||||||
 | 
					            defaultValue={profile.profileIcon && profile.profileIcon.initials ? profile.profileIcon.initials : ''}
 | 
				
			||||||
 | 
					            width="100%"
 | 
				
			||||||
 | 
					            label="Initials "
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Input defaultValue={profile.username ?? ''} width="100%" label="Username " />
 | 
				
			||||||
 | 
					          <Input width="100%" label="Email" />
 | 
				
			||||||
 | 
					          <Input width="100%" label="Bio" />
 | 
				
			||||||
 | 
					          <SettingActions>
 | 
				
			||||||
 | 
					            <SaveButton>Save Change</SaveButton>
 | 
				
			||||||
 | 
					          </SettingActions>
 | 
				
			||||||
        </Tab>
 | 
					        </Tab>
 | 
				
			||||||
        <Tab tab={1} currentTab={currentTab}>
 | 
					        <Tab tab={1} currentTab={currentTab}>
 | 
				
			||||||
          <ResetPasswordTab onResetPassword={onResetPassword} />
 | 
					          <ResetPasswordTab onResetPassword={onResetPassword} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -169,7 +169,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
 | 
				
			|||||||
          <LeftSidebarSection>
 | 
					          <LeftSidebarSection>
 | 
				
			||||||
            <SidebarTitle>TASK GROUP</SidebarTitle>
 | 
					            <SidebarTitle>TASK GROUP</SidebarTitle>
 | 
				
			||||||
            <SidebarButton>
 | 
					            <SidebarButton>
 | 
				
			||||||
              <SidebarButtonText>{task.taskGroup.name}</SidebarButtonText>
 | 
					              <SidebarButtonText>Release 0.1.0</SidebarButtonText>
 | 
				
			||||||
            </SidebarButton>
 | 
					            </SidebarButton>
 | 
				
			||||||
            <DueDateTitle>DUE DATE</DueDateTitle>
 | 
					            <DueDateTitle>DUE DATE</DueDateTitle>
 | 
				
			||||||
            <SidebarButton
 | 
					            <SidebarButton
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -251,8 +251,8 @@ export const NavSeparator = styled.div`
 | 
				
			|||||||
export const LogoContainer = styled(Link)`
 | 
					export const LogoContainer = styled(Link)`
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  left: 50%;
 | 
					  left: 50%;
 | 
				
			||||||
  right: 50%;
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  transform: translateX(-50%);
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  justify-content: center;
 | 
					  justify-content: center;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,7 +105,6 @@ export type UserAccount = {
 | 
				
			|||||||
  createdAt: Scalars['Time'];
 | 
					  createdAt: Scalars['Time'];
 | 
				
			||||||
  fullName: Scalars['String'];
 | 
					  fullName: Scalars['String'];
 | 
				
			||||||
  initials: Scalars['String'];
 | 
					  initials: Scalars['String'];
 | 
				
			||||||
  bio: Scalars['String'];
 | 
					 | 
				
			||||||
  role: Role;
 | 
					  role: Role;
 | 
				
			||||||
  username: Scalars['String'];
 | 
					  username: Scalars['String'];
 | 
				
			||||||
  profileIcon: ProfileIcon;
 | 
					  profileIcon: ProfileIcon;
 | 
				
			||||||
@@ -209,8 +208,7 @@ export enum ObjectType {
 | 
				
			|||||||
  Org = 'ORG',
 | 
					  Org = 'ORG',
 | 
				
			||||||
  Team = 'TEAM',
 | 
					  Team = 'TEAM',
 | 
				
			||||||
  Project = 'PROJECT',
 | 
					  Project = 'PROJECT',
 | 
				
			||||||
  Task = 'TASK',
 | 
					  Task = 'TASK'
 | 
				
			||||||
  TaskGroup = 'TASK_GROUP'
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Query = {
 | 
					export type Query = {
 | 
				
			||||||
@@ -305,7 +303,6 @@ export type Mutation = {
 | 
				
			|||||||
  updateTaskLocation: UpdateTaskLocationPayload;
 | 
					  updateTaskLocation: UpdateTaskLocationPayload;
 | 
				
			||||||
  updateTaskName: Task;
 | 
					  updateTaskName: Task;
 | 
				
			||||||
  updateTeamMemberRole: UpdateTeamMemberRolePayload;
 | 
					  updateTeamMemberRole: UpdateTeamMemberRolePayload;
 | 
				
			||||||
  updateUserInfo: UpdateUserInfoPayload;
 | 
					 | 
				
			||||||
  updateUserPassword: UpdateUserPasswordPayload;
 | 
					  updateUserPassword: UpdateUserPasswordPayload;
 | 
				
			||||||
  updateUserRole: UpdateUserRolePayload;
 | 
					  updateUserRole: UpdateUserRolePayload;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -551,11 +548,6 @@ export type MutationUpdateTeamMemberRoleArgs = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type MutationUpdateUserInfoArgs = {
 | 
					 | 
				
			||||||
  input: UpdateUserInfo;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type MutationUpdateUserPasswordArgs = {
 | 
					export type MutationUpdateUserPasswordArgs = {
 | 
				
			||||||
  input: UpdateUserPassword;
 | 
					  input: UpdateUserPassword;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -723,7 +715,7 @@ export type UpdateProjectMemberRolePayload = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type NewTask = {
 | 
					export type NewTask = {
 | 
				
			||||||
  taskGroupID: Scalars['UUID'];
 | 
					  taskGroupID: Scalars['String'];
 | 
				
			||||||
  name: Scalars['String'];
 | 
					  name: Scalars['String'];
 | 
				
			||||||
  position: Scalars['Float'];
 | 
					  position: Scalars['Float'];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -987,18 +979,6 @@ export type UpdateTeamMemberRolePayload = {
 | 
				
			|||||||
  member: Member;
 | 
					  member: Member;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type UpdateUserInfoPayload = {
 | 
					 | 
				
			||||||
   __typename?: 'UpdateUserInfoPayload';
 | 
					 | 
				
			||||||
  user: UserAccount;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type UpdateUserInfo = {
 | 
					 | 
				
			||||||
  name: Scalars['String'];
 | 
					 | 
				
			||||||
  initials: Scalars['String'];
 | 
					 | 
				
			||||||
  email: Scalars['String'];
 | 
					 | 
				
			||||||
  bio: Scalars['String'];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type UpdateUserPassword = {
 | 
					export type UpdateUserPassword = {
 | 
				
			||||||
  userID: Scalars['UUID'];
 | 
					  userID: Scalars['UUID'];
 | 
				
			||||||
  password: Scalars['String'];
 | 
					  password: Scalars['String'];
 | 
				
			||||||
@@ -1265,7 +1245,7 @@ export type FindTaskQuery = (
 | 
				
			|||||||
    & Pick<Task, 'id' | 'name' | 'description' | 'dueDate' | 'position' | 'complete'>
 | 
					    & Pick<Task, 'id' | 'name' | 'description' | 'dueDate' | 'position' | 'complete'>
 | 
				
			||||||
    & { taskGroup: (
 | 
					    & { taskGroup: (
 | 
				
			||||||
      { __typename?: 'TaskGroup' }
 | 
					      { __typename?: 'TaskGroup' }
 | 
				
			||||||
      & Pick<TaskGroup, 'id' | 'name'>
 | 
					      & Pick<TaskGroup, 'id'>
 | 
				
			||||||
    ), badges: (
 | 
					    ), badges: (
 | 
				
			||||||
      { __typename?: 'TaskBadges' }
 | 
					      { __typename?: 'TaskBadges' }
 | 
				
			||||||
      & { checklist?: Maybe<(
 | 
					      & { checklist?: Maybe<(
 | 
				
			||||||
@@ -1374,7 +1354,7 @@ export type MeQuery = (
 | 
				
			|||||||
    { __typename?: 'MePayload' }
 | 
					    { __typename?: 'MePayload' }
 | 
				
			||||||
    & { user: (
 | 
					    & { user: (
 | 
				
			||||||
      { __typename?: 'UserAccount' }
 | 
					      { __typename?: 'UserAccount' }
 | 
				
			||||||
      & Pick<UserAccount, 'id' | 'fullName' | 'username' | 'email' | 'bio'>
 | 
					      & Pick<UserAccount, 'id' | 'fullName'>
 | 
				
			||||||
      & { profileIcon: (
 | 
					      & { profileIcon: (
 | 
				
			||||||
        { __typename?: 'ProfileIcon' }
 | 
					        { __typename?: 'ProfileIcon' }
 | 
				
			||||||
        & Pick<ProfileIcon, 'initials' | 'bgColor' | 'url'>
 | 
					        & Pick<ProfileIcon, 'initials' | 'bgColor' | 'url'>
 | 
				
			||||||
@@ -1473,7 +1453,7 @@ export type UpdateProjectMemberRoleMutation = (
 | 
				
			|||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type CreateTaskMutationVariables = {
 | 
					export type CreateTaskMutationVariables = {
 | 
				
			||||||
  taskGroupID: Scalars['UUID'];
 | 
					  taskGroupID: Scalars['String'];
 | 
				
			||||||
  name: Scalars['String'];
 | 
					  name: Scalars['String'];
 | 
				
			||||||
  position: Scalars['Float'];
 | 
					  position: Scalars['Float'];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -2100,7 +2080,7 @@ export type CreateUserAccountMutation = (
 | 
				
			|||||||
  { __typename?: 'Mutation' }
 | 
					  { __typename?: 'Mutation' }
 | 
				
			||||||
  & { createUserAccount: (
 | 
					  & { createUserAccount: (
 | 
				
			||||||
    { __typename?: 'UserAccount' }
 | 
					    { __typename?: 'UserAccount' }
 | 
				
			||||||
    & Pick<UserAccount, 'id' | 'email' | 'fullName' | 'initials' | 'username' | 'bio'>
 | 
					    & Pick<UserAccount, 'id' | 'email' | 'fullName' | 'initials' | 'username'>
 | 
				
			||||||
    & { profileIcon: (
 | 
					    & { profileIcon: (
 | 
				
			||||||
      { __typename?: 'ProfileIcon' }
 | 
					      { __typename?: 'ProfileIcon' }
 | 
				
			||||||
      & Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
 | 
					      & Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
 | 
				
			||||||
@@ -2147,29 +2127,6 @@ export type DeleteUserAccountMutation = (
 | 
				
			|||||||
  ) }
 | 
					  ) }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type UpdateUserInfoMutationVariables = {
 | 
					 | 
				
			||||||
  name: Scalars['String'];
 | 
					 | 
				
			||||||
  initials: Scalars['String'];
 | 
					 | 
				
			||||||
  email: Scalars['String'];
 | 
					 | 
				
			||||||
  bio: Scalars['String'];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type UpdateUserInfoMutation = (
 | 
					 | 
				
			||||||
  { __typename?: 'Mutation' }
 | 
					 | 
				
			||||||
  & { updateUserInfo: (
 | 
					 | 
				
			||||||
    { __typename?: 'UpdateUserInfoPayload' }
 | 
					 | 
				
			||||||
    & { user: (
 | 
					 | 
				
			||||||
      { __typename?: 'UserAccount' }
 | 
					 | 
				
			||||||
      & Pick<UserAccount, 'id' | 'email' | 'fullName' | 'bio'>
 | 
					 | 
				
			||||||
      & { profileIcon: (
 | 
					 | 
				
			||||||
        { __typename?: 'ProfileIcon' }
 | 
					 | 
				
			||||||
        & Pick<ProfileIcon, 'initials'>
 | 
					 | 
				
			||||||
      ) }
 | 
					 | 
				
			||||||
    ) }
 | 
					 | 
				
			||||||
  ) }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type UpdateUserPasswordMutationVariables = {
 | 
					export type UpdateUserPasswordMutationVariables = {
 | 
				
			||||||
  userID: Scalars['UUID'];
 | 
					  userID: Scalars['UUID'];
 | 
				
			||||||
  password: Scalars['String'];
 | 
					  password: Scalars['String'];
 | 
				
			||||||
@@ -2703,7 +2660,6 @@ export const FindTaskDocument = gql`
 | 
				
			|||||||
    complete
 | 
					    complete
 | 
				
			||||||
    taskGroup {
 | 
					    taskGroup {
 | 
				
			||||||
      id
 | 
					      id
 | 
				
			||||||
      name
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    badges {
 | 
					    badges {
 | 
				
			||||||
      checklist {
 | 
					      checklist {
 | 
				
			||||||
@@ -2839,9 +2795,6 @@ export const MeDocument = gql`
 | 
				
			|||||||
    user {
 | 
					    user {
 | 
				
			||||||
      id
 | 
					      id
 | 
				
			||||||
      fullName
 | 
					      fullName
 | 
				
			||||||
      username
 | 
					 | 
				
			||||||
      email
 | 
					 | 
				
			||||||
      bio
 | 
					 | 
				
			||||||
      profileIcon {
 | 
					      profileIcon {
 | 
				
			||||||
        initials
 | 
					        initials
 | 
				
			||||||
        bgColor
 | 
					        bgColor
 | 
				
			||||||
@@ -3045,7 +2998,7 @@ export type UpdateProjectMemberRoleMutationHookResult = ReturnType<typeof useUpd
 | 
				
			|||||||
export type UpdateProjectMemberRoleMutationResult = ApolloReactCommon.MutationResult<UpdateProjectMemberRoleMutation>;
 | 
					export type UpdateProjectMemberRoleMutationResult = ApolloReactCommon.MutationResult<UpdateProjectMemberRoleMutation>;
 | 
				
			||||||
export type UpdateProjectMemberRoleMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateProjectMemberRoleMutation, UpdateProjectMemberRoleMutationVariables>;
 | 
					export type UpdateProjectMemberRoleMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateProjectMemberRoleMutation, UpdateProjectMemberRoleMutationVariables>;
 | 
				
			||||||
export const CreateTaskDocument = gql`
 | 
					export const CreateTaskDocument = gql`
 | 
				
			||||||
    mutation createTask($taskGroupID: UUID!, $name: String!, $position: Float!) {
 | 
					    mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
 | 
				
			||||||
  createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
 | 
					  createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
 | 
				
			||||||
    ...TaskFields
 | 
					    ...TaskFields
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -4318,7 +4271,6 @@ export const CreateUserAccountDocument = gql`
 | 
				
			|||||||
    fullName
 | 
					    fullName
 | 
				
			||||||
    initials
 | 
					    initials
 | 
				
			||||||
    username
 | 
					    username
 | 
				
			||||||
    bio
 | 
					 | 
				
			||||||
    profileIcon {
 | 
					    profileIcon {
 | 
				
			||||||
      url
 | 
					      url
 | 
				
			||||||
      initials
 | 
					      initials
 | 
				
			||||||
@@ -4417,49 +4369,6 @@ export function useDeleteUserAccountMutation(baseOptions?: ApolloReactHooks.Muta
 | 
				
			|||||||
export type DeleteUserAccountMutationHookResult = ReturnType<typeof useDeleteUserAccountMutation>;
 | 
					export type DeleteUserAccountMutationHookResult = ReturnType<typeof useDeleteUserAccountMutation>;
 | 
				
			||||||
export type DeleteUserAccountMutationResult = ApolloReactCommon.MutationResult<DeleteUserAccountMutation>;
 | 
					export type DeleteUserAccountMutationResult = ApolloReactCommon.MutationResult<DeleteUserAccountMutation>;
 | 
				
			||||||
export type DeleteUserAccountMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>;
 | 
					export type DeleteUserAccountMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>;
 | 
				
			||||||
export const UpdateUserInfoDocument = gql`
 | 
					 | 
				
			||||||
    mutation updateUserInfo($name: String!, $initials: String!, $email: String!, $bio: String!) {
 | 
					 | 
				
			||||||
  updateUserInfo(input: {name: $name, initials: $initials, email: $email, bio: $bio}) {
 | 
					 | 
				
			||||||
    user {
 | 
					 | 
				
			||||||
      id
 | 
					 | 
				
			||||||
      email
 | 
					 | 
				
			||||||
      fullName
 | 
					 | 
				
			||||||
      bio
 | 
					 | 
				
			||||||
      profileIcon {
 | 
					 | 
				
			||||||
        initials
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
    `;
 | 
					 | 
				
			||||||
export type UpdateUserInfoMutationFn = ApolloReactCommon.MutationFunction<UpdateUserInfoMutation, UpdateUserInfoMutationVariables>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * __useUpdateUserInfoMutation__
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * To run a mutation, you first call `useUpdateUserInfoMutation` within a React component and pass it any options that fit your needs.
 | 
					 | 
				
			||||||
 * When your component renders, `useUpdateUserInfoMutation` returns a tuple that includes:
 | 
					 | 
				
			||||||
 * - A mutate function that you can call at any time to execute the mutation
 | 
					 | 
				
			||||||
 * - An object with fields that represent the current status of the mutation's execution
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @example
 | 
					 | 
				
			||||||
 * const [updateUserInfoMutation, { data, loading, error }] = useUpdateUserInfoMutation({
 | 
					 | 
				
			||||||
 *   variables: {
 | 
					 | 
				
			||||||
 *      name: // value for 'name'
 | 
					 | 
				
			||||||
 *      initials: // value for 'initials'
 | 
					 | 
				
			||||||
 *      email: // value for 'email'
 | 
					 | 
				
			||||||
 *      bio: // value for 'bio'
 | 
					 | 
				
			||||||
 *   },
 | 
					 | 
				
			||||||
 * });
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export function useUpdateUserInfoMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<UpdateUserInfoMutation, UpdateUserInfoMutationVariables>) {
 | 
					 | 
				
			||||||
        return ApolloReactHooks.useMutation<UpdateUserInfoMutation, UpdateUserInfoMutationVariables>(UpdateUserInfoDocument, baseOptions);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
export type UpdateUserInfoMutationHookResult = ReturnType<typeof useUpdateUserInfoMutation>;
 | 
					 | 
				
			||||||
export type UpdateUserInfoMutationResult = ApolloReactCommon.MutationResult<UpdateUserInfoMutation>;
 | 
					 | 
				
			||||||
export type UpdateUserInfoMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateUserInfoMutation, UpdateUserInfoMutationVariables>;
 | 
					 | 
				
			||||||
export const UpdateUserPasswordDocument = gql`
 | 
					export const UpdateUserPasswordDocument = gql`
 | 
				
			||||||
    mutation updateUserPassword($userID: UUID!, $password: String!) {
 | 
					    mutation updateUserPassword($userID: UUID!, $password: String!) {
 | 
				
			||||||
  updateUserPassword(input: {userID: $userID, password: $password}) {
 | 
					  updateUserPassword(input: {userID: $userID, password: $password}) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@ query findTask($taskID: UUID!) {
 | 
				
			|||||||
    complete
 | 
					    complete
 | 
				
			||||||
    taskGroup {
 | 
					    taskGroup {
 | 
				
			||||||
      id
 | 
					      id
 | 
				
			||||||
      name
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    badges {
 | 
					    badges {
 | 
				
			||||||
      checklist {
 | 
					      checklist {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,6 @@ query me {
 | 
				
			|||||||
    user {
 | 
					    user {
 | 
				
			||||||
      id
 | 
					      id
 | 
				
			||||||
      fullName
 | 
					      fullName
 | 
				
			||||||
      username
 | 
					 | 
				
			||||||
      email
 | 
					 | 
				
			||||||
      bio
 | 
					 | 
				
			||||||
      profileIcon {
 | 
					      profileIcon {
 | 
				
			||||||
        initials
 | 
					        initials
 | 
				
			||||||
        bgColor
 | 
					        bgColor
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import gql from 'graphql-tag';
 | 
				
			|||||||
import TASK_FRAGMENT from '../fragments/task';
 | 
					import TASK_FRAGMENT from '../fragments/task';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CREATE_TASK_MUTATION = gql`
 | 
					const CREATE_TASK_MUTATION = gql`
 | 
				
			||||||
  mutation createTask($taskGroupID: UUID!, $name: String!, $position: Float!) {
 | 
					  mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
 | 
				
			||||||
    createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
 | 
					    createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
 | 
				
			||||||
      ...TaskFields
 | 
					      ...TaskFields
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@ export const CREATE_USER_MUTATION = gql`
 | 
				
			|||||||
      fullName
 | 
					      fullName
 | 
				
			||||||
      initials
 | 
					      initials
 | 
				
			||||||
      username
 | 
					      username
 | 
				
			||||||
      bio
 | 
					 | 
				
			||||||
      profileIcon {
 | 
					      profileIcon {
 | 
				
			||||||
        url
 | 
					        url
 | 
				
			||||||
        initials
 | 
					        initials
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +0,0 @@
 | 
				
			|||||||
import gql from 'graphql-tag';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const UPDATE_USER_INFO_MUTATION = gql`
 | 
					 | 
				
			||||||
  mutation updateUserInfo($name: String!, $initials: String!, $email: String!, $bio: String!) {
 | 
					 | 
				
			||||||
    updateUserInfo(input: { name: $name, initials: $initials, email: $email, bio: $bio }) {
 | 
					 | 
				
			||||||
      user {
 | 
					 | 
				
			||||||
        id
 | 
					 | 
				
			||||||
        email
 | 
					 | 
				
			||||||
        fullName
 | 
					 | 
				
			||||||
        bio
 | 
					 | 
				
			||||||
        profileIcon {
 | 
					 | 
				
			||||||
          initials
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default UPDATE_USER_INFO_MUTATION;
 | 
					 | 
				
			||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
import { ApolloError } from '@apollo/client';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function hasNotFoundError(...errors: Array<ApolloError | undefined>) {
 | 
					 | 
				
			||||||
  for (const error of errors) {
 | 
					 | 
				
			||||||
    if (error && error.graphQLErrors.length !== 0) {
 | 
					 | 
				
			||||||
      const notFound = error.graphQLErrors.find(e => e.extensions && e.extensions.code === '404');
 | 
					 | 
				
			||||||
      if (notFound) {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								frontend/src/taskcafe.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								frontend/src/taskcafe.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -46,8 +46,6 @@ type OwnedList = {
 | 
				
			|||||||
type TaskUser = {
 | 
					type TaskUser = {
 | 
				
			||||||
  id: string;
 | 
					  id: string;
 | 
				
			||||||
  fullName: string;
 | 
					  fullName: string;
 | 
				
			||||||
  email?: string;
 | 
					 | 
				
			||||||
  bio?: string;
 | 
					 | 
				
			||||||
  profileIcon: ProfileIcon;
 | 
					  profileIcon: ProfileIcon;
 | 
				
			||||||
  username?: string;
 | 
					  username?: string;
 | 
				
			||||||
  role?: Role;
 | 
					  role?: Role;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -157,5 +157,4 @@ type UserAccount struct {
 | 
				
			|||||||
	Initials         string         `json:"initials"`
 | 
						Initials         string         `json:"initials"`
 | 
				
			||||||
	ProfileAvatarUrl sql.NullString `json:"profile_avatar_url"`
 | 
						ProfileAvatarUrl sql.NullString `json:"profile_avatar_url"`
 | 
				
			||||||
	RoleCode         string         `json:"role_code"`
 | 
						RoleCode         string         `json:"role_code"`
 | 
				
			||||||
	Bio              string         `json:"bio"`
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,7 +114,6 @@ type Querier interface {
 | 
				
			|||||||
	UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error)
 | 
						UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error)
 | 
				
			||||||
	UpdateTaskPosition(ctx context.Context, arg UpdateTaskPositionParams) (Task, error)
 | 
						UpdateTaskPosition(ctx context.Context, arg UpdateTaskPositionParams) (Task, error)
 | 
				
			||||||
	UpdateTeamMemberRole(ctx context.Context, arg UpdateTeamMemberRoleParams) (TeamMember, error)
 | 
						UpdateTeamMemberRole(ctx context.Context, arg UpdateTeamMemberRoleParams) (TeamMember, error)
 | 
				
			||||||
	UpdateUserAccountInfo(ctx context.Context, arg UpdateUserAccountInfoParams) (UserAccount, error)
 | 
					 | 
				
			||||||
	UpdateUserAccountProfileAvatarURL(ctx context.Context, arg UpdateUserAccountProfileAvatarURLParams) (UserAccount, error)
 | 
						UpdateUserAccountProfileAvatarURL(ctx context.Context, arg UpdateUserAccountProfileAvatarURLParams) (UserAccount, error)
 | 
				
			||||||
	UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UserAccount, error)
 | 
						UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UserAccount, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,10 +15,6 @@ INSERT INTO user_account(full_name, initials, email, username, created_at, passw
 | 
				
			|||||||
UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
 | 
					UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
 | 
				
			||||||
  RETURNING *;
 | 
					  RETURNING *;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- name: UpdateUserAccountInfo :one
 | 
					 | 
				
			||||||
UPDATE user_account SET bio = $2, full_name = $3, initials = $4, email = $5
 | 
					 | 
				
			||||||
  WHERE user_id = $1 RETURNING *;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
-- name: DeleteUserAccountByID :exec
 | 
					-- name: DeleteUserAccountByID :exec
 | 
				
			||||||
DELETE FROM user_account WHERE user_id = $1;
 | 
					DELETE FROM user_account WHERE user_id = $1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const createUserAccount = `-- name: CreateUserAccount :one
 | 
					const createUserAccount = `-- name: CreateUserAccount :one
 | 
				
			||||||
INSERT INTO user_account(full_name, initials, email, username, created_at, password_hash, role_code)
 | 
					INSERT INTO user_account(full_name, initials, email, username, created_at, password_hash, role_code)
 | 
				
			||||||
  VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio
 | 
					  VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CreateUserAccountParams struct {
 | 
					type CreateUserAccountParams struct {
 | 
				
			||||||
@@ -48,7 +48,6 @@ func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountPa
 | 
				
			|||||||
		&i.Initials,
 | 
							&i.Initials,
 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
							&i.ProfileAvatarUrl,
 | 
				
			||||||
		&i.RoleCode,
 | 
							&i.RoleCode,
 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -63,7 +62,7 @@ func (q *Queries) DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) e
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getAllUserAccounts = `-- name: GetAllUserAccounts :many
 | 
					const getAllUserAccounts = `-- name: GetAllUserAccounts :many
 | 
				
			||||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio FROM user_account WHERE username != 'system'
 | 
					SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code FROM user_account WHERE username != 'system'
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) {
 | 
					func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) {
 | 
				
			||||||
@@ -86,7 +85,6 @@ func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
 | 
				
			|||||||
			&i.Initials,
 | 
								&i.Initials,
 | 
				
			||||||
			&i.ProfileAvatarUrl,
 | 
								&i.ProfileAvatarUrl,
 | 
				
			||||||
			&i.RoleCode,
 | 
								&i.RoleCode,
 | 
				
			||||||
			&i.Bio,
 | 
					 | 
				
			||||||
		); err != nil {
 | 
							); err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -121,7 +119,7 @@ func (q *Queries) GetRoleForUserID(ctx context.Context, userID uuid.UUID) (GetRo
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getUserAccountByID = `-- name: GetUserAccountByID :one
 | 
					const getUserAccountByID = `-- name: GetUserAccountByID :one
 | 
				
			||||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio FROM user_account WHERE user_id = $1
 | 
					SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code FROM user_account WHERE user_id = $1
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error) {
 | 
					func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error) {
 | 
				
			||||||
@@ -138,13 +136,12 @@ func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (Use
 | 
				
			|||||||
		&i.Initials,
 | 
							&i.Initials,
 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
							&i.ProfileAvatarUrl,
 | 
				
			||||||
		&i.RoleCode,
 | 
							&i.RoleCode,
 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getUserAccountByUsername = `-- name: GetUserAccountByUsername :one
 | 
					const getUserAccountByUsername = `-- name: GetUserAccountByUsername :one
 | 
				
			||||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio FROM user_account WHERE username = $1
 | 
					SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code FROM user_account WHERE username = $1
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error) {
 | 
					func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error) {
 | 
				
			||||||
@@ -161,13 +158,12 @@ func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string)
 | 
				
			|||||||
		&i.Initials,
 | 
							&i.Initials,
 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
							&i.ProfileAvatarUrl,
 | 
				
			||||||
		&i.RoleCode,
 | 
							&i.RoleCode,
 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const setUserPassword = `-- name: SetUserPassword :one
 | 
					const setUserPassword = `-- name: SetUserPassword :one
 | 
				
			||||||
UPDATE user_account SET password_hash = $2 WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio
 | 
					UPDATE user_account SET password_hash = $2 WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SetUserPasswordParams struct {
 | 
					type SetUserPasswordParams struct {
 | 
				
			||||||
@@ -189,52 +185,13 @@ func (q *Queries) SetUserPassword(ctx context.Context, arg SetUserPasswordParams
 | 
				
			|||||||
		&i.Initials,
 | 
							&i.Initials,
 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
							&i.ProfileAvatarUrl,
 | 
				
			||||||
		&i.RoleCode,
 | 
							&i.RoleCode,
 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	return i, err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const updateUserAccountInfo = `-- name: UpdateUserAccountInfo :one
 | 
					 | 
				
			||||||
UPDATE user_account SET bio = $2, full_name = $3, initials = $4, email = $5
 | 
					 | 
				
			||||||
  WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio
 | 
					 | 
				
			||||||
`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateUserAccountInfoParams struct {
 | 
					 | 
				
			||||||
	UserID   uuid.UUID `json:"user_id"`
 | 
					 | 
				
			||||||
	Bio      string    `json:"bio"`
 | 
					 | 
				
			||||||
	FullName string    `json:"full_name"`
 | 
					 | 
				
			||||||
	Initials string    `json:"initials"`
 | 
					 | 
				
			||||||
	Email    string    `json:"email"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (q *Queries) UpdateUserAccountInfo(ctx context.Context, arg UpdateUserAccountInfoParams) (UserAccount, error) {
 | 
					 | 
				
			||||||
	row := q.db.QueryRowContext(ctx, updateUserAccountInfo,
 | 
					 | 
				
			||||||
		arg.UserID,
 | 
					 | 
				
			||||||
		arg.Bio,
 | 
					 | 
				
			||||||
		arg.FullName,
 | 
					 | 
				
			||||||
		arg.Initials,
 | 
					 | 
				
			||||||
		arg.Email,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	var i UserAccount
 | 
					 | 
				
			||||||
	err := row.Scan(
 | 
					 | 
				
			||||||
		&i.UserID,
 | 
					 | 
				
			||||||
		&i.CreatedAt,
 | 
					 | 
				
			||||||
		&i.Email,
 | 
					 | 
				
			||||||
		&i.Username,
 | 
					 | 
				
			||||||
		&i.PasswordHash,
 | 
					 | 
				
			||||||
		&i.ProfileBgColor,
 | 
					 | 
				
			||||||
		&i.FullName,
 | 
					 | 
				
			||||||
		&i.Initials,
 | 
					 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
					 | 
				
			||||||
		&i.RoleCode,
 | 
					 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const updateUserAccountProfileAvatarURL = `-- name: UpdateUserAccountProfileAvatarURL :one
 | 
					const updateUserAccountProfileAvatarURL = `-- name: UpdateUserAccountProfileAvatarURL :one
 | 
				
			||||||
UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
 | 
					UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
 | 
				
			||||||
  RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio
 | 
					  RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UpdateUserAccountProfileAvatarURLParams struct {
 | 
					type UpdateUserAccountProfileAvatarURLParams struct {
 | 
				
			||||||
@@ -256,13 +213,12 @@ func (q *Queries) UpdateUserAccountProfileAvatarURL(ctx context.Context, arg Upd
 | 
				
			|||||||
		&i.Initials,
 | 
							&i.Initials,
 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
							&i.ProfileAvatarUrl,
 | 
				
			||||||
		&i.RoleCode,
 | 
							&i.RoleCode,
 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const updateUserRole = `-- name: UpdateUserRole :one
 | 
					const updateUserRole = `-- name: UpdateUserRole :one
 | 
				
			||||||
UPDATE user_account SET role_code = $2 WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio
 | 
					UPDATE user_account SET role_code = $2 WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UpdateUserRoleParams struct {
 | 
					type UpdateUserRoleParams struct {
 | 
				
			||||||
@@ -284,7 +240,6 @@ func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams)
 | 
				
			|||||||
		&i.Initials,
 | 
							&i.Initials,
 | 
				
			||||||
		&i.ProfileAvatarUrl,
 | 
							&i.ProfileAvatarUrl,
 | 
				
			||||||
		&i.RoleCode,
 | 
							&i.RoleCode,
 | 
				
			||||||
		&i.Bio,
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -210,7 +210,6 @@ type ComplexityRoot struct {
 | 
				
			|||||||
		UpdateTaskLocation              func(childComplexity int, input NewTaskLocation) int
 | 
							UpdateTaskLocation              func(childComplexity int, input NewTaskLocation) int
 | 
				
			||||||
		UpdateTaskName                  func(childComplexity int, input UpdateTaskName) int
 | 
							UpdateTaskName                  func(childComplexity int, input UpdateTaskName) int
 | 
				
			||||||
		UpdateTeamMemberRole            func(childComplexity int, input UpdateTeamMemberRole) int
 | 
							UpdateTeamMemberRole            func(childComplexity int, input UpdateTeamMemberRole) int
 | 
				
			||||||
		UpdateUserInfo                  func(childComplexity int, input UpdateUserInfo) int
 | 
					 | 
				
			||||||
		UpdateUserPassword              func(childComplexity int, input UpdateUserPassword) int
 | 
							UpdateUserPassword              func(childComplexity int, input UpdateUserPassword) int
 | 
				
			||||||
		UpdateUserRole                  func(childComplexity int, input UpdateUserRole) int
 | 
							UpdateUserRole                  func(childComplexity int, input UpdateUserRole) int
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -405,10 +404,6 @@ type ComplexityRoot struct {
 | 
				
			|||||||
		TeamID func(childComplexity int) int
 | 
							TeamID func(childComplexity int) int
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UpdateUserInfoPayload struct {
 | 
					 | 
				
			||||||
		User func(childComplexity int) int
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	UpdateUserPasswordPayload struct {
 | 
						UpdateUserPasswordPayload struct {
 | 
				
			||||||
		Ok   func(childComplexity int) int
 | 
							Ok   func(childComplexity int) int
 | 
				
			||||||
		User func(childComplexity int) int
 | 
							User func(childComplexity int) int
 | 
				
			||||||
@@ -419,7 +414,6 @@ type ComplexityRoot struct {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UserAccount struct {
 | 
						UserAccount struct {
 | 
				
			||||||
		Bio         func(childComplexity int) int
 | 
					 | 
				
			||||||
		CreatedAt   func(childComplexity int) int
 | 
							CreatedAt   func(childComplexity int) int
 | 
				
			||||||
		Email       func(childComplexity int) int
 | 
							Email       func(childComplexity int) int
 | 
				
			||||||
		FullName    func(childComplexity int) int
 | 
							FullName    func(childComplexity int) int
 | 
				
			||||||
@@ -488,7 +482,6 @@ type MutationResolver interface {
 | 
				
			|||||||
	ClearProfileAvatar(ctx context.Context) (*db.UserAccount, error)
 | 
						ClearProfileAvatar(ctx context.Context) (*db.UserAccount, error)
 | 
				
			||||||
	UpdateUserPassword(ctx context.Context, input UpdateUserPassword) (*UpdateUserPasswordPayload, error)
 | 
						UpdateUserPassword(ctx context.Context, input UpdateUserPassword) (*UpdateUserPasswordPayload, error)
 | 
				
			||||||
	UpdateUserRole(ctx context.Context, input UpdateUserRole) (*UpdateUserRolePayload, error)
 | 
						UpdateUserRole(ctx context.Context, input UpdateUserRole) (*UpdateUserRolePayload, error)
 | 
				
			||||||
	UpdateUserInfo(ctx context.Context, input UpdateUserInfo) (*UpdateUserInfoPayload, error)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type NotificationResolver interface {
 | 
					type NotificationResolver interface {
 | 
				
			||||||
	ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error)
 | 
						ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error)
 | 
				
			||||||
@@ -1500,18 +1493,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		return e.complexity.Mutation.UpdateTeamMemberRole(childComplexity, args["input"].(UpdateTeamMemberRole)), true
 | 
							return e.complexity.Mutation.UpdateTeamMemberRole(childComplexity, args["input"].(UpdateTeamMemberRole)), true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case "Mutation.updateUserInfo":
 | 
					 | 
				
			||||||
		if e.complexity.Mutation.UpdateUserInfo == nil {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		args, err := ec.field_Mutation_updateUserInfo_args(context.TODO(), rawArgs)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return 0, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return e.complexity.Mutation.UpdateUserInfo(childComplexity, args["input"].(UpdateUserInfo)), true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case "Mutation.updateUserPassword":
 | 
						case "Mutation.updateUserPassword":
 | 
				
			||||||
		if e.complexity.Mutation.UpdateUserPassword == nil {
 | 
							if e.complexity.Mutation.UpdateUserPassword == nil {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
@@ -2303,13 +2284,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		return e.complexity.UpdateTeamMemberRolePayload.TeamID(childComplexity), true
 | 
							return e.complexity.UpdateTeamMemberRolePayload.TeamID(childComplexity), true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case "UpdateUserInfoPayload.user":
 | 
					 | 
				
			||||||
		if e.complexity.UpdateUserInfoPayload.User == nil {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return e.complexity.UpdateUserInfoPayload.User(childComplexity), true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case "UpdateUserPasswordPayload.ok":
 | 
						case "UpdateUserPasswordPayload.ok":
 | 
				
			||||||
		if e.complexity.UpdateUserPasswordPayload.Ok == nil {
 | 
							if e.complexity.UpdateUserPasswordPayload.Ok == nil {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
@@ -2331,13 +2305,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		return e.complexity.UpdateUserRolePayload.User(childComplexity), true
 | 
							return e.complexity.UpdateUserRolePayload.User(childComplexity), true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case "UserAccount.bio":
 | 
					 | 
				
			||||||
		if e.complexity.UserAccount.Bio == nil {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return e.complexity.UserAccount.Bio(childComplexity), true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case "UserAccount.createdAt":
 | 
						case "UserAccount.createdAt":
 | 
				
			||||||
		if e.complexity.UserAccount.CreatedAt == nil {
 | 
							if e.complexity.UserAccount.CreatedAt == nil {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
@@ -2552,7 +2519,6 @@ type UserAccount {
 | 
				
			|||||||
  createdAt: Time!
 | 
					  createdAt: Time!
 | 
				
			||||||
  fullName: String!
 | 
					  fullName: String!
 | 
				
			||||||
  initials: String!
 | 
					  initials: String!
 | 
				
			||||||
  bio: String!
 | 
					 | 
				
			||||||
  role: Role!
 | 
					  role: Role!
 | 
				
			||||||
  username: String!
 | 
					  username: String!
 | 
				
			||||||
  profileIcon: ProfileIcon!
 | 
					  profileIcon: ProfileIcon!
 | 
				
			||||||
@@ -2648,7 +2614,6 @@ enum ObjectType {
 | 
				
			|||||||
  TEAM
 | 
					  TEAM
 | 
				
			||||||
  PROJECT
 | 
					  PROJECT
 | 
				
			||||||
  TASK
 | 
					  TASK
 | 
				
			||||||
  TASK_GROUP
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
					directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
				
			||||||
@@ -2852,20 +2817,20 @@ type UpdateProjectMemberRolePayload {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extend type Mutation {
 | 
					extend type Mutation {
 | 
				
			||||||
  createTask(input: NewTask!):
 | 
					  createTask(input: NewTask!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK_GROUP)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  deleteTask(input: DeleteTaskInput!):
 | 
					  deleteTask(input: DeleteTaskInput!):
 | 
				
			||||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
					  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskLocation(input: NewTaskLocation!):
 | 
					  updateTaskLocation(input: NewTaskLocation!):
 | 
				
			||||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskName(input: UpdateTaskName!):
 | 
					  updateTaskName(input: UpdateTaskName!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  setTaskComplete(input: SetTaskComplete!):
 | 
					  setTaskComplete(input: SetTaskComplete!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
					  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  assignTask(input: AssignTaskInput):
 | 
					  assignTask(input: AssignTaskInput):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
				
			||||||
@@ -2874,7 +2839,7 @@ extend type Mutation {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input NewTask {
 | 
					input NewTask {
 | 
				
			||||||
  taskGroupID: UUID!
 | 
					  taskGroupID: String!
 | 
				
			||||||
  name: String!
 | 
					  name: String!
 | 
				
			||||||
  position: Float!
 | 
					  position: Float!
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -3198,19 +3163,6 @@ extend type Mutation {
 | 
				
			|||||||
  updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
 | 
					  updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
 | 
				
			||||||
  updateUserRole(input: UpdateUserRole!):
 | 
					  updateUserRole(input: UpdateUserRole!):
 | 
				
			||||||
   UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
					   UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
				
			||||||
  updateUserInfo(input: UpdateUserInfo!):
 | 
					 | 
				
			||||||
    UpdateUserInfoPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateUserInfoPayload {
 | 
					 | 
				
			||||||
  user: UserAccount!
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
input UpdateUserInfo {
 | 
					 | 
				
			||||||
  name: String!
 | 
					 | 
				
			||||||
  initials: String!
 | 
					 | 
				
			||||||
  email: String!
 | 
					 | 
				
			||||||
  bio: String!
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input UpdateUserPassword {
 | 
					input UpdateUserPassword {
 | 
				
			||||||
@@ -3969,20 +3921,6 @@ func (ec *executionContext) field_Mutation_updateTeamMemberRole_args(ctx context
 | 
				
			|||||||
	return args, nil
 | 
						return args, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) field_Mutation_updateUserInfo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 | 
					 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	args := map[string]interface{}{}
 | 
					 | 
				
			||||||
	var arg0 UpdateUserInfo
 | 
					 | 
				
			||||||
	if tmp, ok := rawArgs["input"]; ok {
 | 
					 | 
				
			||||||
		arg0, err = ec.unmarshalNUpdateUserInfo2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserInfo(ctx, tmp)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	args["input"] = arg0
 | 
					 | 
				
			||||||
	return args, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) field_Mutation_updateUserPassword_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 | 
					func (ec *executionContext) field_Mutation_updateUserPassword_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	args := map[string]interface{}{}
 | 
						args := map[string]interface{}{}
 | 
				
			||||||
@@ -6534,7 +6472,7 @@ func (ec *executionContext) _Mutation_createTask(ctx context.Context, field grap
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK_GROUP")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -6607,7 +6545,7 @@ func (ec *executionContext) _Mutation_deleteTask(ctx context.Context, field grap
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -6680,7 +6618,7 @@ func (ec *executionContext) _Mutation_updateTaskDescription(ctx context.Context,
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -6753,7 +6691,7 @@ func (ec *executionContext) _Mutation_updateTaskLocation(ctx context.Context, fi
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -6826,7 +6764,7 @@ func (ec *executionContext) _Mutation_updateTaskName(ctx context.Context, field
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -6899,7 +6837,7 @@ func (ec *executionContext) _Mutation_setTaskComplete(ctx context.Context, field
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -6972,7 +6910,7 @@ func (ec *executionContext) _Mutation_updateTaskDueDate(ctx context.Context, fie
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
								typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -9283,79 +9221,6 @@ func (ec *executionContext) _Mutation_updateUserRole(ctx context.Context, field
 | 
				
			|||||||
	return ec.marshalNUpdateUserRolePayload2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserRolePayload(ctx, field.Selections, res)
 | 
						return ec.marshalNUpdateUserRolePayload2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserRolePayload(ctx, field.Selections, res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) _Mutation_updateUserInfo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if r := recover(); r != nil {
 | 
					 | 
				
			||||||
			ec.Error(ctx, ec.Recover(ctx, r))
 | 
					 | 
				
			||||||
			ret = graphql.Null
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	fc := &graphql.FieldContext{
 | 
					 | 
				
			||||||
		Object:   "Mutation",
 | 
					 | 
				
			||||||
		Field:    field,
 | 
					 | 
				
			||||||
		Args:     nil,
 | 
					 | 
				
			||||||
		IsMethod: true,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx = graphql.WithFieldContext(ctx, fc)
 | 
					 | 
				
			||||||
	rawArgs := field.ArgumentMap(ec.Variables)
 | 
					 | 
				
			||||||
	args, err := ec.field_Mutation_updateUserInfo_args(ctx, rawArgs)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ec.Error(ctx, err)
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fc.Args = args
 | 
					 | 
				
			||||||
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 | 
					 | 
				
			||||||
		directive0 := func(rctx context.Context) (interface{}, error) {
 | 
					 | 
				
			||||||
			ctx = rctx // use context from middleware stack in children
 | 
					 | 
				
			||||||
			return ec.resolvers.Mutation().UpdateUserInfo(rctx, args["input"].(UpdateUserInfo))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		directive1 := func(ctx context.Context) (interface{}, error) {
 | 
					 | 
				
			||||||
			roles, err := ec.unmarshalNRoleLevel2ᚕgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐRoleLevelᚄ(ctx, []interface{}{"ADMIN"})
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			level, err := ec.unmarshalNActionLevel2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐActionLevel(ctx, "ORG")
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "ORG")
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if ec.directives.HasRole == nil {
 | 
					 | 
				
			||||||
				return nil, errors.New("directive hasRole is not implemented")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return ec.directives.HasRole(ctx, nil, directive0, roles, level, typeArg)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		tmp, err := directive1(rctx)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if tmp == nil {
 | 
					 | 
				
			||||||
			return nil, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if data, ok := tmp.(*UpdateUserInfoPayload); ok {
 | 
					 | 
				
			||||||
			return data, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/jordanknott/taskcafe/internal/graph.UpdateUserInfoPayload`, tmp)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ec.Error(ctx, err)
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if resTmp == nil {
 | 
					 | 
				
			||||||
		if !graphql.HasFieldError(ctx, fc) {
 | 
					 | 
				
			||||||
			ec.Errorf(ctx, "must not be null")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	res := resTmp.(*UpdateUserInfoPayload)
 | 
					 | 
				
			||||||
	fc.Result = res
 | 
					 | 
				
			||||||
	return ec.marshalNUpdateUserInfoPayload2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserInfoPayload(ctx, field.Selections, res)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) _Notification_id(ctx context.Context, field graphql.CollectedField, obj *db.Notification) (ret graphql.Marshaler) {
 | 
					func (ec *executionContext) _Notification_id(ctx context.Context, field graphql.CollectedField, obj *db.Notification) (ret graphql.Marshaler) {
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if r := recover(); r != nil {
 | 
							if r := recover(); r != nil {
 | 
				
			||||||
@@ -13040,40 +12905,6 @@ func (ec *executionContext) _UpdateTeamMemberRolePayload_member(ctx context.Cont
 | 
				
			|||||||
	return ec.marshalNMember2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐMember(ctx, field.Selections, res)
 | 
						return ec.marshalNMember2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐMember(ctx, field.Selections, res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) _UpdateUserInfoPayload_user(ctx context.Context, field graphql.CollectedField, obj *UpdateUserInfoPayload) (ret graphql.Marshaler) {
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if r := recover(); r != nil {
 | 
					 | 
				
			||||||
			ec.Error(ctx, ec.Recover(ctx, r))
 | 
					 | 
				
			||||||
			ret = graphql.Null
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	fc := &graphql.FieldContext{
 | 
					 | 
				
			||||||
		Object:   "UpdateUserInfoPayload",
 | 
					 | 
				
			||||||
		Field:    field,
 | 
					 | 
				
			||||||
		Args:     nil,
 | 
					 | 
				
			||||||
		IsMethod: false,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx = graphql.WithFieldContext(ctx, fc)
 | 
					 | 
				
			||||||
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 | 
					 | 
				
			||||||
		ctx = rctx // use context from middleware stack in children
 | 
					 | 
				
			||||||
		return obj.User, nil
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ec.Error(ctx, err)
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if resTmp == nil {
 | 
					 | 
				
			||||||
		if !graphql.HasFieldError(ctx, fc) {
 | 
					 | 
				
			||||||
			ec.Errorf(ctx, "must not be null")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	res := resTmp.(*db.UserAccount)
 | 
					 | 
				
			||||||
	fc.Result = res
 | 
					 | 
				
			||||||
	return ec.marshalNUserAccount2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋdbᚐUserAccount(ctx, field.Selections, res)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) _UpdateUserPasswordPayload_ok(ctx context.Context, field graphql.CollectedField, obj *UpdateUserPasswordPayload) (ret graphql.Marshaler) {
 | 
					func (ec *executionContext) _UpdateUserPasswordPayload_ok(ctx context.Context, field graphql.CollectedField, obj *UpdateUserPasswordPayload) (ret graphql.Marshaler) {
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if r := recover(); r != nil {
 | 
							if r := recover(); r != nil {
 | 
				
			||||||
@@ -13346,40 +13177,6 @@ func (ec *executionContext) _UserAccount_initials(ctx context.Context, field gra
 | 
				
			|||||||
	return ec.marshalNString2string(ctx, field.Selections, res)
 | 
						return ec.marshalNString2string(ctx, field.Selections, res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) _UserAccount_bio(ctx context.Context, field graphql.CollectedField, obj *db.UserAccount) (ret graphql.Marshaler) {
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if r := recover(); r != nil {
 | 
					 | 
				
			||||||
			ec.Error(ctx, ec.Recover(ctx, r))
 | 
					 | 
				
			||||||
			ret = graphql.Null
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	fc := &graphql.FieldContext{
 | 
					 | 
				
			||||||
		Object:   "UserAccount",
 | 
					 | 
				
			||||||
		Field:    field,
 | 
					 | 
				
			||||||
		Args:     nil,
 | 
					 | 
				
			||||||
		IsMethod: false,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx = graphql.WithFieldContext(ctx, fc)
 | 
					 | 
				
			||||||
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 | 
					 | 
				
			||||||
		ctx = rctx // use context from middleware stack in children
 | 
					 | 
				
			||||||
		return obj.Bio, nil
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ec.Error(ctx, err)
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if resTmp == nil {
 | 
					 | 
				
			||||||
		if !graphql.HasFieldError(ctx, fc) {
 | 
					 | 
				
			||||||
			ec.Errorf(ctx, "must not be null")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	res := resTmp.(string)
 | 
					 | 
				
			||||||
	fc.Result = res
 | 
					 | 
				
			||||||
	return ec.marshalNString2string(ctx, field.Selections, res)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) _UserAccount_role(ctx context.Context, field graphql.CollectedField, obj *db.UserAccount) (ret graphql.Marshaler) {
 | 
					func (ec *executionContext) _UserAccount_role(ctx context.Context, field graphql.CollectedField, obj *db.UserAccount) (ret graphql.Marshaler) {
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if r := recover(); r != nil {
 | 
							if r := recover(); r != nil {
 | 
				
			||||||
@@ -15195,7 +14992,7 @@ func (ec *executionContext) unmarshalInputNewTask(ctx context.Context, obj inter
 | 
				
			|||||||
		switch k {
 | 
							switch k {
 | 
				
			||||||
		case "taskGroupID":
 | 
							case "taskGroupID":
 | 
				
			||||||
			var err error
 | 
								var err error
 | 
				
			||||||
			it.TaskGroupID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v)
 | 
								it.TaskGroupID, err = ec.unmarshalNString2string(ctx, v)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return it, err
 | 
									return it, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -15913,42 +15710,6 @@ func (ec *executionContext) unmarshalInputUpdateTeamMemberRole(ctx context.Conte
 | 
				
			|||||||
	return it, nil
 | 
						return it, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) unmarshalInputUpdateUserInfo(ctx context.Context, obj interface{}) (UpdateUserInfo, error) {
 | 
					 | 
				
			||||||
	var it UpdateUserInfo
 | 
					 | 
				
			||||||
	var asMap = obj.(map[string]interface{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for k, v := range asMap {
 | 
					 | 
				
			||||||
		switch k {
 | 
					 | 
				
			||||||
		case "name":
 | 
					 | 
				
			||||||
			var err error
 | 
					 | 
				
			||||||
			it.Name, err = ec.unmarshalNString2string(ctx, v)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return it, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		case "initials":
 | 
					 | 
				
			||||||
			var err error
 | 
					 | 
				
			||||||
			it.Initials, err = ec.unmarshalNString2string(ctx, v)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return it, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		case "email":
 | 
					 | 
				
			||||||
			var err error
 | 
					 | 
				
			||||||
			it.Email, err = ec.unmarshalNString2string(ctx, v)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return it, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		case "bio":
 | 
					 | 
				
			||||||
			var err error
 | 
					 | 
				
			||||||
			it.Bio, err = ec.unmarshalNString2string(ctx, v)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return it, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return it, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) unmarshalInputUpdateUserPassword(ctx context.Context, obj interface{}) (UpdateUserPassword, error) {
 | 
					func (ec *executionContext) unmarshalInputUpdateUserPassword(ctx context.Context, obj interface{}) (UpdateUserPassword, error) {
 | 
				
			||||||
	var it UpdateUserPassword
 | 
						var it UpdateUserPassword
 | 
				
			||||||
	var asMap = obj.(map[string]interface{})
 | 
						var asMap = obj.(map[string]interface{})
 | 
				
			||||||
@@ -16910,11 +16671,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
 | 
				
			|||||||
			if out.Values[i] == graphql.Null {
 | 
								if out.Values[i] == graphql.Null {
 | 
				
			||||||
				invalids++
 | 
									invalids++
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case "updateUserInfo":
 | 
					 | 
				
			||||||
			out.Values[i] = ec._Mutation_updateUserInfo(ctx, field)
 | 
					 | 
				
			||||||
			if out.Values[i] == graphql.Null {
 | 
					 | 
				
			||||||
				invalids++
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic("unknown field " + strconv.Quote(field.Name))
 | 
								panic("unknown field " + strconv.Quote(field.Name))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -18479,33 +18235,6 @@ func (ec *executionContext) _UpdateTeamMemberRolePayload(ctx context.Context, se
 | 
				
			|||||||
	return out
 | 
						return out
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var updateUserInfoPayloadImplementors = []string{"UpdateUserInfoPayload"}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) _UpdateUserInfoPayload(ctx context.Context, sel ast.SelectionSet, obj *UpdateUserInfoPayload) graphql.Marshaler {
 | 
					 | 
				
			||||||
	fields := graphql.CollectFields(ec.OperationContext, sel, updateUserInfoPayloadImplementors)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	out := graphql.NewFieldSet(fields)
 | 
					 | 
				
			||||||
	var invalids uint32
 | 
					 | 
				
			||||||
	for i, field := range fields {
 | 
					 | 
				
			||||||
		switch field.Name {
 | 
					 | 
				
			||||||
		case "__typename":
 | 
					 | 
				
			||||||
			out.Values[i] = graphql.MarshalString("UpdateUserInfoPayload")
 | 
					 | 
				
			||||||
		case "user":
 | 
					 | 
				
			||||||
			out.Values[i] = ec._UpdateUserInfoPayload_user(ctx, field, obj)
 | 
					 | 
				
			||||||
			if out.Values[i] == graphql.Null {
 | 
					 | 
				
			||||||
				invalids++
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			panic("unknown field " + strconv.Quote(field.Name))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	out.Dispatch()
 | 
					 | 
				
			||||||
	if invalids > 0 {
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return out
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var updateUserPasswordPayloadImplementors = []string{"UpdateUserPasswordPayload"}
 | 
					var updateUserPasswordPayloadImplementors = []string{"UpdateUserPasswordPayload"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) _UpdateUserPasswordPayload(ctx context.Context, sel ast.SelectionSet, obj *UpdateUserPasswordPayload) graphql.Marshaler {
 | 
					func (ec *executionContext) _UpdateUserPasswordPayload(ctx context.Context, sel ast.SelectionSet, obj *UpdateUserPasswordPayload) graphql.Marshaler {
 | 
				
			||||||
@@ -18610,11 +18339,6 @@ func (ec *executionContext) _UserAccount(ctx context.Context, sel ast.SelectionS
 | 
				
			|||||||
			if out.Values[i] == graphql.Null {
 | 
								if out.Values[i] == graphql.Null {
 | 
				
			||||||
				atomic.AddUint32(&invalids, 1)
 | 
									atomic.AddUint32(&invalids, 1)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case "bio":
 | 
					 | 
				
			||||||
			out.Values[i] = ec._UserAccount_bio(ctx, field, obj)
 | 
					 | 
				
			||||||
			if out.Values[i] == graphql.Null {
 | 
					 | 
				
			||||||
				atomic.AddUint32(&invalids, 1)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		case "role":
 | 
							case "role":
 | 
				
			||||||
			field := field
 | 
								field := field
 | 
				
			||||||
			out.Concurrently(i, func() (res graphql.Marshaler) {
 | 
								out.Concurrently(i, func() (res graphql.Marshaler) {
 | 
				
			||||||
@@ -20479,24 +20203,6 @@ func (ec *executionContext) marshalNUpdateTeamMemberRolePayload2ᚖgithubᚗcom
 | 
				
			|||||||
	return ec._UpdateTeamMemberRolePayload(ctx, sel, v)
 | 
						return ec._UpdateTeamMemberRolePayload(ctx, sel, v)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) unmarshalNUpdateUserInfo2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserInfo(ctx context.Context, v interface{}) (UpdateUserInfo, error) {
 | 
					 | 
				
			||||||
	return ec.unmarshalInputUpdateUserInfo(ctx, v)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) marshalNUpdateUserInfoPayload2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserInfoPayload(ctx context.Context, sel ast.SelectionSet, v UpdateUserInfoPayload) graphql.Marshaler {
 | 
					 | 
				
			||||||
	return ec._UpdateUserInfoPayload(ctx, sel, &v)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) marshalNUpdateUserInfoPayload2ᚖgithubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserInfoPayload(ctx context.Context, sel ast.SelectionSet, v *UpdateUserInfoPayload) graphql.Marshaler {
 | 
					 | 
				
			||||||
	if v == nil {
 | 
					 | 
				
			||||||
		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 | 
					 | 
				
			||||||
			ec.Errorf(ctx, "must not be null")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return graphql.Null
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ec._UpdateUserInfoPayload(ctx, sel, v)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ec *executionContext) unmarshalNUpdateUserPassword2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserPassword(ctx context.Context, v interface{}) (UpdateUserPassword, error) {
 | 
					func (ec *executionContext) unmarshalNUpdateUserPassword2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐUpdateUserPassword(ctx context.Context, v interface{}) (UpdateUserPassword, error) {
 | 
				
			||||||
	return ec.unmarshalInputUpdateUserPassword(ctx, v)
 | 
						return ec.unmarshalInputUpdateUserPassword(ctx, v)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,6 @@ import (
 | 
				
			|||||||
	"github.com/jordanknott/taskcafe/internal/db"
 | 
						"github.com/jordanknott/taskcafe/internal/db"
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/utils"
 | 
						"github.com/jordanknott/taskcafe/internal/utils"
 | 
				
			||||||
	log "github.com/sirupsen/logrus"
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/vektah/gqlparser/v2/gqlerror"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewHandler returns a new graphql endpoint handler.
 | 
					// NewHandler returns a new graphql endpoint handler.
 | 
				
			||||||
@@ -52,8 +51,6 @@ func NewHandler(repo db.Repository) http.Handler {
 | 
				
			|||||||
			fieldName = "TeamID"
 | 
								fieldName = "TeamID"
 | 
				
			||||||
		case ObjectTypeTask:
 | 
							case ObjectTypeTask:
 | 
				
			||||||
			fieldName = "TaskID"
 | 
								fieldName = "TaskID"
 | 
				
			||||||
		case ObjectTypeTaskGroup:
 | 
					 | 
				
			||||||
			fieldName = "TaskGroupID"
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			fieldName = "ProjectID"
 | 
								fieldName = "ProjectID"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -71,13 +68,6 @@ func NewHandler(repo db.Repository) http.Handler {
 | 
				
			|||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return nil, err
 | 
										return nil, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if typeArg == ObjectTypeTaskGroup {
 | 
					 | 
				
			||||||
				log.WithFields(log.Fields{"subjectID": subjectID}).Info("fetching project ID using task group ID")
 | 
					 | 
				
			||||||
				taskGroup, err := repo.GetTaskGroupByID(ctx, subjectID)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return nil, err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				subjectID = taskGroup.ProjectID
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			roles, err := GetProjectRoles(ctx, repo, subjectID)
 | 
								roles, err := GetProjectRoles(ctx, repo, subjectID)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@@ -196,13 +186,3 @@ func GetActionType(actionType int32) ActionType {
 | 
				
			|||||||
		panic("Not a valid entity type!")
 | 
							panic("Not a valid entity type!")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// NotFoundError creates a 404 gqlerror
 | 
					 | 
				
			||||||
func NotFoundError(message string) error {
 | 
					 | 
				
			||||||
	return &gqlerror.Error{
 | 
					 | 
				
			||||||
		Message: message,
 | 
					 | 
				
			||||||
		Extensions: map[string]interface{}{
 | 
					 | 
				
			||||||
			"code": "404",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -229,9 +229,9 @@ type NewRefreshToken struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type NewTask struct {
 | 
					type NewTask struct {
 | 
				
			||||||
	TaskGroupID uuid.UUID `json:"taskGroupID"`
 | 
						TaskGroupID string  `json:"taskGroupID"`
 | 
				
			||||||
	Name        string    `json:"name"`
 | 
						Name        string  `json:"name"`
 | 
				
			||||||
	Position    float64   `json:"position"`
 | 
						Position    float64 `json:"position"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type NewTaskGroup struct {
 | 
					type NewTaskGroup struct {
 | 
				
			||||||
@@ -455,17 +455,6 @@ type UpdateTeamMemberRolePayload struct {
 | 
				
			|||||||
	Member *Member   `json:"member"`
 | 
						Member *Member   `json:"member"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UpdateUserInfo struct {
 | 
					 | 
				
			||||||
	Name     string `json:"name"`
 | 
					 | 
				
			||||||
	Initials string `json:"initials"`
 | 
					 | 
				
			||||||
	Email    string `json:"email"`
 | 
					 | 
				
			||||||
	Bio      string `json:"bio"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateUserInfoPayload struct {
 | 
					 | 
				
			||||||
	User *db.UserAccount `json:"user"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateUserPassword struct {
 | 
					type UpdateUserPassword struct {
 | 
				
			||||||
	UserID   uuid.UUID `json:"userID"`
 | 
						UserID   uuid.UUID `json:"userID"`
 | 
				
			||||||
	Password string    `json:"password"`
 | 
						Password string    `json:"password"`
 | 
				
			||||||
@@ -648,11 +637,10 @@ func (e EntityType) MarshalGQL(w io.Writer) {
 | 
				
			|||||||
type ObjectType string
 | 
					type ObjectType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	ObjectTypeOrg       ObjectType = "ORG"
 | 
						ObjectTypeOrg     ObjectType = "ORG"
 | 
				
			||||||
	ObjectTypeTeam      ObjectType = "TEAM"
 | 
						ObjectTypeTeam    ObjectType = "TEAM"
 | 
				
			||||||
	ObjectTypeProject   ObjectType = "PROJECT"
 | 
						ObjectTypeProject ObjectType = "PROJECT"
 | 
				
			||||||
	ObjectTypeTask      ObjectType = "TASK"
 | 
						ObjectTypeTask    ObjectType = "TASK"
 | 
				
			||||||
	ObjectTypeTaskGroup ObjectType = "TASK_GROUP"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var AllObjectType = []ObjectType{
 | 
					var AllObjectType = []ObjectType{
 | 
				
			||||||
@@ -660,12 +648,11 @@ var AllObjectType = []ObjectType{
 | 
				
			|||||||
	ObjectTypeTeam,
 | 
						ObjectTypeTeam,
 | 
				
			||||||
	ObjectTypeProject,
 | 
						ObjectTypeProject,
 | 
				
			||||||
	ObjectTypeTask,
 | 
						ObjectTypeTask,
 | 
				
			||||||
	ObjectTypeTaskGroup,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (e ObjectType) IsValid() bool {
 | 
					func (e ObjectType) IsValid() bool {
 | 
				
			||||||
	switch e {
 | 
						switch e {
 | 
				
			||||||
	case ObjectTypeOrg, ObjectTypeTeam, ObjectTypeProject, ObjectTypeTask, ObjectTypeTaskGroup:
 | 
						case ObjectTypeOrg, ObjectTypeTeam, ObjectTypeProject, ObjectTypeTask:
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,6 @@ type UserAccount {
 | 
				
			|||||||
  createdAt: Time!
 | 
					  createdAt: Time!
 | 
				
			||||||
  fullName: String!
 | 
					  fullName: String!
 | 
				
			||||||
  initials: String!
 | 
					  initials: String!
 | 
				
			||||||
  bio: String!
 | 
					 | 
				
			||||||
  role: Role!
 | 
					  role: Role!
 | 
				
			||||||
  username: String!
 | 
					  username: String!
 | 
				
			||||||
  profileIcon: ProfileIcon!
 | 
					  profileIcon: ProfileIcon!
 | 
				
			||||||
@@ -174,7 +173,6 @@ enum ObjectType {
 | 
				
			|||||||
  TEAM
 | 
					  TEAM
 | 
				
			||||||
  PROJECT
 | 
					  PROJECT
 | 
				
			||||||
  TASK
 | 
					  TASK
 | 
				
			||||||
  TASK_GROUP
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
					directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
				
			||||||
@@ -378,20 +376,20 @@ type UpdateProjectMemberRolePayload {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extend type Mutation {
 | 
					extend type Mutation {
 | 
				
			||||||
  createTask(input: NewTask!):
 | 
					  createTask(input: NewTask!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK_GROUP)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  deleteTask(input: DeleteTaskInput!):
 | 
					  deleteTask(input: DeleteTaskInput!):
 | 
				
			||||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
					  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskLocation(input: NewTaskLocation!):
 | 
					  updateTaskLocation(input: NewTaskLocation!):
 | 
				
			||||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskName(input: UpdateTaskName!):
 | 
					  updateTaskName(input: UpdateTaskName!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  setTaskComplete(input: SetTaskComplete!):
 | 
					  setTaskComplete(input: SetTaskComplete!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
					  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  assignTask(input: AssignTaskInput):
 | 
					  assignTask(input: AssignTaskInput):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
				
			||||||
@@ -400,7 +398,7 @@ extend type Mutation {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input NewTask {
 | 
					input NewTask {
 | 
				
			||||||
  taskGroupID: UUID!
 | 
					  taskGroupID: String!
 | 
				
			||||||
  name: String!
 | 
					  name: String!
 | 
				
			||||||
  position: Float!
 | 
					  position: Float!
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -724,19 +722,6 @@ extend type Mutation {
 | 
				
			|||||||
  updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
 | 
					  updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
 | 
				
			||||||
  updateUserRole(input: UpdateUserRole!):
 | 
					  updateUserRole(input: UpdateUserRole!):
 | 
				
			||||||
   UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
					   UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
				
			||||||
  updateUserInfo(input: UpdateUserInfo!):
 | 
					 | 
				
			||||||
    UpdateUserInfoPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateUserInfoPayload {
 | 
					 | 
				
			||||||
  user: UserAccount!
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
input UpdateUserInfo {
 | 
					 | 
				
			||||||
  name: String!
 | 
					 | 
				
			||||||
  initials: String!
 | 
					 | 
				
			||||||
  email: String!
 | 
					 | 
				
			||||||
  bio: String!
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input UpdateUserPassword {
 | 
					input UpdateUserPassword {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -179,9 +179,14 @@ func (r *mutationResolver) UpdateProjectMemberRole(ctx context.Context, input Up
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*db.Task, error) {
 | 
					func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*db.Task, error) {
 | 
				
			||||||
 | 
						taskGroupID, err := uuid.Parse(input.TaskGroupID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.WithError(err).Error("issue while parsing task group ID")
 | 
				
			||||||
 | 
							return &db.Task{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	createdAt := time.Now().UTC()
 | 
						createdAt := time.Now().UTC()
 | 
				
			||||||
	log.WithFields(log.Fields{"positon": input.Position, "taskGroupID": input.TaskGroupID}).Info("creating task")
 | 
						log.WithFields(log.Fields{"positon": input.Position, "taskGroupID": taskGroupID}).Info("creating task")
 | 
				
			||||||
	task, err := r.Repository.CreateTask(ctx, db.CreateTaskParams{input.TaskGroupID, createdAt, input.Name, input.Position})
 | 
						task, err := r.Repository.CreateTask(ctx, db.CreateTaskParams{taskGroupID, createdAt, input.Name, input.Position})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.WithError(err).Error("issue while creating task")
 | 
							log.WithError(err).Error("issue while creating task")
 | 
				
			||||||
		return &db.Task{}, err
 | 
							return &db.Task{}, err
 | 
				
			||||||
@@ -233,9 +238,6 @@ func (r *mutationResolver) SetTaskComplete(ctx context.Context, input SetTaskCom
 | 
				
			|||||||
	completedAt := time.Now().UTC()
 | 
						completedAt := time.Now().UTC()
 | 
				
			||||||
	task, err := r.Repository.SetTaskComplete(ctx, db.SetTaskCompleteParams{TaskID: input.TaskID, Complete: input.Complete, CompletedAt: sql.NullTime{Time: completedAt, Valid: true}})
 | 
						task, err := r.Repository.SetTaskComplete(ctx, db.SetTaskCompleteParams{TaskID: input.TaskID, Complete: input.Complete, CompletedAt: sql.NullTime{Time: completedAt, Valid: true}})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if err == sql.ErrNoRows {
 | 
					 | 
				
			||||||
			return &db.Task{}, NotFoundError("task does not exist")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return &db.Task{}, err
 | 
							return &db.Task{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &task, nil
 | 
						return &task, nil
 | 
				
			||||||
@@ -824,17 +826,6 @@ func (r *mutationResolver) UpdateUserRole(ctx context.Context, input UpdateUserR
 | 
				
			|||||||
	return &UpdateUserRolePayload{User: &user}, nil
 | 
						return &UpdateUserRolePayload{User: &user}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *mutationResolver) UpdateUserInfo(ctx context.Context, input UpdateUserInfo) (*UpdateUserInfoPayload, error) {
 | 
					 | 
				
			||||||
	userID, ok := GetUserID(ctx)
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		return &UpdateUserInfoPayload{}, errors.New("invalid user ID")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	user, err := r.Repository.UpdateUserAccountInfo(ctx, db.UpdateUserAccountInfoParams{
 | 
					 | 
				
			||||||
		Bio: input.Bio, FullName: input.Name, Initials: input.Initials, Email: input.Email, UserID: userID,
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	return &UpdateUserInfoPayload{User: &user}, err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *notificationResolver) ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error) {
 | 
					func (r *notificationResolver) ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error) {
 | 
				
			||||||
	return obj.NotificationID, nil
 | 
						return obj.NotificationID, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1031,14 +1022,6 @@ func (r *queryResolver) FindProject(ctx context.Context, input FindProject) (*db
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (r *queryResolver) FindTask(ctx context.Context, input FindTask) (*db.Task, error) {
 | 
					func (r *queryResolver) FindTask(ctx context.Context, input FindTask) (*db.Task, error) {
 | 
				
			||||||
	task, err := r.Repository.GetTaskByID(ctx, input.TaskID)
 | 
						task, err := r.Repository.GetTaskByID(ctx, input.TaskID)
 | 
				
			||||||
	if err == sql.ErrNoRows {
 | 
					 | 
				
			||||||
		return &db.Task{}, &gqlerror.Error{
 | 
					 | 
				
			||||||
			Message: "Task does not exist",
 | 
					 | 
				
			||||||
			Extensions: map[string]interface{}{
 | 
					 | 
				
			||||||
				"code": "404",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &task, err
 | 
						return &task, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1246,9 +1229,6 @@ func (r *taskResolver) Assigned(ctx context.Context, obj *db.Task) ([]Member, er
 | 
				
			|||||||
	taskMemberLinks, err := r.Repository.GetAssignedMembersForTask(ctx, obj.TaskID)
 | 
						taskMemberLinks, err := r.Repository.GetAssignedMembersForTask(ctx, obj.TaskID)
 | 
				
			||||||
	taskMembers := []Member{}
 | 
						taskMembers := []Member{}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if err == sql.ErrNoRows {
 | 
					 | 
				
			||||||
			return taskMembers, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return taskMembers, err
 | 
							return taskMembers, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, taskMemberLink := range taskMemberLinks {
 | 
						for _, taskMemberLink := range taskMemberLinks {
 | 
				
			||||||
@@ -1283,19 +1263,11 @@ func (r *taskResolver) Assigned(ctx context.Context, obj *db.Task) ([]Member, er
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *taskResolver) Labels(ctx context.Context, obj *db.Task) ([]db.TaskLabel, error) {
 | 
					func (r *taskResolver) Labels(ctx context.Context, obj *db.Task) ([]db.TaskLabel, error) {
 | 
				
			||||||
	labels, err := r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID)
 | 
						return r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID)
 | 
				
			||||||
	if err != nil && err != sql.ErrNoRows {
 | 
					 | 
				
			||||||
		return []db.TaskLabel{}, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return labels, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *taskResolver) Checklists(ctx context.Context, obj *db.Task) ([]db.TaskChecklist, error) {
 | 
					func (r *taskResolver) Checklists(ctx context.Context, obj *db.Task) ([]db.TaskChecklist, error) {
 | 
				
			||||||
	checklists, err := r.Repository.GetTaskChecklistsForTask(ctx, obj.TaskID)
 | 
						return r.Repository.GetTaskChecklistsForTask(ctx, obj.TaskID)
 | 
				
			||||||
	if err != nil && err != sql.ErrNoRows {
 | 
					 | 
				
			||||||
		return []db.TaskChecklist{}, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return checklists, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *taskResolver) Badges(ctx context.Context, obj *db.Task) (*TaskBadges, error) {
 | 
					func (r *taskResolver) Badges(ctx context.Context, obj *db.Task) (*TaskBadges, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,6 @@ type UserAccount {
 | 
				
			|||||||
  createdAt: Time!
 | 
					  createdAt: Time!
 | 
				
			||||||
  fullName: String!
 | 
					  fullName: String!
 | 
				
			||||||
  initials: String!
 | 
					  initials: String!
 | 
				
			||||||
  bio: String!
 | 
					 | 
				
			||||||
  role: Role!
 | 
					  role: Role!
 | 
				
			||||||
  username: String!
 | 
					  username: String!
 | 
				
			||||||
  profileIcon: ProfileIcon!
 | 
					  profileIcon: ProfileIcon!
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@ enum ObjectType {
 | 
				
			|||||||
  TEAM
 | 
					  TEAM
 | 
				
			||||||
  PROJECT
 | 
					  PROJECT
 | 
				
			||||||
  TASK
 | 
					  TASK
 | 
				
			||||||
  TASK_GROUP
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
					directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,19 @@
 | 
				
			|||||||
extend type Mutation {
 | 
					extend type Mutation {
 | 
				
			||||||
  createTask(input: NewTask!):
 | 
					  createTask(input: NewTask!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK_GROUP)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  deleteTask(input: DeleteTaskInput!):
 | 
					  deleteTask(input: DeleteTaskInput!):
 | 
				
			||||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
					  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskLocation(input: NewTaskLocation!):
 | 
					  updateTaskLocation(input: NewTaskLocation!):
 | 
				
			||||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskName(input: UpdateTaskName!):
 | 
					  updateTaskName(input: UpdateTaskName!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  setTaskComplete(input: SetTaskComplete!):
 | 
					  setTaskComplete(input: SetTaskComplete!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
					  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  assignTask(input: AssignTaskInput):
 | 
					  assignTask(input: AssignTaskInput):
 | 
				
			||||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
					    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
				
			||||||
@@ -22,7 +22,7 @@ extend type Mutation {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input NewTask {
 | 
					input NewTask {
 | 
				
			||||||
  taskGroupID: UUID!
 | 
					  taskGroupID: String!
 | 
				
			||||||
  name: String!
 | 
					  name: String!
 | 
				
			||||||
  position: Float!
 | 
					  position: Float!
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,19 +11,6 @@ extend type Mutation {
 | 
				
			|||||||
  updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
 | 
					  updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
 | 
				
			||||||
  updateUserRole(input: UpdateUserRole!):
 | 
					  updateUserRole(input: UpdateUserRole!):
 | 
				
			||||||
   UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
					   UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
				
			||||||
  updateUserInfo(input: UpdateUserInfo!):
 | 
					 | 
				
			||||||
    UpdateUserInfoPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateUserInfoPayload {
 | 
					 | 
				
			||||||
  user: UserAccount!
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
input UpdateUserInfo {
 | 
					 | 
				
			||||||
  name: String!
 | 
					 | 
				
			||||||
  initials: String!
 | 
					 | 
				
			||||||
  email: String!
 | 
					 | 
				
			||||||
  bio: String!
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input UpdateUserPassword {
 | 
					input UpdateUserPassword {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/db"
 | 
						"github.com/jordanknott/taskcafe/internal/db"
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/frontend"
 | 
						"github.com/jordanknott/taskcafe/internal/frontend"
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/utils"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Frontend serves the index.html file
 | 
					// Frontend serves the index.html file
 | 
				
			||||||
@@ -31,7 +30,7 @@ func (h *TaskcafeHandler) Frontend(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
// ProfileImageUpload handles a user uploading a new avatar profile image
 | 
					// ProfileImageUpload handles a user uploading a new avatar profile image
 | 
				
			||||||
func (h *TaskcafeHandler) ProfileImageUpload(w http.ResponseWriter, r *http.Request) {
 | 
					func (h *TaskcafeHandler) ProfileImageUpload(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	log.Info("preparing to upload file")
 | 
						log.Info("preparing to upload file")
 | 
				
			||||||
	userID, ok := r.Context().Value(utils.UserIDKey).(uuid.UUID)
 | 
						userID, ok := r.Context().Value("userID").(uuid.UUID)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		log.Error("not a valid uuid")
 | 
							log.Error("not a valid uuid")
 | 
				
			||||||
		w.WriteHeader(http.StatusInternalServerError)
 | 
							w.WriteHeader(http.StatusInternalServerError)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
ALTER TABLE user_account ADD COLUMN bio text NOT NULL DEFAULT '';
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user