2020-05-31 06:11:19 +02:00
|
|
|
import React, { useRef, useState, useEffect } from 'react';
|
2020-10-21 01:52:09 +02:00
|
|
|
import { Home, Star, Bell, AngleDown, BarChart, CheckCircle, ListUnordered } from 'shared/icons';
|
2020-06-23 22:20:53 +02:00
|
|
|
import styled from 'styled-components';
|
2020-06-13 00:21:58 +02:00
|
|
|
import ProfileIcon from 'shared/components/ProfileIcon';
|
2020-08-13 03:54:14 +02:00
|
|
|
import { usePopup } from 'shared/components/PopupMenu';
|
2020-07-05 01:02:57 +02:00
|
|
|
import { RoleCode } from 'shared/generated/graphql';
|
2020-08-13 03:54:14 +02:00
|
|
|
import NOOP from 'shared/utils/noop';
|
2020-10-21 01:52:09 +02:00
|
|
|
import { useHistory } from 'react-router';
|
2020-04-10 04:40:22 +02:00
|
|
|
import {
|
2020-08-07 03:50:35 +02:00
|
|
|
TaskcafeLogo,
|
|
|
|
TaskcafeTitle,
|
2020-06-23 22:20:53 +02:00
|
|
|
ProjectFinder,
|
|
|
|
LogoContainer,
|
|
|
|
NavSeparator,
|
2020-08-13 03:54:14 +02:00
|
|
|
IconContainerWrapper,
|
2021-01-06 01:53:48 +01:00
|
|
|
ProjectNameWrapper,
|
|
|
|
ProjectNameSpan,
|
2020-05-31 06:11:19 +02:00
|
|
|
ProjectNameTextarea,
|
2020-05-27 23:18:50 +02:00
|
|
|
InviteButton,
|
2020-04-10 04:40:22 +02:00
|
|
|
GlobalActions,
|
|
|
|
ProjectActions,
|
2020-04-21 01:04:27 +02:00
|
|
|
ProjectMeta,
|
|
|
|
ProjectName,
|
|
|
|
ProjectTabs,
|
|
|
|
ProjectTab,
|
2020-04-10 04:40:22 +02:00
|
|
|
NavbarWrapper,
|
|
|
|
NavbarHeader,
|
2020-05-27 02:53:31 +02:00
|
|
|
ProjectSettingsButton,
|
2020-04-10 04:40:22 +02:00
|
|
|
ProfileContainer,
|
|
|
|
ProfileNameWrapper,
|
|
|
|
ProfileNamePrimary,
|
|
|
|
ProfileNameSecondary,
|
2020-07-05 01:02:57 +02:00
|
|
|
ProjectMember,
|
2020-05-27 23:18:50 +02:00
|
|
|
ProjectMembers,
|
2020-04-10 04:40:22 +02:00
|
|
|
} from './Styles';
|
2020-06-23 22:20:53 +02:00
|
|
|
|
2020-08-13 03:54:14 +02:00
|
|
|
type IconContainerProps = {
|
|
|
|
disabled?: boolean;
|
|
|
|
onClick?: ($target: React.RefObject<HTMLElement>) => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
const IconContainer: React.FC<IconContainerProps> = ({ onClick, disabled = false, children }) => {
|
|
|
|
const $container = useRef<HTMLDivElement>(null);
|
|
|
|
return (
|
|
|
|
<IconContainerWrapper
|
|
|
|
ref={$container}
|
|
|
|
disabled={disabled}
|
|
|
|
onClick={() => {
|
|
|
|
if (onClick) {
|
|
|
|
onClick($container);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</IconContainerWrapper>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-06-23 22:20:53 +02:00
|
|
|
const HomeDashboard = styled(Home)``;
|
2020-04-10 04:40:22 +02:00
|
|
|
|
2020-05-31 06:11:19 +02:00
|
|
|
type ProjectHeadingProps = {
|
2020-06-23 22:20:53 +02:00
|
|
|
onFavorite?: () => void;
|
|
|
|
name: string;
|
2020-08-01 03:01:14 +02:00
|
|
|
canEditProjectName: boolean;
|
2020-05-31 06:11:19 +02:00
|
|
|
onSaveProjectName?: (projectName: string) => void;
|
2020-06-01 04:20:03 +02:00
|
|
|
onOpenSettings: ($target: React.RefObject<HTMLElement>) => void;
|
2020-05-31 06:11:19 +02:00
|
|
|
};
|
|
|
|
|
2020-06-01 04:20:03 +02:00
|
|
|
const ProjectHeading: React.FC<ProjectHeadingProps> = ({
|
2020-06-23 22:20:53 +02:00
|
|
|
onFavorite,
|
|
|
|
name: initialProjectName,
|
2020-06-01 04:20:03 +02:00
|
|
|
onSaveProjectName,
|
2020-08-01 03:01:14 +02:00
|
|
|
canEditProjectName,
|
2020-06-01 04:20:03 +02:00
|
|
|
onOpenSettings,
|
|
|
|
}) => {
|
2020-05-31 06:11:19 +02:00
|
|
|
const [isEditProjectName, setEditProjectName] = useState(false);
|
|
|
|
const [projectName, setProjectName] = useState(initialProjectName);
|
2021-01-06 01:53:48 +01:00
|
|
|
const $projectName = useRef<HTMLInputElement>(null);
|
2020-05-31 06:11:19 +02:00
|
|
|
useEffect(() => {
|
|
|
|
if (isEditProjectName && $projectName && $projectName.current) {
|
|
|
|
$projectName.current.focus();
|
|
|
|
$projectName.current.select();
|
|
|
|
}
|
|
|
|
}, [isEditProjectName]);
|
|
|
|
useEffect(() => {
|
|
|
|
setProjectName(initialProjectName);
|
|
|
|
}, [initialProjectName]);
|
|
|
|
|
2021-01-06 01:53:48 +01:00
|
|
|
const onProjectNameChange = (event: React.FormEvent<HTMLInputElement>): void => {
|
2020-05-31 06:11:19 +02:00
|
|
|
setProjectName(event.currentTarget.value);
|
|
|
|
};
|
|
|
|
const onProjectNameBlur = () => {
|
|
|
|
if (onSaveProjectName) {
|
|
|
|
onSaveProjectName(projectName);
|
|
|
|
}
|
|
|
|
setEditProjectName(false);
|
|
|
|
};
|
|
|
|
const onProjectNameKeyDown = (e: React.KeyboardEvent) => {
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
e.preventDefault();
|
|
|
|
if ($projectName && $projectName.current) {
|
|
|
|
$projectName.current.blur();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-01 04:20:03 +02:00
|
|
|
const $settings = useRef<HTMLButtonElement>(null);
|
2020-05-31 06:11:19 +02:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{isEditProjectName ? (
|
2021-01-06 01:53:48 +01:00
|
|
|
<ProjectNameWrapper>
|
|
|
|
<ProjectNameSpan>{projectName}</ProjectNameSpan>
|
|
|
|
<ProjectNameTextarea
|
|
|
|
ref={$projectName}
|
|
|
|
onChange={onProjectNameChange}
|
|
|
|
onKeyDown={onProjectNameKeyDown}
|
|
|
|
onBlur={onProjectNameBlur}
|
|
|
|
spellCheck={false}
|
|
|
|
value={projectName}
|
|
|
|
/>
|
|
|
|
</ProjectNameWrapper>
|
2020-05-31 06:11:19 +02:00
|
|
|
) : (
|
|
|
|
<ProjectName
|
|
|
|
onClick={() => {
|
2020-08-01 03:01:14 +02:00
|
|
|
if (canEditProjectName) {
|
|
|
|
setEditProjectName(true);
|
|
|
|
}
|
2020-05-31 06:11:19 +02:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
{projectName}
|
|
|
|
</ProjectName>
|
|
|
|
)}
|
2020-06-01 04:20:03 +02:00
|
|
|
<ProjectSettingsButton
|
|
|
|
onClick={() => {
|
|
|
|
onOpenSettings($settings);
|
|
|
|
}}
|
|
|
|
ref={$settings}
|
|
|
|
>
|
2020-05-31 07:15:10 +02:00
|
|
|
<AngleDown color="#c2c6dc" />
|
|
|
|
</ProjectSettingsButton>
|
2020-06-23 22:20:53 +02:00
|
|
|
{onFavorite && (
|
|
|
|
<ProjectSettingsButton onClick={() => onFavorite()}>
|
|
|
|
<Star width={16} height={16} color="#c2c6dc" />
|
|
|
|
</ProjectSettingsButton>
|
|
|
|
)}
|
2020-05-31 06:11:19 +02:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-07-05 01:02:57 +02:00
|
|
|
export type MenuItem = {
|
|
|
|
name: string;
|
|
|
|
link: string;
|
2020-06-23 22:20:53 +02:00
|
|
|
};
|
|
|
|
type MenuTypes = {
|
|
|
|
[key: string]: Array<string>;
|
|
|
|
};
|
|
|
|
|
|
|
|
export const MENU_TYPES: MenuTypes = {
|
|
|
|
PROJECT_MENU: ['Board', 'Timeline', 'Calender'],
|
|
|
|
TEAM_MENU: ['Projects', 'Members', 'Settings'],
|
|
|
|
};
|
|
|
|
|
2020-04-10 04:40:22 +02:00
|
|
|
type NavBarProps = {
|
2020-07-05 01:02:57 +02:00
|
|
|
menuType?: Array<MenuItem> | null;
|
2020-06-23 22:20:53 +02:00
|
|
|
name: string | null;
|
|
|
|
currentTab?: number;
|
2020-07-05 01:02:57 +02:00
|
|
|
onSetTab?: (tab: number) => void;
|
2020-06-23 22:20:53 +02:00
|
|
|
onOpenProjectFinder: ($target: React.RefObject<HTMLElement>) => void;
|
2020-07-05 01:02:57 +02:00
|
|
|
onChangeProjectOwner?: (userID: string) => void;
|
|
|
|
onChangeRole?: (userID: string, roleCode: RoleCode) => void;
|
2020-06-23 22:20:53 +02:00
|
|
|
onFavorite?: () => void;
|
2020-06-13 00:21:58 +02:00
|
|
|
onProfileClick: ($target: React.RefObject<HTMLElement>) => void;
|
2020-06-23 22:20:53 +02:00
|
|
|
onSaveName?: (name: string) => void;
|
2020-08-13 03:54:14 +02:00
|
|
|
onNotificationClick: ($target: React.RefObject<HTMLElement>) => void;
|
2020-08-01 03:01:14 +02:00
|
|
|
canEditProjectName?: boolean;
|
|
|
|
canInviteUser?: boolean;
|
2020-07-05 01:02:57 +02:00
|
|
|
onInviteUser?: ($target: React.RefObject<HTMLElement>) => void;
|
2020-06-23 22:20:53 +02:00
|
|
|
onDashboardClick: () => void;
|
2020-06-13 00:21:58 +02:00
|
|
|
user: TaskUser | null;
|
2020-06-01 04:20:03 +02:00
|
|
|
onOpenSettings: ($target: React.RefObject<HTMLElement>) => void;
|
2020-05-27 23:18:50 +02:00
|
|
|
projectMembers?: Array<TaskUser> | null;
|
2020-10-21 01:52:09 +02:00
|
|
|
projectInvitedMembers?: Array<InvitedUser> | null;
|
|
|
|
|
2020-07-05 01:02:57 +02:00
|
|
|
onRemoveFromBoard?: (userID: string) => void;
|
2020-08-01 03:01:14 +02:00
|
|
|
onMemberProfile?: ($targetRef: React.RefObject<HTMLElement>, memberID: string) => void;
|
2020-10-21 01:52:09 +02:00
|
|
|
onInvitedMemberProfile?: ($targetRef: React.RefObject<HTMLElement>, email: string) => void;
|
2020-12-31 03:56:59 +01:00
|
|
|
onMyTasksClick: () => void;
|
2020-04-10 04:40:22 +02:00
|
|
|
};
|
2020-05-31 06:11:19 +02:00
|
|
|
|
2020-04-21 01:04:27 +02:00
|
|
|
const NavBar: React.FC<NavBarProps> = ({
|
2020-06-23 22:20:53 +02:00
|
|
|
menuType,
|
2020-08-01 03:01:14 +02:00
|
|
|
canInviteUser = false,
|
2020-07-05 01:02:57 +02:00
|
|
|
onInviteUser,
|
|
|
|
onChangeProjectOwner,
|
2020-06-23 22:20:53 +02:00
|
|
|
currentTab,
|
2020-08-01 03:01:14 +02:00
|
|
|
onMemberProfile,
|
2020-10-21 01:52:09 +02:00
|
|
|
onInvitedMemberProfile,
|
2020-08-01 03:01:14 +02:00
|
|
|
canEditProjectName = false,
|
2020-06-23 22:20:53 +02:00
|
|
|
onOpenProjectFinder,
|
|
|
|
onFavorite,
|
2020-07-05 01:02:57 +02:00
|
|
|
onSetTab,
|
2020-10-21 01:52:09 +02:00
|
|
|
projectInvitedMembers,
|
2020-07-05 01:02:57 +02:00
|
|
|
onChangeRole,
|
2020-06-23 22:20:53 +02:00
|
|
|
name,
|
2020-07-05 01:02:57 +02:00
|
|
|
onRemoveFromBoard,
|
2020-06-23 22:20:53 +02:00
|
|
|
onSaveName,
|
2020-04-21 01:04:27 +02:00
|
|
|
onProfileClick,
|
|
|
|
onNotificationClick,
|
2020-06-23 22:20:53 +02:00
|
|
|
onDashboardClick,
|
2020-12-31 03:56:59 +01:00
|
|
|
onMyTasksClick,
|
2020-06-13 00:21:58 +02:00
|
|
|
user,
|
2020-05-27 23:18:50 +02:00
|
|
|
projectMembers,
|
2020-06-01 04:20:03 +02:00
|
|
|
onOpenSettings,
|
2020-04-21 01:04:27 +02:00
|
|
|
}) => {
|
2020-06-13 00:21:58 +02:00
|
|
|
const handleProfileClick = ($target: React.RefObject<HTMLElement>) => {
|
|
|
|
if ($target && $target.current) {
|
|
|
|
onProfileClick($target);
|
|
|
|
}
|
2020-04-10 04:40:22 +02:00
|
|
|
};
|
2020-10-21 01:52:09 +02:00
|
|
|
const history = useHistory();
|
2020-05-27 23:18:50 +02:00
|
|
|
const { showPopup } = usePopup();
|
2020-04-10 04:40:22 +02:00
|
|
|
return (
|
|
|
|
<NavbarWrapper>
|
|
|
|
<NavbarHeader>
|
|
|
|
<ProjectActions>
|
2020-04-21 01:04:27 +02:00
|
|
|
<ProjectMeta>
|
2020-06-23 22:20:53 +02:00
|
|
|
{name && (
|
2020-06-01 04:20:03 +02:00
|
|
|
<ProjectHeading
|
2020-06-23 22:20:53 +02:00
|
|
|
onFavorite={onFavorite}
|
2020-06-01 04:20:03 +02:00
|
|
|
onOpenSettings={onOpenSettings}
|
2020-06-23 22:20:53 +02:00
|
|
|
name={name}
|
2020-08-01 03:01:14 +02:00
|
|
|
canEditProjectName={canEditProjectName}
|
2020-06-23 22:20:53 +02:00
|
|
|
onSaveProjectName={onSaveName}
|
2020-06-01 04:20:03 +02:00
|
|
|
/>
|
|
|
|
)}
|
2020-04-21 01:04:27 +02:00
|
|
|
</ProjectMeta>
|
2020-06-23 22:20:53 +02:00
|
|
|
{name && (
|
2020-05-31 07:15:10 +02:00
|
|
|
<ProjectTabs>
|
2020-06-23 22:20:53 +02:00
|
|
|
{menuType &&
|
2020-07-05 01:02:57 +02:00
|
|
|
menuType.map((menu, idx) => {
|
2020-06-23 23:55:17 +02:00
|
|
|
return (
|
2020-07-05 01:02:57 +02:00
|
|
|
<ProjectTab
|
|
|
|
key={menu.name}
|
|
|
|
to={menu.link}
|
|
|
|
exact
|
|
|
|
onClick={() => {
|
|
|
|
// TODO
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{menu.name}
|
2020-06-23 23:55:17 +02:00
|
|
|
</ProjectTab>
|
|
|
|
);
|
2020-06-23 22:20:53 +02:00
|
|
|
})}
|
2020-05-31 07:15:10 +02:00
|
|
|
</ProjectTabs>
|
|
|
|
)}
|
2020-04-10 04:40:22 +02:00
|
|
|
</ProjectActions>
|
2020-06-23 22:20:53 +02:00
|
|
|
<LogoContainer to="/">
|
2020-08-07 03:50:35 +02:00
|
|
|
<TaskcafeLogo width={32} height={32} />
|
|
|
|
<TaskcafeTitle>Taskcafé</TaskcafeTitle>
|
2020-06-23 22:20:53 +02:00
|
|
|
</LogoContainer>
|
2020-04-10 04:40:22 +02:00
|
|
|
<GlobalActions>
|
2020-10-21 01:52:09 +02:00
|
|
|
{projectMembers && projectInvitedMembers && onMemberProfile && onInvitedMemberProfile && (
|
2020-06-23 22:20:53 +02:00
|
|
|
<>
|
|
|
|
<ProjectMembers>
|
2020-07-05 01:02:57 +02:00
|
|
|
{projectMembers.map((member, idx) => (
|
|
|
|
<ProjectMember
|
|
|
|
showRoleIcons
|
2020-10-21 01:52:09 +02:00
|
|
|
zIndex={projectMembers.length - idx + projectInvitedMembers.length}
|
2020-07-05 01:02:57 +02:00
|
|
|
key={member.id}
|
|
|
|
size={28}
|
|
|
|
member={member}
|
|
|
|
onMemberProfile={onMemberProfile}
|
|
|
|
/>
|
2020-06-23 22:20:53 +02:00
|
|
|
))}
|
2020-10-21 01:52:09 +02:00
|
|
|
{projectInvitedMembers.map((member, idx) => (
|
|
|
|
<ProjectMember
|
|
|
|
showRoleIcons
|
|
|
|
zIndex={projectInvitedMembers.length - idx}
|
|
|
|
key={member.email}
|
|
|
|
size={28}
|
|
|
|
invited
|
|
|
|
member={{
|
|
|
|
id: member.email,
|
|
|
|
fullName: member.email,
|
|
|
|
profileIcon: {
|
|
|
|
url: null,
|
|
|
|
initials: member.email.charAt(0),
|
|
|
|
bgColor: '#fff',
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
onMemberProfile={onInvitedMemberProfile}
|
|
|
|
/>
|
|
|
|
))}
|
2020-08-01 03:01:14 +02:00
|
|
|
{canInviteUser && (
|
|
|
|
<InviteButton
|
|
|
|
onClick={$target => {
|
|
|
|
if (onInviteUser) {
|
|
|
|
onInviteUser($target);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
variant="outline"
|
|
|
|
>
|
|
|
|
Invite
|
|
|
|
</InviteButton>
|
|
|
|
)}
|
2020-06-23 22:20:53 +02:00
|
|
|
</ProjectMembers>
|
|
|
|
<NavSeparator />
|
|
|
|
</>
|
2020-05-27 23:18:50 +02:00
|
|
|
)}
|
2020-06-23 22:20:53 +02:00
|
|
|
<ProjectFinder onClick={onOpenProjectFinder} variant="gradient">
|
|
|
|
Projects
|
|
|
|
</ProjectFinder>
|
2020-08-13 03:54:14 +02:00
|
|
|
<IconContainer onClick={() => onDashboardClick()}>
|
2020-06-23 22:20:53 +02:00
|
|
|
<HomeDashboard width={20} height={20} />
|
|
|
|
</IconContainer>
|
2020-12-31 03:56:59 +01:00
|
|
|
<IconContainer onClick={() => onMyTasksClick()}>
|
2020-06-23 22:20:53 +02:00
|
|
|
<CheckCircle width={20} height={20} />
|
|
|
|
</IconContainer>
|
2020-10-21 01:52:09 +02:00
|
|
|
<IconContainer disabled onClick={NOOP}>
|
|
|
|
<ListUnordered width={20} height={20} />
|
|
|
|
</IconContainer>
|
2020-08-13 03:54:14 +02:00
|
|
|
<IconContainer disabled onClick={onNotificationClick}>
|
2020-04-10 04:40:22 +02:00
|
|
|
<Bell color="#c2c6dc" size={20} />
|
2020-06-23 22:20:53 +02:00
|
|
|
</IconContainer>
|
2020-08-13 03:54:14 +02:00
|
|
|
<IconContainer disabled onClick={NOOP}>
|
2020-06-23 22:20:53 +02:00
|
|
|
<BarChart width={20} height={20} />
|
|
|
|
</IconContainer>
|
2020-06-13 00:21:58 +02:00
|
|
|
|
|
|
|
{user && (
|
2020-06-23 22:20:53 +02:00
|
|
|
<IconContainer>
|
|
|
|
<ProfileIcon user={user} size={30} onProfileClick={handleProfileClick} />
|
|
|
|
</IconContainer>
|
2020-06-13 00:21:58 +02:00
|
|
|
)}
|
2020-04-10 04:40:22 +02:00
|
|
|
</GlobalActions>
|
|
|
|
</NavbarHeader>
|
|
|
|
</NavbarWrapper>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default NavBar;
|