types#BoardMember TypeScript Examples
The following examples show how to use
types#BoardMember.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CommentItem.test.tsx From knboard with MIT License | 5 votes |
member: BoardMember = {
id: 1,
username: "foobar",
email: "[email protected]",
first_name: "Foo",
last_name: "Bar",
avatar: null,
}
Example #2
Source File: MemberSlice.tsx From knboard with MIT License | 5 votes |
memberAdapter = createEntityAdapter<BoardMember>({
sortComparer: (a, b) => a.username.localeCompare(b.username),
})
Example #3
Source File: Task.tsx From knboard with MIT License | 5 votes |
TaskFooter = ({ task }: { task: ITask }) => {
const membersByIds = useSelector(selectMembersEntities);
const assignees = task.assignees.map(
(assigneeId) => membersByIds[assigneeId]
) as BoardMember[];
return (
<Footer>
<CardIcon data-testid="task-priority">
<FontAwesomeIcon icon={faArrowUp} color={PRIO_COLORS[task.priority]} />
</CardIcon>
{assignees.length > 0 && (
<Assignees>
<AvatarGroup
max={3}
css={css`
& .MuiAvatarGroup-avatar {
height: 1.25rem;
width: 1.25rem;
font-size: 8px;
margin-left: -4px;
border: none;
}
`}
>
{assignees.map((assignee) => (
<Avatar
key={assignee.id}
css={css`
height: 1.25rem;
width: 1.25rem;
font-size: 8px;
margin-left: -12px;
`}
src={assignee.avatar?.photo}
alt={assignee.avatar?.name}
>
{assignee.username.charAt(0)}
</Avatar>
))}
</AvatarGroup>
</Assignees>
)}
</Footer>
);
}
Example #4
Source File: MemberDialog.tsx From knboard with MIT License | 4 votes |
MemberDialog = ({ board }: Props) => {
const theme = useTheme();
const dispatch = useDispatch();
const memberId = useSelector((state: RootState) => state.member.dialogMember);
const members = useSelector(selectMembersEntities);
const boardOwner = useSelector((state: RootState) =>
currentBoardOwner(state)
);
const xsDown = useMediaQuery(theme.breakpoints.down("xs"));
const [confirmDelete, setConfirmDelete] = useState(false);
const member = memberId === null ? null : members[memberId];
const memberIsOwner = member?.id === board.owner;
const open = member !== null;
if (!member) {
return null;
}
const handleClose = () => {
dispatch(setDialogMember(null));
setConfirmDelete(false);
};
const handleRemoveMember = async () => {
try {
const response = await api.post(
`${API_BOARDS}${board.id}/remove_member/`,
{ username: member.username }
);
const removedMember = response.data as BoardMember;
dispatch(removeBoardMember(removedMember.id));
dispatch(createSuccessToast(`Removed ${removedMember.username}`));
handleClose();
} catch (err) {
dispatch(createErrorToast(err.toString()));
}
};
return (
<Dialog
open={open}
onClose={handleClose}
maxWidth="xs"
fullWidth
fullScreen={xsDown}
>
<Close onClose={handleClose} />
<DialogTitle id="member-detail">Member</DialogTitle>
<Container theme={theme}>
{confirmDelete ? (
<div>
<Alert
severity="error"
css={css`
margin-bottom: 2rem;
`}
>
Are you sure you want to remove this member? This member will be
removed from all cards.
</Alert>
<ConfirmAction>
<Fab
size="small"
onClick={() => setConfirmDelete(false)}
css={css`
box-shadow: none;
&.MuiFab-sizeSmall {
width: 32px;
height: 32px;
}
`}
>
<FontAwesomeIcon icon={faAngleLeft} color="#555" />
</Fab>
<Button
size="small"
color="secondary"
variant="contained"
onClick={handleRemoveMember}
css={css`
font-size: 0.625rem;
`}
>
Remove member
</Button>
</ConfirmAction>
</div>
) : (
<>
<Avatar
css={css`
height: 6rem;
width: 6rem;
font-size: 36px;
margin-bottom: 1rem;
`}
src={member?.avatar?.photo}
alt={member?.avatar?.name}
>
{member.username.charAt(0)}
</Avatar>
<Main>
<PrimaryText>
{member.first_name} {member.last_name}
</PrimaryText>
<SecondaryText>
username: <b>{member.username}</b>
</SecondaryText>
<SecondaryText
css={css`
margin-bottom: 1.5rem;
`}
>
email: <b>{member?.email || "-"}</b>
</SecondaryText>
{memberIsOwner && (
<Alert severity="info">Owner of this board</Alert>
)}
{boardOwner && !memberIsOwner && (
<Button
size="small"
css={css`
color: #333;
font-size: 0.625rem;
`}
variant="outlined"
onClick={() => setConfirmDelete(true)}
>
Remove from board
</Button>
)}
</Main>
</>
)}
</Container>
</Dialog>
);
}
Example #5
Source File: MemberFilter.tsx From knboard with MIT License | 4 votes |
MemberFilter = ({ boardId }: Props) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [filteredAssignee, setFilteredAssignee] = useState<BoardMember[]>([]);
const dispatch = useDispatch();
const members = useSelector(selectAllMembers);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const postFilterMember = async (users: BoardMember[]) => {
dispatch(
fetchBoardById({
boardId: boardId,
assigneeIds: users.map((m) => m.id),
})
);
handleClose();
};
const handleClickFilter = () => {
postFilterMember(filteredAssignee);
};
const handleClickClearFilter = () => {
setFilteredAssignee([]);
postFilterMember([]);
};
const ClearFilterButton = () => (
<FilterButton>
<Button
variant="outlined"
size="small"
css={css`
text-transform: none;
`}
onClick={handleClickClearFilter}
data-testid="clear-filter"
>
Clear Filters
</Button>
</FilterButton>
);
return (
<>
<FilterButton>
<Button
variant="outlined"
size="small"
css={css`
text-transform: none;
`}
onClick={handleClick}
aria-controls="member-filter-menu"
aria-haspopup="true"
data-testid="member-filter"
>
Filter
</Button>
</FilterButton>
{filteredAssignee.length > 0 ? <ClearFilterButton /> : null}
<Popover
id="member-filter-menu"
anchorEl={anchorEl}
getContentAnchorEl={null}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
open={Boolean(anchorEl)}
onClose={handleClose}
transitionDuration={0}
>
<Content>
<Description>Filter tasks by assignees</Description>
<Box display="flex" alignItems="center">
<Box flexGrow={1}>
<AssigneeAutoComplete
assignee={filteredAssignee}
members={members}
controlId={"assignee-filter"}
dataTestId={"filter-assignees"}
setAssignee={setFilteredAssignee}
/>
</Box>
<Button
color="primary"
variant="contained"
css={css`
font-size: 0.625rem;
margin-left: 0.5rem;
`}
onClick={handleClickFilter}
data-testid="filter-selected"
disabled={filteredAssignee.length === 0}
>
Filter
</Button>
</Box>
</Content>
</Popover>
</>
);
}
Example #6
Source File: MemberInvite.tsx From knboard with MIT License | 4 votes |
MemberInvite = ({ boardId }: Props) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [tagsValue, setTagsValue] = useState<UserOption[]>([]);
const dispatch = useDispatch();
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const postInviteMember = async (users: number[]) => {
try {
const response = await api.post(
`${API_BOARDS}${boardId}/invite_member/`,
{ users }
);
const newMembers = response.data as BoardMember[];
dispatch(addBoardMembers(newMembers));
dispatch(
createSuccessToast(
`Invited ${newMembers.map((m) => m.username).join(", ")}`
)
);
handleClose();
setTagsValue([]);
} catch (err) {
dispatch(createErrorToast(err.toString()));
}
};
const handleClickInvite = () => {
postInviteMember(tagsValue.map((v) => v.id));
};
return (
<>
<InviteMember>
<Button
variant="outlined"
size="small"
css={css`
text-transform: none;
`}
onClick={handleClick}
aria-controls="member-invite-menu"
aria-haspopup="true"
data-testid="member-invite"
>
Invite
</Button>
</InviteMember>
<Popover
id="member-invite-menu"
anchorEl={anchorEl}
getContentAnchorEl={null}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
open={Boolean(anchorEl)}
onClose={handleClose}
transitionDuration={0}
>
<Content>
<Description>Invite to this board</Description>
<Box display="flex" alignItems="center">
<UserSearch
boardId={boardId}
tagsValue={tagsValue}
setTagsValue={setTagsValue}
/>
<Button
color="primary"
variant="contained"
css={css`
font-size: 0.625rem;
margin-left: 0.5rem;
`}
onClick={handleClickInvite}
data-testid="invite-selected"
disabled={tagsValue.length === 0}
>
Invite
</Button>
</Box>
</Content>
</Popover>
</>
);
}
Example #7
Source File: CreateTaskDialog.tsx From knboard with MIT License | 4 votes |
CreateTaskDialog = () => {
const theme = useTheme();
const dispatch = useDispatch();
const labelsOptions = useSelector(selectAllLabels);
const members = useSelector(selectAllMembers);
const open = useSelector((state: RootState) => state.task.createDialogOpen);
const columnId = useSelector(
(state: RootState) => state.task.createDialogColumn
);
const createLoading = useSelector(
(state: RootState) => state.task.createLoading
);
const [titleTouched, setTitleTouched] = useState<boolean>(false);
const [title, setTitle] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [assignees, setAssignees] = useState<BoardMember[]>([]);
const [priority, setPriority] = useState<Priority | null>({
value: "M",
label: "Medium",
});
const [labels, setLabels] = useState<Label[]>([]);
const xsDown = useMediaQuery(theme.breakpoints.down("xs"));
const handleEditorChange = ({ text }: any) => {
setDescription(text);
};
const setInitialValues = () => {
if (columnId) {
setTitleTouched(false);
setTitle("");
setDescription("");
setAssignees([]);
setPriority(PRIORITY_2);
setLabels([]);
}
};
useEffect(() => {
setInitialValues();
}, [open]);
const handleClose = () => {
if (window.confirm("Are you sure? Any progress made will be lost.")) {
dispatch(setCreateDialogOpen(false));
}
};
const handleCreate = async () => {
setTitleTouched(true);
if (columnId && priority) {
const newTask = {
title,
description,
column: columnId,
labels: labels.map((l) => l.id),
assignees: assignees.map((a) => a.id),
priority: priority.value,
};
dispatch(createTask(newTask));
}
};
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.keyCode == Key.Enter && e.metaKey) {
handleCreate();
}
};
return (
<Dialog
open={open}
onClose={handleClose}
maxWidth="sm"
fullWidth
keepMounted={false}
fullScreen={xsDown}
>
<Content onKeyDown={handleKeyDown}>
<DialogTitle>New issue</DialogTitle>
<TextField
autoFocus
id="create-task-title"
data-testid="create-task-title"
label="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
variant="outlined"
fullWidth
size="small"
onBlur={() => setTitleTouched(true)}
error={titleTouched && !title}
/>
<EditorWrapper>
<MdEditor
plugins={MD_EDITOR_PLUGINS}
config={MD_EDITOR_CONFIG}
value={description}
renderHTML={(text) => mdParser.render(text)}
onChange={handleEditorChange}
placeholder="Describe the issue..."
/>
</EditorWrapper>
<Autocomplete
multiple
filterSelectedOptions
disableClearable
openOnFocus
id="create-assignee-select"
size="small"
options={members}
getOptionLabel={(option) => option.username}
value={assignees}
onChange={(_event, value) => setAssignees(value)}
renderOption={(option) => <AvatarOption option={option} />}
renderInput={(params) => (
<TextField {...params} label="Assignees" variant="outlined" />
)}
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<AvatarTag
key={option.id}
option={option}
{...getTagProps({ index })}
/>
))
}
css={css`
width: 100%;
margin-top: 1rem;
`}
/>
<Autocomplete
id="create-priority-select"
size="small"
autoHighlight
options={PRIORITY_OPTIONS}
getOptionLabel={(option) => option.label}
value={priority}
onChange={(_: any, value: Priority | null) => setPriority(value)}
renderOption={(option) => <PriorityOption option={option} />}
renderInput={(params) => (
<TextField {...params} label="Priority" variant="outlined" />
)}
openOnFocus
disableClearable
css={css`
width: 100%;
margin-top: 1rem;
`}
/>
<Autocomplete
multiple
id="create-labels-select"
size="small"
filterSelectedOptions
autoHighlight
openOnFocus
options={labelsOptions}
getOptionLabel={(option) => option.name}
value={labels}
onChange={(_, newLabels) => setLabels(newLabels)}
renderInput={(params) => (
<TextField {...params} label="Labels" variant="outlined" />
)}
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<LabelChip
key={option.id}
label={option}
size="small"
{...getTagProps({ index })}
/>
))
}
renderOption={(option) => <LabelChip label={option} size="small" />}
css={css`
margin-top: 1rem;
width: 100%;
`}
/>
</Content>
<Footer theme={theme}>
<Button
startIcon={
createLoading ? (
<CircularProgress color="inherit" size={16} />
) : (
<FontAwesomeIcon icon={faRocket} />
)
}
variant="contained"
color="primary"
size="small"
onClick={handleCreate}
disabled={createLoading}
data-testid="task-create"
css={css`
${theme.breakpoints.down("xs")} {
flex-grow: 1;
}
`}
>
Create issue ({getMetaKey()}+⏎)
</Button>
<Button
css={css`
margin-left: 1rem;
`}
onClick={handleClose}
>
Cancel (Esc)
</Button>
</Footer>
</Dialog>
);
}
Example #8
Source File: TaskAssignees.tsx From knboard with MIT License | 4 votes |
TaskAssignees = ({ task }: Props) => {
const dispatch = useDispatch();
const membersById = useSelector(selectMembersEntities);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [pendingAssignees, setPendingAssignees] = useState<BoardMember[]>([]);
const members = useSelector(selectAllMembers);
const assignees = task.assignees.map(
(id) => membersById[id]
) as BoardMember[];
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setPendingAssignees(assignees);
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
const currentIds = assignees.map((a) => a.id);
const pendingIds = pendingAssignees.map((member) => member.id);
if (
!(
pendingIds.length === currentIds.length &&
pendingIds
.sort()
.every((value, index) => value === currentIds.sort()[index])
)
) {
dispatch(
patchTask({
id: task.id,
fields: { assignees: pendingIds },
})
);
}
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const popoverId = open ? "task-assignees-popover" : undefined;
return (
<Container>
<Label>Assignees</Label>
{assignees.map((assignee) => (
<List key={assignee.id}>
<div>
<Avatar
css={css`
height: 2rem;
width: 2rem;
margin-right: 0.5rem;
`}
src={assignee.avatar?.photo}
alt={assignee.avatar?.name}
>
{assignee.username.charAt(0)}
</Avatar>
</div>
<div>{assignee.username}</div>
</List>
))}
<Button
size="small"
onClick={handleClick}
data-testid="open-edit-assignees"
css={css`
color: ${PRIMARY};
font-size: 0.7rem;
`}
>
Change
</Button>
<Popover
id={popoverId}
open={open}
anchorEl={anchorEl}
transitionDuration={0}
style={{ zIndex: modalPopperIndex }}
onClose={handleClose}
css={css`
.MuiPaper-rounded {
border-radius: 0;
}
`}
>
<Content>
<Close onClose={handleClose} onPopper />
<ContentTitle>Assigned board members</ContentTitle>
<AssigneeContainer>
<AssigneeAutoComplete
assignee={pendingAssignees}
members={members}
setAssignee={setPendingAssignees}
controlId="assignee-select"
dataTestId={"edit-assignees"}
/>
</AssigneeContainer>
</Content>
</Popover>
</Container>
);
}