feature: add projects & quick card members button

This commit is contained in:
Jordan Knott
2020-05-31 21:20:03 -05:00
parent 67ac88856b
commit 4c02df9061
31 changed files with 1148 additions and 154 deletions

View File

@@ -128,28 +128,3 @@ export const CardMembers = styled.div`
margin: 0 -2px 0 0;
`;
export const CardMember = styled.div<{ bgColor: string; ref: any }>`
height: 28px;
width: 28px;
float: right;
margin: 0 0 4px 4px;
background-color: ${props => props.bgColor};
color: #fff;
border-radius: 25em;
cursor: pointer;
display: block;
overflow: visible;
position: relative;
text-decoration: none;
z-index: 0;
`;
export const CardMemberInitials = styled.div`
height: 28px;
width: 28px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
`;

View File

@@ -2,6 +2,7 @@ import React, { useState, useRef } from 'react';
import { DraggableProvidedDraggableProps } from 'react-beautiful-dnd';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Member from 'shared/components/Member';
import { faPencilAlt, faList } from '@fortawesome/free-solid-svg-icons';
import { faClock, faCheckSquare, faEye } from '@fortawesome/free-regular-svg-icons';
import {
@@ -19,8 +20,6 @@ import {
ListCardOperation,
CardTitle,
CardMembers,
CardMember,
CardMemberInitials,
} from './Styles';
type DueDate = {
@@ -33,31 +32,6 @@ type Checklist = {
total: number;
};
type MemberProps = {
onCardMemberClick?: OnCardMemberClick;
taskID: string;
member: TaskUser;
};
const Member: React.FC<MemberProps> = ({ onCardMemberClick, taskID, member }) => {
const $targetRef = useRef<HTMLDivElement>();
return (
<CardMember
ref={$targetRef}
onClick={e => {
if (onCardMemberClick) {
e.stopPropagation();
onCardMemberClick($targetRef, taskID, member.id);
}
}}
key={member.id}
bgColor={member.profileIcon.bgColor ?? '#7367F0'}
>
<CardMemberInitials>{member.profileIcon.initials}</CardMemberInitials>
</CardMember>
);
};
type Props = {
title: string;
description: string;

View File

@@ -15,7 +15,7 @@ import { Container, BoardWrapper } from './Styles';
interface SimpleProps {
taskGroups: Array<TaskGroup>;
onTaskDrop: (task: Task) => void;
onTaskDrop: (task: Task, previousTaskGroupID: string) => void;
onTaskGroupDrop: (taskGroup: TaskGroup) => void;
onTaskClick: (task: Task) => void;
@@ -110,7 +110,7 @@ const SimpleLists: React.FC<SimpleProps> = ({
id: destination.droppableId,
},
};
onTaskDrop(newTask);
onTaskDrop(newTask, droppedTask.taskGroup.id);
}
}
};

View File

@@ -0,0 +1,55 @@
import React, { useRef } from 'react';
import styled from 'styled-components';
const CardMember = styled.div<{ bgColor: string; ref: any }>`
height: 28px;
width: 28px;
float: right;
margin: 0 0 4px 4px;
background-color: ${props => props.bgColor};
color: #fff;
border-radius: 25em;
cursor: pointer;
display: block;
overflow: visible;
position: relative;
text-decoration: none;
z-index: 0;
`;
const CardMemberInitials = styled.div`
height: 28px;
width: 28px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
`;
type MemberProps = {
onCardMemberClick?: OnCardMemberClick;
taskID: string;
member: TaskUser;
};
const Member: React.FC<MemberProps> = ({ onCardMemberClick, taskID, member }) => {
const $targetRef = useRef<HTMLDivElement>();
return (
<CardMember
ref={$targetRef}
onClick={e => {
if (onCardMemberClick) {
e.stopPropagation();
onCardMemberClick($targetRef, taskID, member.id);
}
}}
key={member.id}
bgColor={member.profileIcon.bgColor ?? '#7367F0'}
>
<CardMemberInitials>{member.profileIcon.initials}</CardMemberInitials>
</CardMember>
);
};
export default Member;

View File

@@ -0,0 +1,32 @@
import React, { useState, useRef, createRef } from 'react';
import { action } from '@storybook/addon-actions';
import styled from 'styled-components';
import NormalizeStyles from 'App/NormalizeStyles';
import BaseStyles from 'App/BaseStyles';
import NewProject from '.';
export default {
component: NewProject,
title: 'NewProject',
parameters: {
backgrounds: [
{ name: 'white', value: '#ffffff', default: true },
{ name: 'gray', value: '#f8f8f8' },
],
},
};
export const Default = () => {
return (
<>
<NormalizeStyles />
<BaseStyles />
<NewProject
onCreateProject={action('create project')}
teams={[{ name: 'General', id: 'general', createdAt: '' }]}
onClose={() => {}}
/>
</>
);
};

View File

@@ -0,0 +1,280 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { mixin } from 'shared/utils/styles';
import Select from 'react-select';
import { ArrowLeft, Cross } from 'shared/icons';
const Overlay = styled.div`
z-index: 10000;
background: #262c49;
bottom: 0;
color: #fff;
left: 0;
position: fixed;
right: 0;
top: 0;
`;
const Content = styled.div`
display: flex;
flex-direction: column;
height: 100%;
`;
const Header = styled.div`
height: 64px;
padding: 0 24px;
align-items: center;
display: flex;
flex: 0 0 auto;
justify-content: space-between;
transition: box-shadow 250ms;
`;
const HeaderLeft = styled.div`
align-items: center;
display: flex;
cursor: pointer;
`;
const HeaderRight = styled.div`
cursor: pointer;
align-items: center;
display: flex;
`;
const Container = styled.div`
padding: 32px 0;
align-items: center;
display: flex;
flex-direction: column;
`;
const ContainerContent = styled.div`
width: 520px;
display: flex;
flex-direction: column;
`;
const Title = styled.h1`
font-size: 24px;
font-weight: 500;
color: #c2c6dc;
margin-bottom: 25px;
`;
const ProjectName = styled.input`
margin: 0 0 12px;
width: 100%;
box-sizing: border-box;
display: block;
line-height: 20px;
margin-bottom: 12px;
padding: 8px 12px;
background: #262c49;
outline: none;
color: #c2c6dc;
border-radius: 3px;
border-width: 1px;
border-style: solid;
border-color: transparent;
border-image: initial;
border-color: #414561;
font-size: 16px;
font-weight: 400;
&:focus {
background: ${mixin.darken('#262c49', 0.15)};
box-shadow: rgb(115, 103, 240) 0px 0px 0px 1px;
}
`;
const ProjectNameLabel = styled.label`
color: #c2c6dc;
font-size: 12px;
margin-bottom: 4px;
`;
const ProjectInfo = styled.div`
display: flex;
`;
const ProjectField = styled.div`
display: flex;
flex-direction: column;
margin-right: 15px;
flex-grow: 1;
`;
const ProjectTeamField = styled.div`
display: flex;
flex-direction: column;
flex-grow: 1;
`;
const colourStyles = {
control: (styles: any, data: any) => {
return {
...styles,
backgroundColor: data.isMenuOpen ? mixin.darken('#262c49', 0.15) : '#262c49',
boxShadow: data.menuIsOpen ? 'rgb(115, 103, 240) 0px 0px 0px 1px' : 'none',
borderRadius: '3px',
borderWidth: '1px',
borderStyle: 'solid',
borderImage: 'initial',
borderColor: '#414561',
':hover': {
boxShadow: 'rgb(115, 103, 240) 0px 0px 0px 1px',
borderRadius: '3px',
borderWidth: '1px',
borderStyle: 'solid',
borderImage: 'initial',
borderColor: '#414561',
},
':active': {
boxShadow: 'rgb(115, 103, 240) 0px 0px 0px 1px',
borderRadius: '3px',
borderWidth: '1px',
borderStyle: 'solid',
borderImage: 'initial',
borderColor: 'rgb(115, 103, 240)',
},
};
},
menu: (styles: any) => {
return {
...styles,
backgroundColor: mixin.darken('#262c49', 0.15),
};
},
dropdownIndicator: (styles: any) => ({ ...styles, color: '#c2c6dc', ':hover': { color: '#c2c6dc' } }),
indicatorSeparator: (styles: any) => ({ ...styles, color: '#c2c6dc' }),
option: (styles: any, { data, isDisabled, isFocused, isSelected }: any) => {
return {
...styles,
backgroundColor: isDisabled
? null
: isSelected
? mixin.darken('#262c49', 0.25)
: isFocused
? mixin.darken('#262c49', 0.15)
: null,
color: isDisabled ? '#ccc' : isSelected ? '#fff' : '#c2c6dc',
cursor: isDisabled ? 'not-allowed' : 'default',
':active': {
...styles[':active'],
backgroundColor: !isDisabled && (isSelected ? mixin.darken('#262c49', 0.25) : '#fff'),
},
':hover': {
...styles[':hover'],
backgroundColor: !isDisabled && (isSelected ? 'rgb(115, 103, 240)' : 'rgb(115, 103, 240)'),
},
};
},
placeholder: (styles: any) => ({ ...styles, color: '#c2c6dc' }),
clearIndicator: (styles: any) => ({ ...styles, color: '#c2c6dc', ':hover': { color: '#c2c6dc' } }),
input: (styles: any) => ({
...styles,
color: '#fff',
}),
singleValue: (styles: any) => {
return {
...styles,
color: '#fff',
};
},
};
const CreateButton = styled.button`
outline: none;
border: none;
width: 100%;
line-height: 20px;
padding: 6px 12px;
background-color: none;
text-align: center;
color: #c2c6dc;
font-size: 14px;
cursor: pointer;
border-radius: 3px;
border-width: 1px;
border-style: solid;
border-color: transparent;
border-image: initial;
border-color: #414561;
&:hover {
color: #fff;
background: rgb(115, 103, 240);
border-color: rgb(115, 103, 240);
}
`;
type NewProjectProps = {
teams: Array<Team>;
onClose: () => void;
onCreateProject: (projectName: string, teamID: string) => void;
};
const NewProject: React.FC<NewProjectProps> = ({ teams, onClose, onCreateProject }) => {
const [projectName, setProjectName] = useState('');
const [team, setTeam] = useState<null | string>(null);
const options = teams.map(t => ({ label: t.name, value: t.id }));
return (
<Overlay>
<Content>
<Header>
<HeaderLeft
onClick={() => {
onClose();
}}
>
<ArrowLeft color="#c2c6dc" />
</HeaderLeft>
<HeaderRight
onClick={() => {
onClose();
}}
>
<Cross color="#c2c6dc" />
</HeaderRight>
</Header>
<Container>
<ContainerContent>
<Title>Add project details</Title>
<ProjectInfo>
<ProjectField>
<ProjectNameLabel>Project name</ProjectNameLabel>
<ProjectName
value={projectName}
onChange={(e: any) => {
setProjectName(e.currentTarget.value);
}}
/>
</ProjectField>
<ProjectTeamField>
<ProjectNameLabel>Team</ProjectNameLabel>
<Select
onChange={(e: any) => {
setTeam(e.value);
}}
value={options.filter(d => d.value === team)}
styles={colourStyles}
classNamePrefix="teamSelect"
options={options}
/>
</ProjectTeamField>
</ProjectInfo>
<CreateButton
onClick={() => {
if (team && projectName !== '') {
onCreateProject(projectName, team);
}
}}
>
Create project
</CreateButton>
</ContainerContent>
</Container>
</Content>
</Overlay>
);
};
export default NewProject;

View File

@@ -1,12 +1,12 @@
import styled, { css } from 'styled-components';
import { mixin } from 'shared/utils/styles';
export const Container = styled.div<{ invert: boolean; top: number; left: number; ref: any }>`
export const Container = styled.div<{ invert: boolean; top: number; left: number; ref: any; width: number | string }>`
left: ${props => props.left}px;
top: ${props => props.top}px;
display: block;
position: absolute;
width: 316px;
width: ${props => props.width}px;
padding-top: 10px;
height: auto;
z-index: 40000;

View File

@@ -15,7 +15,7 @@ import {
} from './Styles';
type PopupContextState = {
show: (target: RefObject<HTMLElement>, content: JSX.Element) => void;
show: (target: RefObject<HTMLElement>, content: JSX.Element, width?: string | number) => void;
setTab: (newTab: number) => void;
getCurrentTab: () => number;
hide: () => void;
@@ -23,7 +23,7 @@ type PopupContextState = {
type PopupProps = {
title: string | null;
onClose: () => void;
onClose?: () => void;
tab: number;
};
@@ -32,17 +32,23 @@ type PopupContainerProps = {
left: number;
invert: boolean;
onClose: () => void;
width?: string | number;
};
const PopupContainer: React.FC<PopupContainerProps> = ({ top, left, onClose, children, invert }) => {
const PopupContainer: React.FC<PopupContainerProps> = ({ width, top, left, onClose, children, invert }) => {
const $containerRef = useRef();
useOnOutsideClick($containerRef, true, onClose, null);
return (
<Container left={left} top={top} ref={$containerRef} invert={invert}>
<Container width={width ?? 316} left={left} top={top} ref={$containerRef} invert={invert}>
{children}
</Container>
);
};
PopupContainer.defaultProps = {
width: 316,
};
const PopupContext = createContext<PopupContextState>({
show: () => {},
setTab: () => {},
@@ -63,6 +69,7 @@ type PopupState = {
currentTab: number;
previousTab: number;
content: JSX.Element | null;
width?: string | number;
};
const { Provider, Consumer } = PopupContext;
@@ -81,7 +88,7 @@ const defaultState = {
export const PopupProvider: React.FC = ({ children }) => {
const [currentState, setState] = useState<PopupState>(defaultState);
const show = (target: RefObject<HTMLElement>, content: JSX.Element) => {
const show = (target: RefObject<HTMLElement>, content: JSX.Element, width?: number | string) => {
if (target && target.current) {
const bounds = target.current.getBoundingClientRect();
if (bounds.left + 304 + 30 > window.innerWidth) {
@@ -93,6 +100,7 @@ export const PopupProvider: React.FC = ({ children }) => {
currentTab: 0,
previousTab: 0,
content,
width: width ?? 316,
});
} else {
setState({
@@ -103,6 +111,7 @@ export const PopupProvider: React.FC = ({ children }) => {
currentTab: 0,
previousTab: 0,
content,
width: width ?? 316,
});
}
}
@@ -144,6 +153,7 @@ export const PopupProvider: React.FC = ({ children }) => {
top={currentState.top}
left={currentState.left}
onClose={() => setState(defaultState)}
width={currentState.width ?? 316}
>
{currentState.content}
<ContainerDiamond invert={currentState.invert} />
@@ -162,14 +172,15 @@ type Props = {
onClose: () => void;
onPrevious?: () => void | null;
noHeader?: boolean | null;
width?: string | number;
};
const PopupMenu: React.FC<Props> = ({ title, top, left, onClose, noHeader, children, onPrevious }) => {
const PopupMenu: React.FC<Props> = ({ width, title, top, left, onClose, noHeader, children, onPrevious }) => {
const $containerRef = useRef();
useOnOutsideClick($containerRef, true, onClose, null);
return (
<Container invert={false} left={left} top={top} ref={$containerRef}>
<Container width={width ?? 316} invert={false} left={left} top={top} ref={$containerRef}>
<Wrapper>
{onPrevious && (
<PreviousButton onClick={onPrevious}>
@@ -217,9 +228,11 @@ export const Popup: React.FC<PopupProps> = ({ title, onClose, tab, children }) =
<HeaderTitle>{title}</HeaderTitle>
</Header>
)}
<CloseButton onClick={() => onClose()}>
<Cross color="#c2c6dc" />
</CloseButton>
{onClose && (
<CloseButton onClick={() => onClose()}>
<Cross color="#c2c6dc" />
</CloseButton>
)}
<Content>{children}</Content>
</Wrapper>
</>

View File

@@ -1,6 +1,12 @@
import styled from 'styled-components';
import { mixin } from 'shared/utils/styles';
export const AddProjectLabel = styled.span`
padding-top: 4px;
font-size: 14px;
color: #c2c6dc;
`;
export const ProjectContent = styled.div`
display: flex;
flex-direction: column;
@@ -20,8 +26,7 @@ export const TeamTitle = styled.span`
export const ProjectWrapper = styled.div<{ color: string }>`
display: flex;
padding: 15px 25px;
border-radius: 20px;
padding: 15px 25px; border-radius: 20px;
${mixin.boxShadowCard}
background: ${props => mixin.darken(props.color, 0.35)};
color: #fff;
@@ -31,8 +36,30 @@ export const ProjectWrapper = styled.div<{ color: string }>`
height: 100px;
transition: transform 0.25s ease;
align-items: center;
justify-content: center;
&:hover {
transform: translateY(-5px);
}
`;
export const AddProjectWrapper = styled.div`
display: flex;
padding: 15px 25px;
border-radius: 20px;
${mixin.boxShadowCard}
border: 1px dashed;
border-color: #c2c6dc;
color: #fff;
cursor: pointer;
margin: 0 10px;
width: 240px;
flex-direction: column;
height: 100px;
transition: transform 0.25s ease;
align-items: center;
justify-content: center;
&:hover {
transform: translateY(-5px);
}
`;

View File

@@ -1,7 +1,23 @@
import React from 'react';
import { ProjectWrapper, ProjectContent, ProjectTitle, TeamTitle } from './Styles';
import { Plus } from 'shared/icons';
import { AddProjectWrapper, AddProjectLabel, ProjectWrapper, ProjectContent, ProjectTitle, TeamTitle } from './Styles';
type AddProjectItemProps = {
onAddProject: () => void;
};
export const AddProjectItem: React.FC<AddProjectItemProps> = ({ onAddProject }) => {
return (
<AddProjectWrapper
onClick={() => {
onAddProject();
}}
>
<Plus size={20} color="#c2c6dc" />
<AddProjectLabel>New Project</AddProjectLabel>
</AddProjectWrapper>
);
};
type Props = {
project: Project;
};

View File

@@ -0,0 +1,51 @@
import React from 'react';
import styled from 'styled-components';
export const ListActionsWrapper = styled.ul`
list-style-type: none;
margin: 0;
padding: 0;
`;
export const ListActionItemWrapper = styled.li`
margin: 0;
padding: 0;
`;
export const ListActionItem = styled.span`
cursor: pointer;
display: block;
font-size: 14px;
color: #c2c6dc;
font-weight: 400;
padding: 6px 12px;
position: relative;
margin: 0 -12px;
text-decoration: none;
&:hover {
background: rgb(115, 103, 240);
}
`;
export const ListSeparator = styled.hr`
background-color: #414561;
border: 0;
height: 1px;
margin: 8px 0;
padding: 0;
width: 100%;
`;
type Props = {};
const ProjectSettings: React.FC<Props> = () => {
return (
<>
<ListActionsWrapper>
<ListActionItemWrapper onClick={() => {}}>
<ListActionItem>Delete Project</ListActionItem>
</ListActionItemWrapper>
</ListActionsWrapper>
</>
);
};
export default ProjectSettings;

View File

@@ -56,6 +56,7 @@ export const Default = () => {
onCloseEditor={() => setEditorOpen(false)}
onEditCard={action('edit card')}
onOpenLabelsPopup={action('open popup')}
onOpenMembersPopup={action('open popup')}
onArchiveCard={action('archive card')}
top={top}
left={left}

View File

@@ -1,5 +1,7 @@
import React, { useRef, useState, useEffect } from 'react';
import Cross from 'shared/icons/Cross';
import styled from 'styled-components';
import Member from 'shared/components/Member';
import {
Wrapper,
Container,
@@ -14,20 +16,39 @@ import {
ListCardLabel,
} from './Styles';
export const CardMembers = styled.div`
position: absolute;
right: 0;
bottom: 0;
`;
type Props = {
task: Task;
onCloseEditor: () => void;
onEditCard: (taskGroupID: string, taskID: string, cardName: string) => void;
onOpenLabelsPopup: ($targetRef: React.RefObject<HTMLElement>, task: Task) => void;
onOpenMembersPopup: ($targetRef: React.RefObject<HTMLElement>, task: Task) => void;
onArchiveCard: (taskGroupID: string, taskID: string) => void;
onCardMemberClick?: OnCardMemberClick;
top: number;
left: number;
};
const QuickCardEditor = ({ task, onCloseEditor, onOpenLabelsPopup, onArchiveCard, onEditCard, top, left }: Props) => {
const QuickCardEditor = ({
task,
onCloseEditor,
onOpenLabelsPopup,
onOpenMembersPopup,
onCardMemberClick,
onArchiveCard,
onEditCard,
top,
left,
}: Props) => {
const [currentCardTitle, setCardTitle] = useState(task.name);
const $editorRef: any = useRef();
const $labelsRef: any = useRef();
const $membersRef: any = useRef();
useEffect(() => {
$editorRef.current.focus();
$editorRef.current.select();
@@ -71,10 +92,25 @@ const QuickCardEditor = ({ task, onCloseEditor, onOpenLabelsPopup, onArchiveCard
value={currentCardTitle}
ref={$editorRef}
/>
<CardMembers>
{task.assigned &&
task.assigned.map(member => (
<Member key={member.id} taskID={task.id} member={member} onCardMemberClick={onCardMemberClick} />
))}
</CardMembers>
</EditorDetails>
</Editor>
<SaveButton onClick={e => onEditCard(task.taskGroup.id, task.id, currentCardTitle)}>Save</SaveButton>
<EditorButtons>
<EditorButton
ref={$membersRef}
onClick={e => {
e.stopPropagation();
onOpenMembersPopup($membersRef, task);
}}
>
Edit Assigned
</EditorButton>
<EditorButton
ref={$labelsRef}
onClick={e => {

View File

@@ -44,6 +44,7 @@ export const Default = () => {
lastName="Knott"
initials="JK"
onNotificationClick={action('notifications click')}
onOpenSettings={action('open settings')}
onProfileClick={onClick}
/>
{menu.isOpen && (

View File

@@ -32,9 +32,14 @@ import MiniProfile from 'shared/components/MiniProfile';
type ProjectHeadingProps = {
projectName: string;
onSaveProjectName?: (projectName: string) => void;
onOpenSettings: ($target: React.RefObject<HTMLElement>) => void;
};
const ProjectHeading: React.FC<ProjectHeadingProps> = ({ projectName: initialProjectName, onSaveProjectName }) => {
const ProjectHeading: React.FC<ProjectHeadingProps> = ({
projectName: initialProjectName,
onSaveProjectName,
onOpenSettings,
}) => {
const [isEditProjectName, setEditProjectName] = useState(false);
const [projectName, setProjectName] = useState(initialProjectName);
const $projectName = useRef<HTMLTextAreaElement>(null);
@@ -66,6 +71,7 @@ const ProjectHeading: React.FC<ProjectHeadingProps> = ({ projectName: initialPro
}
};
const $settings = useRef<HTMLButtonElement>(null);
return (
<>
<Separator>»</Separator>
@@ -87,7 +93,12 @@ const ProjectHeading: React.FC<ProjectHeadingProps> = ({ projectName: initialPro
{projectName}
</ProjectName>
)}
<ProjectSettingsButton>
<ProjectSettingsButton
onClick={() => {
onOpenSettings($settings);
}}
ref={$settings}
>
<AngleDown color="#c2c6dc" />
</ProjectSettingsButton>
<ProjectSettingsButton>
@@ -103,6 +114,7 @@ type NavBarProps = {
onSaveProjectName?: (projectName: string) => void;
onNotificationClick: () => void;
bgColor: string;
onOpenSettings: ($target: React.RefObject<HTMLElement>) => void;
firstName: string;
lastName: string;
initials: string;
@@ -119,6 +131,7 @@ const NavBar: React.FC<NavBarProps> = ({
initials,
bgColor,
projectMembers,
onOpenSettings,
}) => {
const $profileRef: any = useRef(null);
const handleProfileClick = () => {
@@ -147,7 +160,13 @@ const NavBar: React.FC<NavBarProps> = ({
<ProjectActions>
<ProjectMeta>
<ProjectSwitcher>Projects</ProjectSwitcher>
{projectName && <ProjectHeading projectName={projectName} onSaveProjectName={onSaveProjectName} />}
{projectName && (
<ProjectHeading
onOpenSettings={onOpenSettings}
projectName={projectName}
onSaveProjectName={onSaveProjectName}
/>
)}
</ProjectMeta>
{projectName && (
<ProjectTabs>

View File

@@ -136,6 +136,7 @@ export type Query = {
findProject: Project;
findTask: Task;
projects: Array<Project>;
teams: Array<Team>;
labelColors: Array<LabelColor>;
taskGroups: Array<TaskGroup>;
me: UserAccount;
@@ -201,8 +202,8 @@ export type NewTask = {
};
export type NewTaskLocation = {
taskID: Scalars['String'];
taskGroupID: Scalars['String'];
taskID: Scalars['UUID'];
taskGroupID: Scalars['UUID'];
position: Scalars['Float'];
};
@@ -302,6 +303,12 @@ export type UpdateProjectName = {
name: Scalars['String'];
};
export type UpdateTaskLocationPayload = {
__typename?: 'UpdateTaskLocationPayload';
previousTaskGroupID: Scalars['UUID'];
task: Task;
};
export type Mutation = {
__typename?: 'Mutation';
createRefreshToken: RefreshToken;
@@ -322,7 +329,7 @@ export type Mutation = {
toggleTaskLabel: ToggleTaskLabelPayload;
createTask: Task;
updateTaskDescription: Task;
updateTaskLocation: Task;
updateTaskLocation: UpdateTaskLocationPayload;
updateTaskName: Task;
deleteTask: DeleteTaskPayload;
assignTask: Task;
@@ -468,6 +475,25 @@ export type AssignTaskMutation = (
) }
);
export type CreateProjectMutationVariables = {
teamID: Scalars['UUID'];
userID: Scalars['UUID'];
name: Scalars['String'];
};
export type CreateProjectMutation = (
{ __typename?: 'Mutation' }
& { createProject: (
{ __typename?: 'Project' }
& Pick<Project, 'id' | 'name'>
& { team: (
{ __typename?: 'Team' }
& Pick<Team, 'id' | 'name'>
) }
) }
);
export type CreateProjectLabelMutationVariables = {
projectID: Scalars['UUID'];
labelColorID: Scalars['UUID'];
@@ -686,7 +712,10 @@ export type GetProjectsQueryVariables = {};
export type GetProjectsQuery = (
{ __typename?: 'Query' }
& { projects: Array<(
& { teams: Array<(
{ __typename?: 'Team' }
& Pick<Team, 'id' | 'name' | 'createdAt'>
)>, projects: Array<(
{ __typename?: 'Project' }
& Pick<Project, 'id' | 'name'>
& { team: (
@@ -821,8 +850,8 @@ export type UpdateTaskGroupLocationMutation = (
);
export type UpdateTaskLocationMutationVariables = {
taskID: Scalars['String'];
taskGroupID: Scalars['String'];
taskID: Scalars['UUID'];
taskGroupID: Scalars['UUID'];
position: Scalars['Float'];
};
@@ -830,8 +859,16 @@ export type UpdateTaskLocationMutationVariables = {
export type UpdateTaskLocationMutation = (
{ __typename?: 'Mutation' }
& { updateTaskLocation: (
{ __typename?: 'Task' }
& Pick<Task, 'id' | 'createdAt' | 'name' | 'position'>
{ __typename?: 'UpdateTaskLocationPayload' }
& Pick<UpdateTaskLocationPayload, 'previousTaskGroupID'>
& { task: (
{ __typename?: 'Task' }
& Pick<Task, 'id' | 'createdAt' | 'name' | 'position'>
& { taskGroup: (
{ __typename?: 'TaskGroup' }
& Pick<TaskGroup, 'id'>
) }
) }
) }
);
@@ -888,6 +925,45 @@ export function useAssignTaskMutation(baseOptions?: ApolloReactHooks.MutationHoo
export type AssignTaskMutationHookResult = ReturnType<typeof useAssignTaskMutation>;
export type AssignTaskMutationResult = ApolloReactCommon.MutationResult<AssignTaskMutation>;
export type AssignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<AssignTaskMutation, AssignTaskMutationVariables>;
export const CreateProjectDocument = gql`
mutation createProject($teamID: UUID!, $userID: UUID!, $name: String!) {
createProject(input: {teamID: $teamID, userID: $userID, name: $name}) {
id
name
team {
id
name
}
}
}
`;
export type CreateProjectMutationFn = ApolloReactCommon.MutationFunction<CreateProjectMutation, CreateProjectMutationVariables>;
/**
* __useCreateProjectMutation__
*
* To run a mutation, you first call `useCreateProjectMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateProjectMutation` 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 [createProjectMutation, { data, loading, error }] = useCreateProjectMutation({
* variables: {
* teamID: // value for 'teamID'
* userID: // value for 'userID'
* name: // value for 'name'
* },
* });
*/
export function useCreateProjectMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateProjectMutation, CreateProjectMutationVariables>) {
return ApolloReactHooks.useMutation<CreateProjectMutation, CreateProjectMutationVariables>(CreateProjectDocument, baseOptions);
}
export type CreateProjectMutationHookResult = ReturnType<typeof useCreateProjectMutation>;
export type CreateProjectMutationResult = ApolloReactCommon.MutationResult<CreateProjectMutation>;
export type CreateProjectMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateProjectMutation, CreateProjectMutationVariables>;
export const CreateProjectLabelDocument = gql`
mutation createProjectLabel($projectID: UUID!, $labelColorID: UUID!, $name: String!) {
createProjectLabel(input: {projectID: $projectID, labelColorID: $labelColorID, name: $name}) {
@@ -1304,6 +1380,11 @@ export type FindTaskLazyQueryHookResult = ReturnType<typeof useFindTaskLazyQuery
export type FindTaskQueryResult = ApolloReactCommon.QueryResult<FindTaskQuery, FindTaskQueryVariables>;
export const GetProjectsDocument = gql`
query getProjects {
teams {
id
name
createdAt
}
projects {
id
name
@@ -1609,12 +1690,18 @@ export type UpdateTaskGroupLocationMutationHookResult = ReturnType<typeof useUpd
export type UpdateTaskGroupLocationMutationResult = ApolloReactCommon.MutationResult<UpdateTaskGroupLocationMutation>;
export type UpdateTaskGroupLocationMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateTaskGroupLocationMutation, UpdateTaskGroupLocationMutationVariables>;
export const UpdateTaskLocationDocument = gql`
mutation updateTaskLocation($taskID: String!, $taskGroupID: String!, $position: Float!) {
mutation updateTaskLocation($taskID: UUID!, $taskGroupID: UUID!, $position: Float!) {
updateTaskLocation(input: {taskID: $taskID, taskGroupID: $taskGroupID, position: $position}) {
id
createdAt
name
position
previousTaskGroupID
task {
id
createdAt
name
position
taskGroup {
id
}
}
}
}
`;

View File

@@ -0,0 +1,10 @@
mutation createProject($teamID: UUID!, $userID: UUID!, $name: String!) {
createProject(input: {teamID: $teamID, userID: $userID, name: $name}) {
id
name
team {
id
name
}
}
}

View File

@@ -1,4 +1,9 @@
query getProjects {
teams {
id
name
createdAt
}
projects {
id
name

View File

@@ -1,8 +1,14 @@
mutation updateTaskLocation($taskID: String!, $taskGroupID: String!, $position: Float!) {
mutation updateTaskLocation($taskID: UUID!, $taskGroupID: UUID!, $position: Float!) {
updateTaskLocation(input: { taskID: $taskID, taskGroupID: $taskGroupID, position: $position }) {
id
createdAt
name
position
previousTaskGroupID
task {
id
createdAt
name
position
taskGroup {
id
}
}
}
}

View File

@@ -0,0 +1,27 @@
import React from 'react';
type Props = {
width: number | string;
height: number | string;
color: string;
};
const ArrowLeft = ({ width, height, color }: Props) => {
return (
<svg width={width} height={height} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
fill={color}
d="M257.5 445.1l-22.2 22.2c-9.4 9.4-24.6 9.4-33.9 0L7 273c-9.4-9.4-9.4-24.6 0-33.9L201.4 44.7c9.4-9.4 24.6-9.4 33.9 0l22.2 22.2c9.5 9.5 9.3 25-.4 34.3L136.6 216H424c13.3 0 24 10.7 24 24v32c0 13.3-10.7 24-24 24H136.6l120.5 114.8c9.8 9.3 10 24.8.4 34.3z"
/>
</svg>
);
};
ArrowLeft.defaultProps = {
width: 16,
height: 16,
color: '#000',
};
export default ArrowLeft;

View File

@@ -1,5 +1,6 @@
import Cross from './Cross';
import Cog from './Cog';
import ArrowLeft from './ArrowLeft';
import Bolt from './Bolt';
import Plus from './Plus';
import Bell from './Bell';
@@ -43,5 +44,6 @@ export {
User,
Users,
Lock,
ArrowLeft,
ToggleOn,
};