feature: fix user admin related bugs
This commit is contained in:
@ -104,24 +104,28 @@ export const RemoveMemberButton = styled(Button)`
|
||||
width: 100%;
|
||||
`;
|
||||
type TeamRoleManagerPopupProps = {
|
||||
user: TaskUser;
|
||||
user: User;
|
||||
users: Array<User>;
|
||||
warning?: string | null;
|
||||
canChangeRole: boolean;
|
||||
onChangeRole: (roleCode: RoleCode) => void;
|
||||
updateUserPassword?: (user: TaskUser, password: string) => void;
|
||||
onRemoveFromTeam?: () => void;
|
||||
onDeleteUser?: (userID: string, newOwnerID: string | null) => void;
|
||||
};
|
||||
|
||||
const TeamRoleManagerPopup: React.FC<TeamRoleManagerPopupProps> = ({
|
||||
warning,
|
||||
user,
|
||||
users,
|
||||
canChangeRole,
|
||||
onRemoveFromTeam,
|
||||
onDeleteUser,
|
||||
updateUserPassword,
|
||||
onChangeRole,
|
||||
}) => {
|
||||
const { hidePopup, setTab } = usePopup();
|
||||
const [userPass, setUserPass] = useState({ pass: '', passConfirm: '' });
|
||||
const [deleteUser, setDeleteUser] = useState<{ label: string; value: string } | null>(null);
|
||||
const hasOwned = user.owned.projects.length !== 0 || user.owned.teams.length !== 0;
|
||||
return (
|
||||
<>
|
||||
<Popup title={null} tab={0}>
|
||||
@ -144,7 +148,7 @@ const TeamRoleManagerPopup: React.FC<TeamRoleManagerPopupProps> = ({
|
||||
>
|
||||
Reset password...
|
||||
</MiniProfileActionItem>
|
||||
<MiniProfileActionItem onClick={() => setTab(5)}>Remove from organzation...</MiniProfileActionItem>
|
||||
<MiniProfileActionItem onClick={() => setTab(2)}>Remove from organzation...</MiniProfileActionItem>
|
||||
</MiniProfileActionWrapper>
|
||||
</MiniProfileActions>
|
||||
{warning && (
|
||||
@ -198,21 +202,55 @@ const TeamRoleManagerPopup: React.FC<TeamRoleManagerPopupProps> = ({
|
||||
)}
|
||||
</MiniProfileActions>
|
||||
</Popup>
|
||||
<Popup title="Remove from Team?" onClose={() => hidePopup()} tab={2}>
|
||||
<Popup title="Remove from Organization?" onClose={() => hidePopup()} tab={2}>
|
||||
<Content>
|
||||
<DeleteDescription>
|
||||
The member will be removed from all cards on this project. They will receive a notification.
|
||||
Removing this user from the organzation will remove them from assigned tasks, projects, and teams.
|
||||
</DeleteDescription>
|
||||
<RemoveMemberButton
|
||||
color="danger"
|
||||
{hasOwned && (
|
||||
<>
|
||||
<DeleteDescription>{`The user is the owner of ${user.owned.projects.length} projects & ${user.owned.teams.length} teams.`}</DeleteDescription>
|
||||
<DeleteDescription>
|
||||
Choose a new user to take over ownership of this user's teams & projects.
|
||||
</DeleteDescription>
|
||||
<UserSelect
|
||||
onChange={v => setDeleteUser(v)}
|
||||
value={deleteUser}
|
||||
options={users.map(u => ({ label: u.fullName, value: u.id }))}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<UserPassConfirmButton
|
||||
disabled={!(!hasOwned || (hasOwned && deleteUser))}
|
||||
onClick={() => {
|
||||
if (onRemoveFromTeam) {
|
||||
onRemoveFromTeam();
|
||||
if (onDeleteUser) {
|
||||
console.log(`${!hasOwned} || (${hasOwned} && ${deleteUser})`);
|
||||
if (!hasOwned || (hasOwned && deleteUser)) {
|
||||
onDeleteUser(user.id, deleteUser ? deleteUser.value : null);
|
||||
}
|
||||
}
|
||||
}}
|
||||
color="danger"
|
||||
>
|
||||
Remove Member
|
||||
</RemoveMemberButton>
|
||||
Delete user
|
||||
</UserPassConfirmButton>
|
||||
</Content>
|
||||
</Popup>
|
||||
<Popup title="Really remove from Team?" onClose={() => hidePopup()} tab={4}>
|
||||
<Content>
|
||||
<DeleteDescription>
|
||||
Removing this user from the organzation will remove them from assigned tasks, projects, and teams.
|
||||
</DeleteDescription>
|
||||
<DeleteDescription>{`The user is the owner of ${user.owned.projects.length} projects & ${user.owned.teams.length} teams.`}</DeleteDescription>
|
||||
<UserSelect onChange={() => {}} value={null} options={users.map(u => ({ label: u.fullName, value: u.id }))} />
|
||||
<UserPassConfirmButton
|
||||
onClick={() => {
|
||||
// onDeleteUser();
|
||||
}}
|
||||
color="danger"
|
||||
>
|
||||
Delete user
|
||||
</UserPassConfirmButton>
|
||||
</Content>
|
||||
</Popup>
|
||||
<Popup title="Reset password?" onClose={() => hidePopup()} tab={3}>
|
||||
@ -253,18 +291,6 @@ const TeamRoleManagerPopup: React.FC<TeamRoleManagerPopupProps> = ({
|
||||
</UserPassConfirmButton>
|
||||
</Content>
|
||||
</Popup>
|
||||
<Popup title="Remove user" onClose={() => hidePopup()} tab={5}>
|
||||
<Content>
|
||||
<DeleteDescription>
|
||||
Removing this user from the organzation will remove them from assigned tasks, projects, and teams.
|
||||
</DeleteDescription>
|
||||
<DeleteDescription>The user is the owner of 3 projects & 2 teams.</DeleteDescription>
|
||||
<UserSelect onChange={() => {}} value={null} options={[{ label: 'Jordan Knott', value: 'jordanknott' }]} />
|
||||
<UserPassConfirmButton onClick={() => {}} color="danger">
|
||||
Set password
|
||||
</UserPassConfirmButton>
|
||||
</Content>
|
||||
</Popup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -653,7 +679,7 @@ const NavItem: React.FC<NavItemProps> = ({ active, name, tab, onClick }) => {
|
||||
type AdminProps = {
|
||||
initialTab: number;
|
||||
onAddUser: ($target: React.RefObject<HTMLElement>) => void;
|
||||
onDeleteUser: ($target: React.RefObject<HTMLElement>, userID: string) => void;
|
||||
onDeleteUser: (userID: string, newOwnerID: string | null) => void;
|
||||
onInviteUser: ($target: React.RefObject<HTMLElement>) => void;
|
||||
users: Array<User>;
|
||||
onUpdateUserPassword: (user: TaskUser, password: string) => void;
|
||||
@ -700,9 +726,10 @@ const Admin: React.FC<AdminProps> = ({
|
||||
<TabContent>
|
||||
<MemberListWrapper>
|
||||
<MemberListHeader>
|
||||
<ListTitle>{`Users (${users.length})`}</ListTitle>
|
||||
<ListTitle>{`Members (${users.length})`}</ListTitle>
|
||||
<ListDesc>
|
||||
Team members can view and join all Team Visible boards and create new boards in the team.
|
||||
Organization admins can create / manage / delete all projects & teams. Members only have access to teams
|
||||
or projects they have been added to.
|
||||
</ListDesc>
|
||||
<ListActions>
|
||||
<FilterSearch width="250px" variant="alternate" placeholder="Filter by name" />
|
||||
@ -735,6 +762,7 @@ const Admin: React.FC<AdminProps> = ({
|
||||
$target,
|
||||
<TeamRoleManagerPopup
|
||||
user={member}
|
||||
users={users}
|
||||
warning={member.role && member.role.code === 'owner' ? warning : null}
|
||||
updateUserPassword={(user, password) => {
|
||||
onUpdateUserPassword(user, password);
|
||||
@ -743,13 +771,7 @@ const Admin: React.FC<AdminProps> = ({
|
||||
onChangeRole={roleCode => {
|
||||
updateUserRole({ variables: { userID: member.id, roleCode } });
|
||||
}}
|
||||
onRemoveFromTeam={
|
||||
member.role && member.role.code === 'owner'
|
||||
? undefined
|
||||
: () => {
|
||||
hidePopup();
|
||||
}
|
||||
}
|
||||
onDeleteUser={onDeleteUser}
|
||||
/>,
|
||||
);
|
||||
}}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, {useState, useRef, useEffect} from 'react';
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import {CheckSquare, Trash, Square, CheckSquareOutline, Clock, Cross, AccountPlus} from 'shared/icons';
|
||||
import {DragDropContext, Droppable, Draggable, DropResult} from 'react-beautiful-dnd';
|
||||
import { CheckSquare, Trash, Square, CheckSquareOutline, Clock, Cross, AccountPlus } from 'shared/icons';
|
||||
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
|
||||
import {
|
||||
isPositionChanged,
|
||||
getSortedDraggables,
|
||||
@ -81,7 +81,7 @@ const ChecklistProgressBar = styled.div`
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
`;
|
||||
const ChecklistProgressBarCurrent = styled.div<{width: number}>`
|
||||
const ChecklistProgressBarCurrent = styled.div<{ width: number }>`
|
||||
width: ${props => props.width}%;
|
||||
background: rgba(${props => (props.width === 100 ? props.theme.colors.success : props.theme.colors.primary)});
|
||||
bottom: 0;
|
||||
@ -132,7 +132,7 @@ const ChecklistItemTextControls = styled.div`
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const ChecklistItemText = styled.span<{complete: boolean}>`
|
||||
const ChecklistItemText = styled.span<{ complete: boolean }>`
|
||||
color: ${props => (props.complete ? '#5e6c84' : `rgba(${props.theme.colors.text.primary})`)};
|
||||
${props => props.complete && 'text-decoration: line-through;'}
|
||||
line-height: 20px;
|
||||
@ -156,11 +156,11 @@ const ControlButton = styled.div`
|
||||
padding: 4px 6px;
|
||||
border-radius: 6px;
|
||||
background-color: rgba(${props => props.theme.colors.bg.primary}, 0.8);
|
||||
display: flex;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover {
|
||||
background-color: rgba(${props => props.theme.colors.primary}, 1);
|
||||
}
|
||||
@ -212,16 +212,13 @@ const TrashButton = styled(Trash)`
|
||||
fill: rgba(${props => props.theme.colors.text.primary});
|
||||
`;
|
||||
|
||||
const ChecklistItemWrapper = styled.div<{ref: any}>`
|
||||
const ChecklistItemWrapper = styled.div<{ ref: any }>`
|
||||
user-select: none;
|
||||
clear: both;
|
||||
padding-left: 40px;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
transform-origin: left bottom;
|
||||
transition-property: transform, opacity, height, padding, margin;
|
||||
transition-duration: 0.14s;
|
||||
transition-timing-function: ease-in;
|
||||
|
||||
& ${ControlButton}:last-child {
|
||||
margin-right: 4px;
|
||||
}
|
||||
@ -295,7 +292,17 @@ type ChecklistItemProps = {
|
||||
|
||||
export const ChecklistItem = React.forwardRef(
|
||||
(
|
||||
{itemID, checklistID, complete, name, wrapperProps, handleProps, onChangeName, onToggleItem, onDeleteItem}: ChecklistItemProps,
|
||||
{
|
||||
itemID,
|
||||
checklistID,
|
||||
complete,
|
||||
name,
|
||||
wrapperProps,
|
||||
handleProps,
|
||||
onChangeName,
|
||||
onToggleItem,
|
||||
onDeleteItem,
|
||||
}: ChecklistItemProps,
|
||||
$item,
|
||||
) => {
|
||||
const $editor = useRef<HTMLTextAreaElement>(null);
|
||||
@ -319,8 +326,8 @@ export const ChecklistItem = React.forwardRef(
|
||||
{complete ? (
|
||||
<ChecklistItemCheckedIcon width={20} height={20} />
|
||||
) : (
|
||||
<ChecklistItemUncheckedIcon width={20} height={20} />
|
||||
)}
|
||||
<ChecklistItemUncheckedIcon width={20} height={20} />
|
||||
)}
|
||||
</ChecklistIcon>
|
||||
{editting ? (
|
||||
<>
|
||||
@ -370,34 +377,34 @@ export const ChecklistItem = React.forwardRef(
|
||||
</EditControls>
|
||||
</>
|
||||
) : (
|
||||
<ChecklistItemDetails
|
||||
onClick={() => {
|
||||
setEditting(true);
|
||||
}}
|
||||
>
|
||||
<ChecklistItemRow>
|
||||
<ChecklistItemTextControls>
|
||||
<ChecklistItemText complete={complete}>{name}</ChecklistItemText>
|
||||
<ChecklistControls>
|
||||
<ControlButton>
|
||||
<AssignUserButton width={14} height={14} />
|
||||
</ControlButton>
|
||||
<ControlButton>
|
||||
<ClockButton width={14} height={14} />
|
||||
</ControlButton>
|
||||
<ControlButton
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onDeleteItem(checklistID, itemID);
|
||||
}}
|
||||
>
|
||||
<TrashButton width={14} height={14} />
|
||||
</ControlButton>
|
||||
</ChecklistControls>
|
||||
</ChecklistItemTextControls>
|
||||
</ChecklistItemRow>
|
||||
</ChecklistItemDetails>
|
||||
)}
|
||||
<ChecklistItemDetails
|
||||
onClick={() => {
|
||||
setEditting(true);
|
||||
}}
|
||||
>
|
||||
<ChecklistItemRow>
|
||||
<ChecklistItemTextControls>
|
||||
<ChecklistItemText complete={complete}>{name}</ChecklistItemText>
|
||||
<ChecklistControls>
|
||||
<ControlButton>
|
||||
<AssignUserButton width={14} height={14} />
|
||||
</ControlButton>
|
||||
<ControlButton>
|
||||
<ClockButton width={14} height={14} />
|
||||
</ControlButton>
|
||||
<ControlButton
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onDeleteItem(checklistID, itemID);
|
||||
}}
|
||||
>
|
||||
<TrashButton width={14} height={14} />
|
||||
</ControlButton>
|
||||
</ChecklistControls>
|
||||
</ChecklistItemTextControls>
|
||||
</ChecklistItemRow>
|
||||
</ChecklistItemDetails>
|
||||
)}
|
||||
</ChecklistItemWrapper>
|
||||
);
|
||||
},
|
||||
@ -407,7 +414,7 @@ type AddNewItemProps = {
|
||||
onAddItem: (name: string) => void;
|
||||
};
|
||||
|
||||
const AddNewItem: React.FC<AddNewItemProps> = ({onAddItem}) => {
|
||||
const AddNewItem: React.FC<AddNewItemProps> = ({ onAddItem }) => {
|
||||
const $editor = useRef<HTMLTextAreaElement>(null);
|
||||
const $wrapper = useRef<HTMLDivElement>(null);
|
||||
const [currentName, setCurrentName] = useState('');
|
||||
@ -464,8 +471,8 @@ const AddNewItem: React.FC<AddNewItemProps> = ({onAddItem}) => {
|
||||
</EditControls>
|
||||
</>
|
||||
) : (
|
||||
<NewItemButton onClick={() => setEditting(true)}>Add an item</NewItemButton>
|
||||
)}
|
||||
<NewItemButton onClick={() => setEditting(true)}>Add an item</NewItemButton>
|
||||
)}
|
||||
</ChecklistNewItem>
|
||||
);
|
||||
};
|
||||
@ -477,7 +484,7 @@ type ChecklistTitleEditorProps = {
|
||||
};
|
||||
|
||||
const ChecklistTitleEditor = React.forwardRef(
|
||||
({name, onChangeName, onCancel}: ChecklistTitleEditorProps, $name: any) => {
|
||||
({ name, onChangeName, onCancel }: ChecklistTitleEditorProps, $name: any) => {
|
||||
const [currentName, setCurrentName] = useState(name);
|
||||
return (
|
||||
<>
|
||||
@ -579,21 +586,21 @@ const Checklist = React.forwardRef(
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<WindowChecklistTitle {...handleProps}>
|
||||
<WindowTitleText onClick={() => setEditting(true)}>{name}</WindowTitleText>
|
||||
<WindowOptions>
|
||||
<DeleteButton
|
||||
onClick={$target => {
|
||||
onDeleteChecklist($target, checklistID);
|
||||
}}
|
||||
color="danger"
|
||||
variant="outline"
|
||||
>
|
||||
Delete
|
||||
<WindowChecklistTitle {...handleProps}>
|
||||
<WindowTitleText onClick={() => setEditting(true)}>{name}</WindowTitleText>
|
||||
<WindowOptions>
|
||||
<DeleteButton
|
||||
onClick={$target => {
|
||||
onDeleteChecklist($target, checklistID);
|
||||
}}
|
||||
color="danger"
|
||||
variant="outline"
|
||||
>
|
||||
Delete
|
||||
</DeleteButton>
|
||||
</WindowOptions>
|
||||
</WindowChecklistTitle>
|
||||
)}
|
||||
</WindowOptions>
|
||||
</WindowChecklistTitle>
|
||||
)}
|
||||
</WindowTitle>
|
||||
<ChecklistProgress>
|
||||
<ChecklistProgressPercent>{`${percent}%`}</ChecklistProgressPercent>
|
||||
|
@ -1,6 +1,14 @@
|
||||
import React, { useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||
import { Checkmark } from 'shared/icons';
|
||||
|
||||
const CardCheckmark = styled(Checkmark)`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 11px;
|
||||
`;
|
||||
const CardMember = styled.div<{ bgColor: string }>`
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
@ -34,6 +42,7 @@ type MemberProps = {
|
||||
member: TaskUser;
|
||||
showName?: boolean;
|
||||
className?: string;
|
||||
showCheckmark?: boolean;
|
||||
};
|
||||
|
||||
const CardMemberWrapper = styled.div<{ ref: any }>`
|
||||
@ -46,7 +55,14 @@ const CardMemberName = styled.span`
|
||||
padding-left: 8px;
|
||||
`;
|
||||
|
||||
const Member: React.FC<MemberProps> = ({ onCardMemberClick, taskID, member, showName, className }) => {
|
||||
const Member: React.FC<MemberProps> = ({
|
||||
onCardMemberClick,
|
||||
taskID,
|
||||
member,
|
||||
showName,
|
||||
showCheckmark = false,
|
||||
className,
|
||||
}) => {
|
||||
const $targetRef = useRef<HTMLDivElement>();
|
||||
return (
|
||||
<CardMemberWrapper
|
||||
@ -60,10 +76,9 @@ const Member: React.FC<MemberProps> = ({ onCardMemberClick, taskID, member, show
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CardMember bgColor={member.profileIcon.bgColor ?? '#7367F0'}>
|
||||
<CardMemberInitials>{member.profileIcon.initials}</CardMemberInitials>
|
||||
</CardMember>
|
||||
<TaskAssignee onMemberProfile={() => {}} size={28} member={member} />
|
||||
{showName && <CardMemberName>{member.fullName}</CardMemberName>}
|
||||
{showCheckmark && <CardCheckmark width={12} height={12} />}
|
||||
</CardMemberWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import styled from 'styled-components';
|
||||
import TextareaAutosize from 'react-autosize-textarea/lib';
|
||||
import { mixin } from 'shared/utils/styles';
|
||||
import Member from '../Member';
|
||||
|
||||
export const MemberManagerWrapper = styled.div``;
|
||||
|
||||
@ -48,7 +49,7 @@ export const BoardMembersList = styled.ul`
|
||||
|
||||
export const BoardMembersListItem = styled.li``;
|
||||
|
||||
export const BoardMemberListItemContent = styled.div`
|
||||
export const BoardMemberListItemContent = styled(Member)`
|
||||
background-color: rgba(9, 30, 66, 0.04);
|
||||
padding-right: 28px;
|
||||
border-radius: 3px;
|
||||
@ -64,6 +65,11 @@ export const BoardMemberListItemContent = styled.div`
|
||||
padding: 4px;
|
||||
margin-bottom: 2px;
|
||||
color: #c2c6dc;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(${props => props.theme.colors.primary});
|
||||
color: rgba(${props => props.theme.colors.text.secondary});
|
||||
}
|
||||
`;
|
||||
|
||||
export const ProfileIcon = styled.div`
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
ActiveIconWrapper,
|
||||
} from './Styles';
|
||||
import { Checkmark } from 'shared/icons';
|
||||
import Member from 'shared/components/Member';
|
||||
|
||||
type MemberManagerProps = {
|
||||
availableMembers: Array<TaskUser>;
|
||||
@ -45,7 +46,10 @@ const MemberManager: React.FC<MemberManagerProps> = ({
|
||||
return (
|
||||
<BoardMembersListItem key={member.id}>
|
||||
<BoardMemberListItemContent
|
||||
onClick={() => {
|
||||
member={member}
|
||||
showName
|
||||
showCheckmark={activeMembers.findIndex(m => m.id === member.id) !== -1}
|
||||
onCardMemberClick={() => {
|
||||
const isActive = activeMembers.findIndex(m => m.id === member.id) !== -1;
|
||||
if (isActive) {
|
||||
setActiveMembers(activeMembers.filter(m => m.id !== member.id));
|
||||
@ -54,15 +58,7 @@ const MemberManager: React.FC<MemberManagerProps> = ({
|
||||
}
|
||||
onMemberChange(member, !isActive);
|
||||
}}
|
||||
>
|
||||
<ProfileIcon>JK</ProfileIcon>
|
||||
<MemberName>{member.fullName}</MemberName>
|
||||
{activeMembers.findIndex(m => m.id === member.id) !== -1 && (
|
||||
<ActiveIconWrapper>
|
||||
<Checkmark width={16} height={16} />
|
||||
</ActiveIconWrapper>
|
||||
)}
|
||||
</BoardMemberListItemContent>
|
||||
/>
|
||||
</BoardMembersListItem>
|
||||
);
|
||||
})}
|
||||
|
@ -74,7 +74,13 @@ export const EditorButton = styled.div`
|
||||
margin: 0 0 4px 8px;
|
||||
padding: 6px 12px 6px 8px;
|
||||
text-decoration: none;
|
||||
transition: transform 85ms ease-in;
|
||||
transition: all 85ms ease-in;
|
||||
|
||||
&:hover {
|
||||
transform: translateX(5px);
|
||||
background: rgba(0, 0, 0, 1);
|
||||
color: #fff;
|
||||
}
|
||||
`;
|
||||
|
||||
export const CloseButton = styled.div`
|
||||
|
@ -420,33 +420,35 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
>
|
||||
<Droppable direction="vertical" type="checklistItem" droppableId={checklist.id}>
|
||||
{checklistDrop => (
|
||||
<ChecklistItems ref={checklistDrop.innerRef} {...checklistDrop.droppableProps}>
|
||||
{checklist.items
|
||||
.slice()
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map((item, itemIdx) => (
|
||||
<Draggable key={item.id} draggableId={item.id} index={itemIdx}>
|
||||
{itemDrop => (
|
||||
<ChecklistItem
|
||||
key={item.id}
|
||||
itemID={item.id}
|
||||
checklistID={item.taskChecklistID}
|
||||
ref={itemDrop.innerRef}
|
||||
wrapperProps={itemDrop.draggableProps}
|
||||
handleProps={itemDrop.dragHandleProps}
|
||||
name={item.name}
|
||||
complete={item.complete}
|
||||
onDeleteItem={onDeleteItem}
|
||||
onChangeName={onChangeItemName}
|
||||
onToggleItem={(itemID, complete) =>
|
||||
onToggleChecklistItem(item.id, complete)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
<>
|
||||
<ChecklistItems ref={checklistDrop.innerRef} {...checklistDrop.droppableProps}>
|
||||
{checklist.items
|
||||
.slice()
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map((item, itemIdx) => (
|
||||
<Draggable key={item.id} draggableId={item.id} index={itemIdx}>
|
||||
{itemDrop => (
|
||||
<ChecklistItem
|
||||
key={item.id}
|
||||
itemID={item.id}
|
||||
checklistID={item.taskChecklistID}
|
||||
ref={itemDrop.innerRef}
|
||||
wrapperProps={itemDrop.draggableProps}
|
||||
handleProps={itemDrop.dragHandleProps}
|
||||
name={item.name}
|
||||
complete={item.complete}
|
||||
onDeleteItem={onDeleteItem}
|
||||
onChangeName={onChangeItemName}
|
||||
onToggleItem={(itemID, complete) =>
|
||||
onToggleChecklistItem(item.id, complete)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
</ChecklistItems>
|
||||
{checklistDrop.placeholder}
|
||||
</ChecklistItems>
|
||||
</>
|
||||
)}
|
||||
</Droppable>
|
||||
</Checklist>
|
||||
|
Reference in New Issue
Block a user