feature: UI changes
This commit is contained in:
@ -41,13 +41,27 @@ const GlobalTopNavbar: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<TopNavbar
|
||||
bgColor={data ? data.me.profileIcon.bgColor ?? '#7367F0' : '#7367F0'}
|
||||
firstName={data ? data.me.firstName : ''}
|
||||
lastName={data ? data.me.lastName : ''}
|
||||
initials={!data ? '' : data.me.profileIcon.initials ?? ''}
|
||||
onNotificationClick={() => console.log('beep')}
|
||||
onProfileClick={onProfileClick}
|
||||
/>
|
||||
{menu.isOpen && <DropdownMenu onLogout={onLogout} left={menu.left} top={menu.top} />}
|
||||
{menu.isOpen && (
|
||||
<DropdownMenu
|
||||
onCloseDropdown={() => {
|
||||
setMenu({
|
||||
top: 0,
|
||||
left: 0,
|
||||
isOpen: false,
|
||||
});
|
||||
}}
|
||||
onLogout={onLogout}
|
||||
left={menu.left}
|
||||
top={menu.top}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import TaskDetails from 'shared/components/TaskDetails';
|
||||
import PopupMenu from 'shared/components/PopupMenu';
|
||||
import MemberManager from 'shared/components/MemberManager';
|
||||
import { useRouteMatch, useHistory } from 'react-router';
|
||||
import { useFindTaskQuery, useAssignTaskMutation } from 'shared/generated/graphql';
|
||||
import { useFindTaskQuery, useAssignTaskMutation, useUnassignTaskMutation } from 'shared/generated/graphql';
|
||||
import UserIDContext from 'App/context';
|
||||
|
||||
type DetailsProps = {
|
||||
@ -15,6 +15,7 @@ type DetailsProps = {
|
||||
onDeleteTask: (task: Task) => void;
|
||||
onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void;
|
||||
availableMembers: Array<TaskUser>;
|
||||
refreshCache: () => void;
|
||||
};
|
||||
|
||||
const initialMemberPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
||||
@ -27,13 +28,25 @@ const Details: React.FC<DetailsProps> = ({
|
||||
onDeleteTask,
|
||||
onOpenAddLabelPopup,
|
||||
availableMembers,
|
||||
refreshCache,
|
||||
}) => {
|
||||
const { userID } = useContext(UserIDContext);
|
||||
const history = useHistory();
|
||||
const match = useRouteMatch();
|
||||
const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState);
|
||||
const { loading, data } = useFindTaskQuery({ variables: { taskID } });
|
||||
const [assignTask] = useAssignTaskMutation();
|
||||
const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
|
||||
const [assignTask] = useAssignTaskMutation({
|
||||
onCompleted: () => {
|
||||
refetch();
|
||||
refreshCache();
|
||||
},
|
||||
});
|
||||
const [unassignTask] = useUnassignTaskMutation({
|
||||
onCompleted: () => {
|
||||
refetch();
|
||||
refreshCache();
|
||||
},
|
||||
});
|
||||
if (loading) {
|
||||
return <div>loading</div>;
|
||||
}
|
||||
@ -47,6 +60,7 @@ const Details: React.FC<DetailsProps> = ({
|
||||
profileIcon: {
|
||||
url: null,
|
||||
initials: assigned.profileIcon.initials ?? null,
|
||||
bgColor: assigned.profileIcon.bgColor ?? null,
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -93,10 +107,13 @@ const Details: React.FC<DetailsProps> = ({
|
||||
>
|
||||
<MemberManager
|
||||
availableMembers={availableMembers}
|
||||
activeMembers={[]}
|
||||
activeMembers={taskMembers}
|
||||
onMemberChange={(member, isActive) => {
|
||||
console.log(`is active ${member.userID} - ${isActive}`);
|
||||
if (isActive) {
|
||||
assignTask({ variables: { taskID: data.findTask.taskID, userID: userID ?? '' } });
|
||||
} else {
|
||||
unassignTask({ variables: { taskID: data.findTask.taskID, userID: userID ?? '' } });
|
||||
}
|
||||
console.log(member, isActive);
|
||||
}}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Board = styled.div`
|
||||
margin-left: 36px;
|
||||
margin-top: 12px;
|
||||
margin-left: 8px;
|
||||
`;
|
||||
|
@ -109,9 +109,10 @@ const Project = () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
const { loading, data } = useFindProjectQuery({
|
||||
const { loading, data, refetch } = useFindProjectQuery({
|
||||
variables: { projectId },
|
||||
onCompleted: newData => {
|
||||
console.log('beep!');
|
||||
const newListsData: BoardState = { tasks: {}, columns: {} };
|
||||
newData.findProject.taskGroups.forEach(taskGroup => {
|
||||
newListsData.columns[taskGroup.taskGroupID] = {
|
||||
@ -121,15 +122,27 @@ const Project = () => {
|
||||
tasks: [],
|
||||
};
|
||||
taskGroup.tasks.forEach(task => {
|
||||
const taskMembers = task.assigned.map(assigned => {
|
||||
return {
|
||||
userID: assigned.userID,
|
||||
displayName: `${assigned.firstName} ${assigned.lastName}`,
|
||||
profileIcon: {
|
||||
url: null,
|
||||
initials: assigned.profileIcon.initials ?? '',
|
||||
bgColor: assigned.profileIcon.bgColor ?? '#7367F0',
|
||||
},
|
||||
};
|
||||
});
|
||||
newListsData.tasks[task.taskID] = {
|
||||
taskID: task.taskID,
|
||||
taskGroup: {
|
||||
taskGroupID: taskGroup.taskGroupID,
|
||||
},
|
||||
name: task.name,
|
||||
position: task.position,
|
||||
labels: [],
|
||||
position: task.position,
|
||||
description: task.description ?? undefined,
|
||||
members: taskMembers,
|
||||
};
|
||||
});
|
||||
});
|
||||
@ -196,15 +209,16 @@ const Project = () => {
|
||||
const availableMembers = data.findProject.members.map(member => {
|
||||
return {
|
||||
displayName: `${member.firstName} ${member.lastName}`,
|
||||
profileIcon: { url: null, initials: member.profileIcon.initials ?? null },
|
||||
profileIcon: {
|
||||
url: null,
|
||||
initials: member.profileIcon.initials ?? null,
|
||||
bgColor: member.profileIcon.bgColor ?? null,
|
||||
},
|
||||
userID: member.userID,
|
||||
};
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<TitleWrapper>
|
||||
<Title>{data.findProject.name}</Title>
|
||||
</TitleWrapper>
|
||||
<KanbanBoard
|
||||
listsData={listsData}
|
||||
onCardDrop={onCardDrop}
|
||||
@ -253,6 +267,10 @@ const Project = () => {
|
||||
path={`${match.path}/c/:taskID`}
|
||||
render={(routeProps: RouteComponentProps<TaskRouteProps>) => (
|
||||
<Details
|
||||
refreshCache={() => {
|
||||
console.log('beep 2!');
|
||||
refetch();
|
||||
}}
|
||||
availableMembers={availableMembers}
|
||||
projectURL={match.url}
|
||||
taskID={routeProps.match.params.taskID}
|
||||
|
1
web/src/citadel.d.ts
vendored
1
web/src/citadel.d.ts
vendored
@ -37,6 +37,7 @@ type InnerTaskGroup = {
|
||||
type ProfileIcon = {
|
||||
url: string | null;
|
||||
initials: string | null;
|
||||
bgColor: string | null;
|
||||
};
|
||||
|
||||
type TaskUser = {
|
||||
|
@ -98,9 +98,6 @@ export const ListCardOperation = styled.span`
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
background-color: ${props => mixin.darken('#262c49', 0.15)};
|
||||
background-clip: padding-box;
|
||||
background-origin: padding-box;
|
||||
border-radius: 3px;
|
||||
opacity: 0.8;
|
||||
padding: 6px;
|
||||
@ -108,6 +105,10 @@ export const ListCardOperation = styled.span`
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
z-index: 10;
|
||||
|
||||
&:hover {
|
||||
background-color: ${props => mixin.darken('#262c49', 0.45)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const CardTitle = styled.span`
|
||||
@ -120,3 +121,34 @@ export const CardTitle = styled.span`
|
||||
word-wrap: break-word;
|
||||
color: #c2c6dc;
|
||||
`;
|
||||
|
||||
export const CardMembers = styled.div`
|
||||
float: right;
|
||||
margin: 0 -2px 0 0;
|
||||
`;
|
||||
|
||||
export const CardMember = styled.div<{ bgColor: string }>`
|
||||
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;
|
||||
`;
|
||||
|
@ -18,6 +18,9 @@ import {
|
||||
ListCardLabel,
|
||||
ListCardOperation,
|
||||
CardTitle,
|
||||
CardMembers,
|
||||
CardMember,
|
||||
CardMemberInitials,
|
||||
} from './Styles';
|
||||
|
||||
type DueDate = {
|
||||
@ -42,6 +45,7 @@ type Props = {
|
||||
watched?: boolean;
|
||||
labels?: Label[];
|
||||
wrapperProps?: any;
|
||||
members?: Array<TaskUser> | null;
|
||||
};
|
||||
|
||||
const Card = React.forwardRef(
|
||||
@ -58,6 +62,7 @@ const Card = React.forwardRef(
|
||||
description,
|
||||
checklists,
|
||||
watched,
|
||||
members,
|
||||
}: Props,
|
||||
$cardRef: any,
|
||||
) => {
|
||||
@ -95,9 +100,11 @@ const Card = React.forwardRef(
|
||||
{...wrapperProps}
|
||||
>
|
||||
<ListCardInnerContainer ref={$innerCardRef}>
|
||||
<ListCardOperation>
|
||||
<FontAwesomeIcon onClick={onOperationClick} color="#c2c6dc" size="xs" icon={faPencilAlt} />
|
||||
</ListCardOperation>
|
||||
{isActive && (
|
||||
<ListCardOperation>
|
||||
<FontAwesomeIcon onClick={onOperationClick} color="#c2c6dc" size="xs" icon={faPencilAlt} />
|
||||
</ListCardOperation>
|
||||
)}
|
||||
<ListCardDetails>
|
||||
<ListCardLabels>
|
||||
{labels &&
|
||||
@ -132,6 +139,14 @@ const Card = React.forwardRef(
|
||||
</ListCardBadge>
|
||||
)}
|
||||
</ListCardBadges>
|
||||
<CardMembers>
|
||||
{members &&
|
||||
members.map(member => (
|
||||
<CardMember key={member.userID} bgColor={member.profileIcon.bgColor ?? '#7367F0'}>
|
||||
<CardMemberInitials>{member.profileIcon.initials}</CardMemberInitials>
|
||||
</CardMember>
|
||||
))}
|
||||
</CardMembers>
|
||||
</ListCardDetails>
|
||||
</ListCardInnerContainer>
|
||||
</ListCardContainer>
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React, { createRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import DropdownMenu from '.';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import DropdownMenu from '.';
|
||||
|
||||
export default {
|
||||
component: DropdownMenu,
|
||||
@ -50,7 +49,16 @@ export const Default = () => {
|
||||
Click me
|
||||
</Button>
|
||||
</Container>
|
||||
{menu.isOpen && <DropdownMenu onLogout={action('on logout')} left={menu.left} top={menu.top} />}
|
||||
{menu.isOpen && (
|
||||
<DropdownMenu
|
||||
onCloseDropdown={() => {
|
||||
setMenu({ top: 0, left: 0, isOpen: false });
|
||||
}}
|
||||
onLogout={action('on logout')}
|
||||
left={menu.left}
|
||||
top={menu.top}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||
import { Exit, User } from 'shared/icons';
|
||||
import { Separator, Container, WrapperDiamond, Wrapper, ActionsList, ActionItem, ActionTitle } from './Styles';
|
||||
|
||||
@ -7,11 +7,14 @@ type DropdownMenuProps = {
|
||||
left: number;
|
||||
top: number;
|
||||
onLogout: () => void;
|
||||
onCloseDropdown: () => void;
|
||||
};
|
||||
|
||||
const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top, onLogout }) => {
|
||||
const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top, onLogout, onCloseDropdown }) => {
|
||||
const $containerRef = useRef<HTMLDivElement>(null);
|
||||
useOnOutsideClick($containerRef, true, onCloseDropdown, null);
|
||||
return (
|
||||
<Container left={left} top={top}>
|
||||
<Container ref={$containerRef} left={left} top={top}>
|
||||
<Wrapper>
|
||||
<ActionItem>
|
||||
<User size={16} color="#c2c6dc" />
|
||||
|
@ -23,7 +23,9 @@ export const Default = () => {
|
||||
position: 1,
|
||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
||||
description: 'hello!',
|
||||
members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }],
|
||||
members: [
|
||||
{ userID: '1', profileIcon: { url: null, initials: null, bgColor: null }, displayName: 'Jordan Knott' },
|
||||
],
|
||||
}}
|
||||
onCancel={action('cancel')}
|
||||
onDueDateChange={action('due date change')}
|
||||
|
@ -159,6 +159,7 @@ const Lists: React.FC<Props> = ({
|
||||
description=""
|
||||
title={task.name}
|
||||
labels={task.labels}
|
||||
members={task.members}
|
||||
onClick={() => onCardClick(task)}
|
||||
onContextMenu={onQuickEditorOpen}
|
||||
/>
|
||||
|
50
web/src/shared/components/MiniProfile/Styles.ts
Normal file
50
web/src/shared/components/MiniProfile/Styles.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Profile = styled.div`
|
||||
margin: 8px 0;
|
||||
min-height: 56px;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
export const ProfileIcon = styled.div<{ bgColor: string }>`
|
||||
float: left;
|
||||
margin: 2px;
|
||||
background-color: ${props => props.bgColor};
|
||||
border-radius: 25em;
|
||||
display: block;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 50px;
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
export const ProfileInfo = styled.div`
|
||||
margin: 0 0 0 64px;
|
||||
word-wrap: break-word;
|
||||
`;
|
||||
|
||||
export const InfoTitle = styled.h3`
|
||||
margin: 0 40px 0 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: #172b4d;
|
||||
`;
|
||||
|
||||
export const InfoUsername = styled.p`
|
||||
color: #5e6c84;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
`;
|
||||
|
||||
export const InfoBio = styled.p`
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #5e6c84;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
26
web/src/shared/components/MiniProfile/index.tsx
Normal file
26
web/src/shared/components/MiniProfile/index.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Profile, ProfileIcon, ProfileInfo, InfoTitle, InfoUsername, InfoBio } from './Styles';
|
||||
|
||||
type MiniProfileProps = {
|
||||
displayName: string;
|
||||
username: string;
|
||||
bio: string;
|
||||
profileIcon: ProfileIcon;
|
||||
};
|
||||
const MiniProfile: React.FC<MiniProfileProps> = ({ displayName, username, bio, profileIcon }) => {
|
||||
return (
|
||||
<>
|
||||
<Profile>
|
||||
<ProfileIcon bgColor={profileIcon.bgColor ?? ''}>{profileIcon.initials}</ProfileIcon>
|
||||
<ProfileInfo>
|
||||
<InfoTitle>{displayName}</InfoTitle>
|
||||
<InfoUsername>{username}</InfoUsername>
|
||||
<InfoBio>{bio}</InfoBio>
|
||||
</ProfileInfo>
|
||||
</Profile>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MiniProfile;
|
@ -17,13 +17,12 @@ export const ClickableOverlay = styled.div`
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 50px;
|
||||
`;
|
||||
|
||||
export const StyledModal = styled.div<{ width: number }>`
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 48px 0 80px;
|
||||
width: 100%;
|
||||
background: #262c49;
|
||||
max-width: ${props => props.width}px;
|
||||
|
@ -1,32 +1,14 @@
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
export const LogoWrapper = styled.div`
|
||||
margin: 20px 0px 20px;
|
||||
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
padding-left: 64px;
|
||||
color: rgb(222, 235, 255);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: color 0.1s ease 0s;
|
||||
`;
|
||||
|
||||
export const Logo = styled.div`
|
||||
position: absolute;
|
||||
left: 19px;
|
||||
`;
|
||||
export const Logo = styled.div``;
|
||||
|
||||
export const LogoTitle = styled.div`
|
||||
position: relative;
|
||||
right: 12px;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
transition: right 0.1s ease 0s, visibility, opacity, transform 0.25s ease;
|
||||
transition: visibility, opacity, transform 0.25s ease;
|
||||
color: #7367f0;
|
||||
`;
|
||||
export const ActionContainer = styled.div`
|
||||
@ -54,6 +36,10 @@ export const IconWrapper = styled.div`
|
||||
export const ActionButtonContainer = styled.div`
|
||||
padding: 0 12px;
|
||||
position: relative;
|
||||
|
||||
& > a:first-child > div {
|
||||
padding-top: 48px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ActionButtonWrapper = styled.div<{ active?: boolean }>`
|
||||
@ -65,7 +51,7 @@ export const ActionButtonWrapper = styled.div<{ active?: boolean }>`
|
||||
`}
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
padding: 10px 15px;
|
||||
padding: 24px 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:hover ${ActionButtonTitle} {
|
||||
@ -76,6 +62,20 @@ export const ActionButtonWrapper = styled.div<{ active?: boolean }>`
|
||||
}
|
||||
`;
|
||||
|
||||
export const LogoWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
color: rgb(222, 235, 255);
|
||||
cursor: pointer;
|
||||
transition: color 0.1s ease 0s, border 0.1s ease 0s;
|
||||
border-bottom: 1px solid rgba(65, 69, 97, 0.65);
|
||||
`;
|
||||
|
||||
export const Container = styled.aside`
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
@ -87,13 +87,15 @@ export const Container = styled.aside`
|
||||
transform: translateZ(0px);
|
||||
background: #10163a;
|
||||
transition: all 0.1s ease 0s;
|
||||
border-right: 1px solid rgba(65, 69, 97, 0.65);
|
||||
|
||||
&:hover {
|
||||
width: 260px;
|
||||
box-shadow: rgba(0, 0, 0, 0.6) 0px 0px 50px 0px;
|
||||
border-right: 1px solid rgba(65, 69, 97, 0);
|
||||
}
|
||||
&:hover ${LogoTitle} {
|
||||
right: 0px;
|
||||
bottom: -12px;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
@ -102,4 +104,8 @@ export const Container = styled.aside`
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:hover ${LogoWrapper} {
|
||||
border-bottom: 1px solid rgba(65, 69, 97, 0);
|
||||
}
|
||||
`;
|
||||
|
@ -35,9 +35,7 @@ export const ButtonContainer: React.FC = ({ children }) => (
|
||||
export const PrimaryLogo = () => {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<Logo>
|
||||
<Citadel size={42} />
|
||||
</Logo>
|
||||
<Citadel size={42} />
|
||||
<LogoTitle>Citadel</LogoTitle>
|
||||
</LogoWrapper>
|
||||
);
|
||||
|
@ -6,6 +6,7 @@ import LabelEditor from 'shared/components/PopupMenu/LabelEditor';
|
||||
import ListActions from 'shared/components/ListActions';
|
||||
import MemberManager from 'shared/components/MemberManager';
|
||||
import DueDateManager from 'shared/components/DueDateManager';
|
||||
import MiniProfile from 'shared/components/MiniProfile';
|
||||
|
||||
import PopupMenu from '.';
|
||||
import NormalizeStyles from 'App/NormalizeStyles';
|
||||
@ -115,7 +116,7 @@ export const MemberManagerPopup = () => {
|
||||
<PopupMenu title="Members" top={popupData.top} onClose={() => setPopupData(initalState)} left={popupData.left}>
|
||||
<MemberManager
|
||||
availableMembers={[
|
||||
{ userID: '1', displayName: 'Jordan Knott', profileIcon: { url: null, initials: null } },
|
||||
{ userID: '1', displayName: 'Jordan Knott', profileIcon: { bgColor: null, url: null, initials: null } },
|
||||
]}
|
||||
activeMembers={[]}
|
||||
onMemberChange={action('member change')}
|
||||
@ -158,7 +159,9 @@ export const DueDateManagerPopup = () => {
|
||||
position: 1,
|
||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
||||
description: 'hello!',
|
||||
members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }],
|
||||
members: [
|
||||
{ userID: '1', profileIcon: { bgColor: null, url: null, initials: null }, displayName: 'Jordan Knott' },
|
||||
],
|
||||
}}
|
||||
onCancel={action('cancel')}
|
||||
onDueDateChange={action('due date change')}
|
||||
@ -189,3 +192,47 @@ export const DueDateManagerPopup = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const MiniProfilePopup = () => {
|
||||
const $buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [popupData, setPopupData] = useState(initalState);
|
||||
return (
|
||||
<>
|
||||
<NormalizeStyles />
|
||||
<BaseStyles />
|
||||
{popupData.isOpen && (
|
||||
<PopupMenu title="Due Date" top={popupData.top} onClose={() => setPopupData(initalState)} left={popupData.left}>
|
||||
<MiniProfile
|
||||
displayName="Jordan Knott"
|
||||
profileIcon={{ url: null, bgColor: '#000', initials: 'JK' }}
|
||||
username="@jordanthedev"
|
||||
bio="Stuff and things"
|
||||
/>
|
||||
</PopupMenu>
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
width: '60px',
|
||||
textAlign: 'center',
|
||||
margin: '25px auto',
|
||||
cursor: 'pointer',
|
||||
color: '#fff',
|
||||
background: '#f00',
|
||||
}}
|
||||
ref={$buttonRef}
|
||||
onClick={() => {
|
||||
if ($buttonRef && $buttonRef.current) {
|
||||
const pos = $buttonRef.current.getBoundingClientRect();
|
||||
setPopupData({
|
||||
isOpen: true,
|
||||
left: pos.left,
|
||||
top: pos.top + pos.height + 10,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Open
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -281,3 +281,9 @@ export const NoDueDateLabel = styled.span`
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
export const UnassignedLabel = styled.div`
|
||||
color: rgb(137, 147, 164);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
@ -35,7 +35,13 @@ export const Default = () => {
|
||||
position: 1,
|
||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
||||
description,
|
||||
members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }],
|
||||
members: [
|
||||
{
|
||||
userID: '1',
|
||||
profileIcon: { bgColor: null, url: null, initials: null },
|
||||
displayName: 'Jordan Knott',
|
||||
},
|
||||
],
|
||||
}}
|
||||
onTaskNameChange={action('task name change')}
|
||||
onTaskDescriptionChange={(_task, desc) => setDescription(desc)}
|
||||
|
@ -4,6 +4,7 @@ import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||
|
||||
import {
|
||||
NoDueDateLabel,
|
||||
UnassignedLabel,
|
||||
TaskDetailsAddMember,
|
||||
TaskGroupLabel,
|
||||
TaskGroupLabelName,
|
||||
@ -126,11 +127,16 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
onTaskNameChange(task, taskName);
|
||||
}
|
||||
};
|
||||
const $unassignedRef = useRef<HTMLDivElement>(null);
|
||||
const $addMemberRef = useRef<HTMLDivElement>(null);
|
||||
const onUnassignedClick = () => {
|
||||
const bounds = convertDivElementRefToBounds($unassignedRef);
|
||||
if (bounds) {
|
||||
onOpenAddMemberPopup(task, bounds);
|
||||
}
|
||||
};
|
||||
const onAddMember = () => {
|
||||
console.log('beep!');
|
||||
const bounds = convertDivElementRefToBounds($addMemberRef);
|
||||
console.log(bounds);
|
||||
if (bounds) {
|
||||
onOpenAddMemberPopup(task, bounds);
|
||||
}
|
||||
@ -191,20 +197,28 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
<TaskDetailsSidebar>
|
||||
<TaskDetailSectionTitle>Assignees</TaskDetailSectionTitle>
|
||||
<TaskDetailAssignees>
|
||||
{task.members &&
|
||||
task.members.map(member => {
|
||||
console.log(member);
|
||||
return (
|
||||
<TaskDetailAssignee key={member.userID}>
|
||||
<ProfileIcon>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
||||
</TaskDetailAssignee>
|
||||
);
|
||||
})}
|
||||
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
||||
<TaskDetailsAddMemberIcon>
|
||||
<Plus size={16} color="#c2c6dc" />
|
||||
</TaskDetailsAddMemberIcon>
|
||||
</TaskDetailsAddMember>
|
||||
{task.members && task.members.length === 0 ? (
|
||||
<UnassignedLabel ref={$unassignedRef} onClick={onUnassignedClick}>
|
||||
Unassigned
|
||||
</UnassignedLabel>
|
||||
) : (
|
||||
<>
|
||||
{task.members &&
|
||||
task.members.map(member => {
|
||||
console.log(member);
|
||||
return (
|
||||
<TaskDetailAssignee key={member.userID}>
|
||||
<ProfileIcon>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
||||
</TaskDetailAssignee>
|
||||
);
|
||||
})}
|
||||
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
||||
<TaskDetailsAddMemberIcon>
|
||||
<Plus size={16} color="#c2c6dc" />
|
||||
</TaskDetailsAddMemberIcon>
|
||||
</TaskDetailsAddMember>
|
||||
</>
|
||||
)}
|
||||
</TaskDetailAssignees>
|
||||
<TaskDetailSectionTitle>Labels</TaskDetailSectionTitle>
|
||||
<TaskDetailLabels>
|
||||
|
@ -1,19 +1,18 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const NavbarWrapper = styled.div`
|
||||
height: 103px;
|
||||
padding: 1.3rem 2.2rem 2.2rem;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const NavbarHeader = styled.header`
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.8rem 1rem;
|
||||
height: 80px;
|
||||
padding: 0 1.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgb(16, 22, 58);
|
||||
box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.05);
|
||||
border-bottom: 1px solid rgba(65, 69, 97, 0.65);
|
||||
`;
|
||||
export const Breadcrumbs = styled.div`
|
||||
color: rgb(94, 108, 132);
|
||||
@ -26,7 +25,14 @@ export const BreadcrumpSeparator = styled.span`
|
||||
margin: 0px 10px;
|
||||
`;
|
||||
|
||||
export const ProjectActions = styled.div``;
|
||||
export const ProjectActions = styled.div`
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-width: 1px;
|
||||
`;
|
||||
|
||||
export const GlobalActions = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -55,7 +61,7 @@ export const ProfileNameSecondary = styled.small`
|
||||
color: #c2c6dc;
|
||||
`;
|
||||
|
||||
export const ProfileIcon = styled.div`
|
||||
export const ProfileIcon = styled.div<{ bgColor: string }>`
|
||||
margin-left: 10px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@ -65,6 +71,48 @@ export const ProfileIcon = styled.div`
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
background: rgb(115, 103, 240);
|
||||
background: ${props => props.bgColor};
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
export const ProjectMeta = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
max-width: 100%;
|
||||
min-height: 51px;
|
||||
`;
|
||||
|
||||
export const ProjectTabs = styled.div`
|
||||
align-items: flex-end;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
justify-content: flex-start;
|
||||
max-width: 100%;
|
||||
`;
|
||||
|
||||
export const ProjectTab = styled.span`
|
||||
font-size: 80%;
|
||||
color: #c2c6dc;
|
||||
font-size: 15px;
|
||||
cursor: default;
|
||||
display: flex;
|
||||
line-height: normal;
|
||||
min-width: 1px;
|
||||
transition-duration: 0.2s;
|
||||
transition-property: box-shadow, color;
|
||||
white-space: nowrap;
|
||||
flex: 0 1 auto;
|
||||
|
||||
padding-bottom: 12px;
|
||||
|
||||
box-shadow: inset 0 -2px #d85dd8;
|
||||
color: #d85dd8;
|
||||
`;
|
||||
|
||||
export const ProjectName = styled.h1`
|
||||
color: #c2c6dc;
|
||||
margin-top: 9px;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
`;
|
||||
|
@ -38,13 +38,23 @@ export const Default = () => {
|
||||
<NormalizeStyles />
|
||||
<BaseStyles />
|
||||
<TopNavbar
|
||||
bgColor="#7367F0"
|
||||
firstName="Jordan"
|
||||
lastName="Knott"
|
||||
initials="JK"
|
||||
onNotificationClick={action('notifications click')}
|
||||
onProfileClick={onClick}
|
||||
/>
|
||||
{menu.isOpen && <DropdownMenu onLogout={action('on logout')} left={menu.left} top={menu.top} />}
|
||||
{menu.isOpen && (
|
||||
<DropdownMenu
|
||||
onCloseDropdown={() => {
|
||||
setMenu({ left: 0, top: 0, isOpen: false });
|
||||
}}
|
||||
onLogout={action('on logout')}
|
||||
left={menu.left}
|
||||
top={menu.top}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -5,6 +5,10 @@ import {
|
||||
NotificationContainer,
|
||||
GlobalActions,
|
||||
ProjectActions,
|
||||
ProjectMeta,
|
||||
ProjectName,
|
||||
ProjectTabs,
|
||||
ProjectTab,
|
||||
NavbarWrapper,
|
||||
NavbarHeader,
|
||||
Breadcrumbs,
|
||||
@ -19,11 +23,19 @@ import {
|
||||
type NavBarProps = {
|
||||
onProfileClick: (bottom: number, right: number) => void;
|
||||
onNotificationClick: () => void;
|
||||
bgColor: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
initials: string;
|
||||
};
|
||||
const NavBar: React.FC<NavBarProps> = ({ onProfileClick, onNotificationClick, firstName, lastName, initials }) => {
|
||||
const NavBar: React.FC<NavBarProps> = ({
|
||||
onProfileClick,
|
||||
onNotificationClick,
|
||||
firstName,
|
||||
lastName,
|
||||
initials,
|
||||
bgColor,
|
||||
}) => {
|
||||
const $profileRef: any = useRef(null);
|
||||
const handleProfileClick = () => {
|
||||
console.log('click');
|
||||
@ -34,13 +46,12 @@ const NavBar: React.FC<NavBarProps> = ({ onProfileClick, onNotificationClick, fi
|
||||
<NavbarWrapper>
|
||||
<NavbarHeader>
|
||||
<ProjectActions>
|
||||
<Breadcrumbs>
|
||||
Projects
|
||||
<BreadcrumpSeparator>/</BreadcrumpSeparator>
|
||||
project name
|
||||
<BreadcrumpSeparator>/</BreadcrumpSeparator>
|
||||
Board
|
||||
</Breadcrumbs>
|
||||
<ProjectMeta>
|
||||
<ProjectName>Production Team</ProjectName>
|
||||
</ProjectMeta>
|
||||
<ProjectTabs>
|
||||
<ProjectTab>Board</ProjectTab>
|
||||
</ProjectTabs>
|
||||
</ProjectActions>
|
||||
<GlobalActions>
|
||||
<NotificationContainer onClick={onNotificationClick}>
|
||||
@ -53,7 +64,7 @@ const NavBar: React.FC<NavBarProps> = ({ onProfileClick, onNotificationClick, fi
|
||||
</ProfileNamePrimary>
|
||||
<ProfileNameSecondary>Manager</ProfileNameSecondary>
|
||||
</ProfileNameWrapper>
|
||||
<ProfileIcon ref={$profileRef} onClick={handleProfileClick}>
|
||||
<ProfileIcon ref={$profileRef} onClick={handleProfileClick} bgColor={bgColor}>
|
||||
{initials}
|
||||
</ProfileIcon>
|
||||
</ProfileContainer>
|
||||
|
@ -15,17 +15,28 @@ export type Scalars = {
|
||||
|
||||
|
||||
|
||||
export type ProjectLabel = {
|
||||
__typename?: 'ProjectLabel';
|
||||
projectLabelID: Scalars['ID'];
|
||||
createdDate: Scalars['Time'];
|
||||
colorHex: Scalars['String'];
|
||||
name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type TaskLabel = {
|
||||
__typename?: 'TaskLabel';
|
||||
taskLabelID: Scalars['ID'];
|
||||
labelColorID: Scalars['UUID'];
|
||||
projectLabelID: Scalars['UUID'];
|
||||
assignedDate: Scalars['Time'];
|
||||
colorHex: Scalars['String'];
|
||||
name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ProfileIcon = {
|
||||
__typename?: 'ProfileIcon';
|
||||
url?: Maybe<Scalars['String']>;
|
||||
initials?: Maybe<Scalars['String']>;
|
||||
bgColor?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ProjectMember = {
|
||||
@ -71,6 +82,7 @@ export type Project = {
|
||||
owner: ProjectMember;
|
||||
taskGroups: Array<TaskGroup>;
|
||||
members: Array<ProjectMember>;
|
||||
labels: Array<ProjectLabel>;
|
||||
};
|
||||
|
||||
export type TaskGroup = {
|
||||
@ -222,6 +234,11 @@ export type AssignTaskInput = {
|
||||
userID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type UnassignTaskInput = {
|
||||
taskID: Scalars['UUID'];
|
||||
userID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type UpdateTaskDescriptionInput = {
|
||||
taskID: Scalars['UUID'];
|
||||
description: Scalars['String'];
|
||||
@ -237,12 +254,19 @@ export type RemoveTaskLabelInput = {
|
||||
taskLabelID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type NewProjectLabel = {
|
||||
projectID: Scalars['UUID'];
|
||||
labelColorID: Scalars['UUID'];
|
||||
name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
createRefreshToken: RefreshToken;
|
||||
createUserAccount: UserAccount;
|
||||
createTeam: Team;
|
||||
createProject: Project;
|
||||
createProjectLabel: ProjectLabel;
|
||||
createTaskGroup: TaskGroup;
|
||||
updateTaskGroupLocation: TaskGroup;
|
||||
deleteTaskGroup: DeleteTaskGroupPayload;
|
||||
@ -254,6 +278,7 @@ export type Mutation = {
|
||||
updateTaskName: Task;
|
||||
deleteTask: DeleteTaskPayload;
|
||||
assignTask: Task;
|
||||
unassignTask: Task;
|
||||
logoutUser: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
@ -278,6 +303,11 @@ export type MutationCreateProjectArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateProjectLabelArgs = {
|
||||
input: NewProjectLabel;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateTaskGroupArgs = {
|
||||
input: NewTaskGroup;
|
||||
};
|
||||
@ -333,6 +363,11 @@ export type MutationAssignTaskArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUnassignTaskArgs = {
|
||||
input?: Maybe<UnassignTaskInput>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationLogoutUserArgs = {
|
||||
input: LogoutUser;
|
||||
};
|
||||
@ -438,7 +473,7 @@ export type FindProjectQuery = (
|
||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'url' | 'initials'>
|
||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||
) }
|
||||
)>, taskGroups: Array<(
|
||||
{ __typename?: 'TaskGroup' }
|
||||
@ -446,6 +481,14 @@ export type FindProjectQuery = (
|
||||
& { tasks: Array<(
|
||||
{ __typename?: 'Task' }
|
||||
& Pick<Task, 'taskID' | 'name' | 'position' | 'description'>
|
||||
& { assigned: Array<(
|
||||
{ __typename?: 'ProjectMember' }
|
||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||
) }
|
||||
)> }
|
||||
)> }
|
||||
)> }
|
||||
) }
|
||||
@ -469,7 +512,7 @@ export type FindTaskQuery = (
|
||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'url' | 'initials'>
|
||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||
) }
|
||||
)> }
|
||||
) }
|
||||
@ -500,11 +543,29 @@ export type MeQuery = (
|
||||
& Pick<UserAccount, 'firstName' | 'lastName'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'initials'>
|
||||
& Pick<ProfileIcon, 'initials' | 'bgColor'>
|
||||
) }
|
||||
) }
|
||||
);
|
||||
|
||||
export type UnassignTaskMutationVariables = {
|
||||
taskID: Scalars['UUID'];
|
||||
userID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type UnassignTaskMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { unassignTask: (
|
||||
{ __typename?: 'Task' }
|
||||
& Pick<Task, 'taskID'>
|
||||
& { assigned: Array<(
|
||||
{ __typename?: 'ProjectMember' }
|
||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||
)> }
|
||||
) }
|
||||
);
|
||||
|
||||
export type UpdateTaskDescriptionMutationVariables = {
|
||||
taskID: Scalars['UUID'];
|
||||
description: Scalars['String'];
|
||||
@ -759,6 +820,7 @@ export const FindProjectDocument = gql`
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
taskGroups {
|
||||
@ -770,6 +832,16 @@ export const FindProjectDocument = gql`
|
||||
name
|
||||
position
|
||||
description
|
||||
assigned {
|
||||
userID
|
||||
firstName
|
||||
lastName
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -818,6 +890,7 @@ export const FindTaskDocument = gql`
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -893,6 +966,7 @@ export const MeDocument = gql`
|
||||
lastName
|
||||
profileIcon {
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -922,6 +996,44 @@ export function useMeLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptio
|
||||
export type MeQueryHookResult = ReturnType<typeof useMeQuery>;
|
||||
export type MeLazyQueryHookResult = ReturnType<typeof useMeLazyQuery>;
|
||||
export type MeQueryResult = ApolloReactCommon.QueryResult<MeQuery, MeQueryVariables>;
|
||||
export const UnassignTaskDocument = gql`
|
||||
mutation unassignTask($taskID: UUID!, $userID: UUID!) {
|
||||
unassignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||
assigned {
|
||||
userID
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
taskID
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type UnassignTaskMutationFn = ApolloReactCommon.MutationFunction<UnassignTaskMutation, UnassignTaskMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUnassignTaskMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useUnassignTaskMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUnassignTaskMutation` 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 [unassignTaskMutation, { data, loading, error }] = useUnassignTaskMutation({
|
||||
* variables: {
|
||||
* taskID: // value for 'taskID'
|
||||
* userID: // value for 'userID'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUnassignTaskMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<UnassignTaskMutation, UnassignTaskMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<UnassignTaskMutation, UnassignTaskMutationVariables>(UnassignTaskDocument, baseOptions);
|
||||
}
|
||||
export type UnassignTaskMutationHookResult = ReturnType<typeof useUnassignTaskMutation>;
|
||||
export type UnassignTaskMutationResult = ApolloReactCommon.MutationResult<UnassignTaskMutation>;
|
||||
export type UnassignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<UnassignTaskMutation, UnassignTaskMutationVariables>;
|
||||
export const UpdateTaskDescriptionDocument = gql`
|
||||
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
||||
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
||||
|
@ -8,6 +8,7 @@ query findProject($projectId: String!) {
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
taskGroups {
|
||||
@ -19,6 +20,16 @@ query findProject($projectId: String!) {
|
||||
name
|
||||
position
|
||||
description
|
||||
assigned {
|
||||
userID
|
||||
firstName
|
||||
lastName
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ query findTask($taskID: UUID!) {
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ query me {
|
||||
lastName
|
||||
profileIcon {
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
web/src/shared/graphql/unassignTask.graphqls
Normal file
10
web/src/shared/graphql/unassignTask.graphqls
Normal file
@ -0,0 +1,10 @@
|
||||
mutation unassignTask($taskID: UUID!, $userID: UUID!) {
|
||||
unassignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||
assigned {
|
||||
userID
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
taskID
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user