feat(MyTasks): allow filtering by task complete status
This commit is contained in:
parent
a1c9251a1f
commit
f051bebd48
151
frontend/src/MyTasks/MyTasksStatus.tsx
Normal file
151
frontend/src/MyTasks/MyTasksStatus.tsx
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Checkmark } from 'shared/icons';
|
||||||
|
import { TaskStatusFilter, TaskStatus, TaskSince } from 'shared/components/Lists';
|
||||||
|
import { MyTasksStatus } from 'shared/generated/graphql';
|
||||||
|
import { Popup } from 'shared/components/PopupMenu';
|
||||||
|
|
||||||
|
export const ActionsList = styled.ul`
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionExtraMenuContainer = styled.div`
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
top: -4px;
|
||||||
|
padding-left: 2px;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionItem = styled.li`
|
||||||
|
position: relative;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
&:hover {
|
||||||
|
background: ${props => props.theme.colors.primary};
|
||||||
|
}
|
||||||
|
&:hover ${ActionExtraMenuContainer} {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionTitle = styled.span`
|
||||||
|
margin-left: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionExtraMenu = styled.ul`
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 5px 25px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
color: #c2c6dc;
|
||||||
|
background: #262c49;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
border-color: #414561;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionExtraMenuItem = styled.li`
|
||||||
|
position: relative;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
&:hover {
|
||||||
|
background: rgb(${props => props.theme.colors.primary});
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
const ActionExtraMenuSeparator = styled.li`
|
||||||
|
color: ${props => props.theme.colors.text.primary};
|
||||||
|
font-size: 12px;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ActiveIcon = styled(Checkmark)`
|
||||||
|
position: absolute;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type MyTasksStatusProps = {
|
||||||
|
status: MyTasksStatus;
|
||||||
|
onChangeStatus: (status: MyTasksStatus) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyTasksStatusPopup: React.FC<MyTasksStatusProps> = ({ status: initialStatus, onChangeStatus }) => {
|
||||||
|
const [status, setStatus] = useState(initialStatus);
|
||||||
|
const handleStatusChange = (f: MyTasksStatus) => {
|
||||||
|
setStatus(f);
|
||||||
|
onChangeStatus(f);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Popup tab={0} title={null}>
|
||||||
|
<ActionsList>
|
||||||
|
<ActionItem onClick={() => handleStatusChange(MyTasksStatus.Incomplete)}>
|
||||||
|
{status === MyTasksStatus.Incomplete && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>Incomplete Tasks</ActionTitle>
|
||||||
|
</ActionItem>
|
||||||
|
<ActionItem>
|
||||||
|
{status !== MyTasksStatus.Incomplete && status !== MyTasksStatus.All && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>Compelete Tasks</ActionTitle>
|
||||||
|
<ActionExtraMenuContainer>
|
||||||
|
<ActionExtraMenu>
|
||||||
|
<ActionExtraMenuItem onClick={() => handleStatusChange(MyTasksStatus.CompleteAll)}>
|
||||||
|
{status === MyTasksStatus.CompleteAll && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>All completed tasks</ActionTitle>
|
||||||
|
</ActionExtraMenuItem>
|
||||||
|
<ActionExtraMenuSeparator>Marked complete since</ActionExtraMenuSeparator>
|
||||||
|
<ActionExtraMenuItem onClick={() => handleStatusChange(MyTasksStatus.CompleteToday)}>
|
||||||
|
{status === MyTasksStatus.CompleteToday && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>Today</ActionTitle>
|
||||||
|
</ActionExtraMenuItem>
|
||||||
|
<ActionExtraMenuItem onClick={() => handleStatusChange(MyTasksStatus.CompleteYesterday)}>
|
||||||
|
{status === MyTasksStatus.CompleteYesterday && <ActiveIcon width={12} height={12} />}
|
||||||
|
|
||||||
|
<ActionTitle>Yesterday</ActionTitle>
|
||||||
|
</ActionExtraMenuItem>
|
||||||
|
<ActionExtraMenuItem onClick={() => handleStatusChange(MyTasksStatus.CompleteOneWeek)}>
|
||||||
|
{status === MyTasksStatus.CompleteOneWeek && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>1 week</ActionTitle>
|
||||||
|
</ActionExtraMenuItem>
|
||||||
|
<ActionExtraMenuItem onClick={() => handleStatusChange(MyTasksStatus.CompleteTwoWeek)}>
|
||||||
|
{status === MyTasksStatus.CompleteTwoWeek && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>2 weeks</ActionTitle>
|
||||||
|
</ActionExtraMenuItem>
|
||||||
|
<ActionExtraMenuItem onClick={() => handleStatusChange(MyTasksStatus.CompleteThreeWeek)}>
|
||||||
|
{status === MyTasksStatus.CompleteThreeWeek && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>3 weeks</ActionTitle>
|
||||||
|
</ActionExtraMenuItem>
|
||||||
|
</ActionExtraMenu>
|
||||||
|
</ActionExtraMenuContainer>
|
||||||
|
</ActionItem>
|
||||||
|
<ActionItem onClick={() => handleStatusChange(MyTasksStatus.All)}>
|
||||||
|
{status === MyTasksStatus.All && <ActiveIcon width={12} height={12} />}
|
||||||
|
<ActionTitle>All Tasks</ActionTitle>
|
||||||
|
</ActionItem>
|
||||||
|
</ActionsList>
|
||||||
|
</Popup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MyTasksStatusPopup;
|
@ -19,7 +19,7 @@ import { usePopup, Popup } from 'shared/components/PopupMenu';
|
|||||||
import updateApolloCache from 'shared/utils/cache';
|
import updateApolloCache from 'shared/utils/cache';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import NOOP from 'shared/utils/noop';
|
import NOOP from 'shared/utils/noop';
|
||||||
import { Sort, Cogs, CaretDown, CheckCircle, CaretRight } from 'shared/icons';
|
import { Sort, Cogs, CaretDown, CheckCircle, CaretRight, CheckCircleOutline } from 'shared/icons';
|
||||||
import Select from 'react-select';
|
import Select from 'react-select';
|
||||||
import { editorColourStyles } from 'shared/components/Select';
|
import { editorColourStyles } from 'shared/components/Select';
|
||||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||||
@ -27,12 +27,36 @@ import DueDateManager from 'shared/components/DueDateManager';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import useStickyState from 'shared/hooks/useStickyState';
|
import useStickyState from 'shared/hooks/useStickyState';
|
||||||
import MyTasksSortPopup from './MyTasksSort';
|
import MyTasksSortPopup from './MyTasksSort';
|
||||||
|
import MyTasksStatusPopup from './MyTasksStatus';
|
||||||
import TaskEntry from './TaskEntry';
|
import TaskEntry from './TaskEntry';
|
||||||
|
|
||||||
type TaskRouteProps = {
|
type TaskRouteProps = {
|
||||||
taskID: string;
|
taskID: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function prettyStatus(status: MyTasksStatus) {
|
||||||
|
switch (status) {
|
||||||
|
case MyTasksStatus.All:
|
||||||
|
return 'All tasks';
|
||||||
|
case MyTasksStatus.Incomplete:
|
||||||
|
return 'Incomplete tasks';
|
||||||
|
case MyTasksStatus.CompleteAll:
|
||||||
|
return 'All completed tasks';
|
||||||
|
case MyTasksStatus.CompleteToday:
|
||||||
|
return 'Completed tasks: today';
|
||||||
|
case MyTasksStatus.CompleteYesterday:
|
||||||
|
return 'Completed tasks: yesterday';
|
||||||
|
case MyTasksStatus.CompleteOneWeek:
|
||||||
|
return 'Completed tasks: 1 week';
|
||||||
|
case MyTasksStatus.CompleteTwoWeek:
|
||||||
|
return 'Completed tasks: 2 weeks';
|
||||||
|
case MyTasksStatus.CompleteThreeWeek:
|
||||||
|
return 'Completed tasks: 3 weeks';
|
||||||
|
default:
|
||||||
|
return 'unknown tasks';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function prettySort(sort: MyTasksSort) {
|
function prettySort(sort: MyTasksSort) {
|
||||||
if (sort === MyTasksSort.None) {
|
if (sort === MyTasksSort.None) {
|
||||||
return 'Sort';
|
return 'Sort';
|
||||||
@ -492,7 +516,10 @@ const Projects = () => {
|
|||||||
{ sort: MyTasksSort.None, status: MyTasksStatus.All },
|
{ sort: MyTasksSort.None, status: MyTasksStatus.All },
|
||||||
'my_tasks_filter',
|
'my_tasks_filter',
|
||||||
);
|
);
|
||||||
const { data } = useMyTasksQuery({ variables: { sort: filters.sort, status: filters.status } });
|
const { data } = useMyTasksQuery({
|
||||||
|
variables: { sort: filters.sort, status: filters.status },
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
});
|
||||||
const [dateEditor, setDateEditor] = useState<DateEditorState>({ open: false, pos: null, task: null });
|
const [dateEditor, setDateEditor] = useState<DateEditorState>({ open: false, pos: null, task: null });
|
||||||
const onEditDueDate = (task: Task, $target: React.RefObject<HTMLElement>) => {
|
const onEditDueDate = (task: Task, $target: React.RefObject<HTMLElement>) => {
|
||||||
if ($target && $target.current && data) {
|
if ($target && $target.current && data) {
|
||||||
@ -524,7 +551,7 @@ const Projects = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { showPopup } = usePopup();
|
const { showPopup, hidePopup } = usePopup();
|
||||||
const [updateTaskDueDate] = useUpdateTaskDueDateMutation();
|
const [updateTaskDueDate] = useUpdateTaskDueDateMutation();
|
||||||
const $editorContents = useRef<HTMLDivElement>(null);
|
const $editorContents = useRef<HTMLDivElement>(null);
|
||||||
const $dateContents = useRef<HTMLDivElement>(null);
|
const $dateContents = useRef<HTMLDivElement>(null);
|
||||||
@ -653,9 +680,23 @@ const Projects = () => {
|
|||||||
<ProjectBar>
|
<ProjectBar>
|
||||||
<ProjectActions />
|
<ProjectActions />
|
||||||
<ProjectActions>
|
<ProjectActions>
|
||||||
<ProjectAction disabled>
|
<ProjectAction
|
||||||
<CheckCircle width={13} height={13} />
|
onClick={$target => {
|
||||||
<ProjectActionText>All Tasks</ProjectActionText>
|
showPopup(
|
||||||
|
$target,
|
||||||
|
<MyTasksStatusPopup
|
||||||
|
status={filters.status}
|
||||||
|
onChangeStatus={status => {
|
||||||
|
setFilters(prev => ({ ...prev, status }));
|
||||||
|
hidePopup();
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
{ width: 185 },
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CheckCircleOutline width={13} height={13} />
|
||||||
|
<ProjectActionText>{prettyStatus(filters.status)}</ProjectActionText>
|
||||||
</ProjectAction>
|
</ProjectAction>
|
||||||
<ProjectAction
|
<ProjectAction
|
||||||
onClick={$target => {
|
onClick={$target => {
|
||||||
@ -663,8 +704,12 @@ const Projects = () => {
|
|||||||
$target,
|
$target,
|
||||||
<MyTasksSortPopup
|
<MyTasksSortPopup
|
||||||
sort={filters.sort}
|
sort={filters.sort}
|
||||||
onChangeSort={sort => setFilters(prev => ({ ...prev, sort }))}
|
onChangeSort={sort => {
|
||||||
|
setFilters(prev => ({ ...prev, sort }));
|
||||||
|
hidePopup();
|
||||||
|
}}
|
||||||
/>,
|
/>,
|
||||||
|
{ width: 185 },
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
1
go.mod
1
go.mod
@ -9,6 +9,7 @@ require (
|
|||||||
github.com/go-chi/chi v3.3.2+incompatible
|
github.com/go-chi/chi v3.3.2+incompatible
|
||||||
github.com/golang-migrate/migrate/v4 v4.11.0
|
github.com/golang-migrate/migrate/v4 v4.11.0
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
|
github.com/jinzhu/now v1.1.1
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/lib/pq v1.3.0
|
github.com/lib/pq v1.3.0
|
||||||
github.com/lithammer/fuzzysearch v1.1.0
|
github.com/lithammer/fuzzysearch v1.1.0
|
||||||
|
2
go.sum
2
go.sum
@ -338,6 +338,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f
|
|||||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ=
|
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||||
|
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||||
|
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||||
|
@ -69,8 +69,8 @@ type Querier interface {
|
|||||||
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
||||||
GetAllVisibleProjectsForUserID(ctx context.Context, userID uuid.UUID) ([]Project, error)
|
GetAllVisibleProjectsForUserID(ctx context.Context, userID uuid.UUID) ([]Project, error)
|
||||||
GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error)
|
GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error)
|
||||||
GetAssignedTasksDueDateForUserID(ctx context.Context, userID uuid.UUID) ([]Task, error)
|
GetAssignedTasksDueDateForUserID(ctx context.Context, arg GetAssignedTasksDueDateForUserIDParams) ([]Task, error)
|
||||||
GetAssignedTasksProjectForUserID(ctx context.Context, userID uuid.UUID) ([]Task, error)
|
GetAssignedTasksProjectForUserID(ctx context.Context, arg GetAssignedTasksProjectForUserIDParams) ([]Task, error)
|
||||||
GetCommentsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskComment, error)
|
GetCommentsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskComment, error)
|
||||||
GetConfirmTokenByEmail(ctx context.Context, email string) (UserAccountConfirmToken, error)
|
GetConfirmTokenByEmail(ctx context.Context, email string) (UserAccountConfirmToken, error)
|
||||||
GetConfirmTokenByID(ctx context.Context, confirmTokenID uuid.UUID) (UserAccountConfirmToken, error)
|
GetConfirmTokenByID(ctx context.Context, confirmTokenID uuid.UUID) (UserAccountConfirmToken, error)
|
||||||
@ -99,7 +99,7 @@ type Querier interface {
|
|||||||
GetProjectMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectMember, error)
|
GetProjectMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectMember, error)
|
||||||
GetProjectRolesForUserID(ctx context.Context, userID uuid.UUID) ([]GetProjectRolesForUserIDRow, error)
|
GetProjectRolesForUserID(ctx context.Context, userID uuid.UUID) ([]GetProjectRolesForUserIDRow, error)
|
||||||
GetProjectsForInvitedMember(ctx context.Context, email string) ([]uuid.UUID, error)
|
GetProjectsForInvitedMember(ctx context.Context, email string) ([]uuid.UUID, error)
|
||||||
GetRecentlyAssignedTaskForUserID(ctx context.Context, userID uuid.UUID) ([]Task, error)
|
GetRecentlyAssignedTaskForUserID(ctx context.Context, arg GetRecentlyAssignedTaskForUserIDParams) ([]Task, error)
|
||||||
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error)
|
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error)
|
||||||
GetRoleForProjectMemberByUserID(ctx context.Context, arg GetRoleForProjectMemberByUserIDParams) (Role, error)
|
GetRoleForProjectMemberByUserID(ctx context.Context, arg GetRoleForProjectMemberByUserIDParams) (Role, error)
|
||||||
GetRoleForTeamMember(ctx context.Context, arg GetRoleForTeamMemberParams) (Role, error)
|
GetRoleForTeamMember(ctx context.Context, arg GetRoleForTeamMemberParams) (Role, error)
|
||||||
|
@ -59,14 +59,25 @@ UPDATE task_comment SET message = $2, updated_at = $3 WHERE task_comment_id = $1
|
|||||||
|
|
||||||
-- name: GetRecentlyAssignedTaskForUserID :many
|
-- name: GetRecentlyAssignedTaskForUserID :many
|
||||||
SELECT task.* FROM task_assigned INNER JOIN
|
SELECT task.* FROM task_assigned INNER JOIN
|
||||||
task ON task.task_id = task_assigned.task_id WHERE user_id = $1 ORDER BY task_assigned.assigned_date DESC;
|
task ON task.task_id = task_assigned.task_id WHERE user_id = $1
|
||||||
|
AND $4::boolean = true OR (
|
||||||
|
$4::boolean = false AND complete = $2 AND (
|
||||||
|
$2 = false OR ($2 = true AND completed_at > $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY task_assigned.assigned_date DESC;
|
||||||
|
|
||||||
-- name: GetAssignedTasksProjectForUserID :many
|
-- name: GetAssignedTasksProjectForUserID :many
|
||||||
SELECT task.* FROM task_assigned
|
SELECT task.* FROM task_assigned
|
||||||
INNER JOIN task ON task.task_id = task_assigned.task_id
|
INNER JOIN task ON task.task_id = task_assigned.task_id
|
||||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
ORDER BY task_group.project_id DESC, task_assigned.assigned_date DESC;
|
AND $4::boolean = true OR (
|
||||||
|
$4::boolean = false AND complete = $2 AND (
|
||||||
|
$2 = false OR ($2 = true AND completed_at > $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY task_group.project_id DESC, task_assigned.assigned_date DESC;
|
||||||
|
|
||||||
-- name: GetProjectIdMappings :many
|
-- name: GetProjectIdMappings :many
|
||||||
SELECT project_id, task_id FROM task
|
SELECT project_id, task_id FROM task
|
||||||
@ -75,7 +86,12 @@ INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
|||||||
|
|
||||||
-- name: GetAssignedTasksDueDateForUserID :many
|
-- name: GetAssignedTasksDueDateForUserID :many
|
||||||
SELECT task.* FROM task_assigned
|
SELECT task.* FROM task_assigned
|
||||||
INNER JOIN task ON task.task_id = task_assigned.task_id
|
INNER JOIN task ON task.task_id = task_assigned.task_id
|
||||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
ORDER BY task.due_date DESC, task_group.project_id DESC;
|
AND $4::boolean = true OR (
|
||||||
|
$4::boolean = false AND complete = $2 AND (
|
||||||
|
$2 = false OR ($2 = true AND completed_at > $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY task.due_date DESC, task_group.project_id DESC;
|
||||||
|
@ -200,14 +200,31 @@ func (q *Queries) GetAllTasks(ctx context.Context) ([]Task, error) {
|
|||||||
|
|
||||||
const getAssignedTasksDueDateForUserID = `-- name: GetAssignedTasksDueDateForUserID :many
|
const getAssignedTasksDueDateForUserID = `-- name: GetAssignedTasksDueDateForUserID :many
|
||||||
SELECT task.task_id, task.task_group_id, task.created_at, task.name, task.position, task.description, task.due_date, task.complete, task.completed_at, task.has_time FROM task_assigned
|
SELECT task.task_id, task.task_group_id, task.created_at, task.name, task.position, task.description, task.due_date, task.complete, task.completed_at, task.has_time FROM task_assigned
|
||||||
INNER JOIN task ON task.task_id = task_assigned.task_id
|
INNER JOIN task ON task.task_id = task_assigned.task_id
|
||||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
ORDER BY task.due_date DESC, task_group.project_id DESC
|
AND $4::boolean = true OR (
|
||||||
|
$4::boolean = false AND complete = $2 AND (
|
||||||
|
$2 = false OR ($2 = true AND completed_at > $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY task.due_date DESC, task_group.project_id DESC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAssignedTasksDueDateForUserID(ctx context.Context, userID uuid.UUID) ([]Task, error) {
|
type GetAssignedTasksDueDateForUserIDParams struct {
|
||||||
rows, err := q.db.QueryContext(ctx, getAssignedTasksDueDateForUserID, userID)
|
UserID uuid.UUID `json:"user_id"`
|
||||||
|
Complete bool `json:"complete"`
|
||||||
|
CompletedAt sql.NullTime `json:"completed_at"`
|
||||||
|
Column4 bool `json:"column_4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAssignedTasksDueDateForUserID(ctx context.Context, arg GetAssignedTasksDueDateForUserIDParams) ([]Task, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getAssignedTasksDueDateForUserID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Complete,
|
||||||
|
arg.CompletedAt,
|
||||||
|
arg.Column4,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -242,14 +259,31 @@ func (q *Queries) GetAssignedTasksDueDateForUserID(ctx context.Context, userID u
|
|||||||
|
|
||||||
const getAssignedTasksProjectForUserID = `-- name: GetAssignedTasksProjectForUserID :many
|
const getAssignedTasksProjectForUserID = `-- name: GetAssignedTasksProjectForUserID :many
|
||||||
SELECT task.task_id, task.task_group_id, task.created_at, task.name, task.position, task.description, task.due_date, task.complete, task.completed_at, task.has_time FROM task_assigned
|
SELECT task.task_id, task.task_group_id, task.created_at, task.name, task.position, task.description, task.due_date, task.complete, task.completed_at, task.has_time FROM task_assigned
|
||||||
INNER JOIN task ON task.task_id = task_assigned.task_id
|
INNER JOIN task ON task.task_id = task_assigned.task_id
|
||||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
ORDER BY task_group.project_id DESC, task_assigned.assigned_date DESC
|
AND $4::boolean = true OR (
|
||||||
|
$4::boolean = false AND complete = $2 AND (
|
||||||
|
$2 = false OR ($2 = true AND completed_at > $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY task_group.project_id DESC, task_assigned.assigned_date DESC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAssignedTasksProjectForUserID(ctx context.Context, userID uuid.UUID) ([]Task, error) {
|
type GetAssignedTasksProjectForUserIDParams struct {
|
||||||
rows, err := q.db.QueryContext(ctx, getAssignedTasksProjectForUserID, userID)
|
UserID uuid.UUID `json:"user_id"`
|
||||||
|
Complete bool `json:"complete"`
|
||||||
|
CompletedAt sql.NullTime `json:"completed_at"`
|
||||||
|
Column4 bool `json:"column_4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAssignedTasksProjectForUserID(ctx context.Context, arg GetAssignedTasksProjectForUserIDParams) ([]Task, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getAssignedTasksProjectForUserID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Complete,
|
||||||
|
arg.CompletedAt,
|
||||||
|
arg.Column4,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -366,11 +400,29 @@ func (q *Queries) GetProjectIdMappings(ctx context.Context, dollar_1 []uuid.UUID
|
|||||||
|
|
||||||
const getRecentlyAssignedTaskForUserID = `-- name: GetRecentlyAssignedTaskForUserID :many
|
const getRecentlyAssignedTaskForUserID = `-- name: GetRecentlyAssignedTaskForUserID :many
|
||||||
SELECT task.task_id, task.task_group_id, task.created_at, task.name, task.position, task.description, task.due_date, task.complete, task.completed_at, task.has_time FROM task_assigned INNER JOIN
|
SELECT task.task_id, task.task_group_id, task.created_at, task.name, task.position, task.description, task.due_date, task.complete, task.completed_at, task.has_time FROM task_assigned INNER JOIN
|
||||||
task ON task.task_id = task_assigned.task_id WHERE user_id = $1 ORDER BY task_assigned.assigned_date DESC
|
task ON task.task_id = task_assigned.task_id WHERE user_id = $1
|
||||||
|
AND $4::boolean = true OR (
|
||||||
|
$4::boolean = false AND complete = $2 AND (
|
||||||
|
$2 = false OR ($2 = true AND completed_at > $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY task_assigned.assigned_date DESC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetRecentlyAssignedTaskForUserID(ctx context.Context, userID uuid.UUID) ([]Task, error) {
|
type GetRecentlyAssignedTaskForUserIDParams struct {
|
||||||
rows, err := q.db.QueryContext(ctx, getRecentlyAssignedTaskForUserID, userID)
|
UserID uuid.UUID `json:"user_id"`
|
||||||
|
Complete bool `json:"complete"`
|
||||||
|
CompletedAt sql.NullTime `json:"completed_at"`
|
||||||
|
Column4 bool `json:"column_4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetRecentlyAssignedTaskForUserID(ctx context.Context, arg GetRecentlyAssignedTaskForUserIDParams) ([]Task, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getRecentlyAssignedTaskForUserID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Complete,
|
||||||
|
arg.CompletedAt,
|
||||||
|
arg.Column4,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/jinzhu/now"
|
||||||
"github.com/jordanknott/taskcafe/internal/auth"
|
"github.com/jordanknott/taskcafe/internal/auth"
|
||||||
"github.com/jordanknott/taskcafe/internal/db"
|
"github.com/jordanknott/taskcafe/internal/db"
|
||||||
"github.com/jordanknott/taskcafe/internal/logger"
|
"github.com/jordanknott/taskcafe/internal/logger"
|
||||||
@ -1411,18 +1412,60 @@ func (r *queryResolver) MyTasks(ctx context.Context, input MyTasks) (*MyTasksPay
|
|||||||
projects := []ProjectTaskMapping{}
|
projects := []ProjectTaskMapping{}
|
||||||
var tasks []db.Task
|
var tasks []db.Task
|
||||||
var err error
|
var err error
|
||||||
|
showAll := false
|
||||||
|
if input.Status == MyTasksStatusAll {
|
||||||
|
showAll = true
|
||||||
|
}
|
||||||
|
complete := false
|
||||||
|
completedAt := sql.NullTime{Valid: false, Time: time.Time{}}
|
||||||
|
switch input.Status {
|
||||||
|
case MyTasksStatusCompleteAll:
|
||||||
|
complete = true
|
||||||
|
completedAt = sql.NullTime{Valid: true, Time: time.Time{}}
|
||||||
|
case MyTasksStatusCompleteToday:
|
||||||
|
complete = true
|
||||||
|
completedAt = sql.NullTime{Valid: true, Time: now.BeginningOfDay()}
|
||||||
|
case MyTasksStatusCompleteYesterday:
|
||||||
|
complete = true
|
||||||
|
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -1)).BeginningOfDay()}
|
||||||
|
case MyTasksStatusCompleteOneWeek:
|
||||||
|
complete = true
|
||||||
|
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -7)).BeginningOfDay()}
|
||||||
|
case MyTasksStatusCompleteTwoWeek:
|
||||||
|
complete = true
|
||||||
|
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -14)).BeginningOfDay()}
|
||||||
|
case MyTasksStatusCompleteThreeWeek:
|
||||||
|
complete = true
|
||||||
|
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -21)).BeginningOfDay()}
|
||||||
|
}
|
||||||
|
|
||||||
if input.Sort == MyTasksSortNone {
|
if input.Sort == MyTasksSortNone {
|
||||||
tasks, err = r.Repository.GetRecentlyAssignedTaskForUserID(ctx, userID)
|
tasks, err = r.Repository.GetRecentlyAssignedTaskForUserID(ctx, db.GetRecentlyAssignedTaskForUserIDParams{
|
||||||
|
UserID: userID,
|
||||||
|
Complete: complete,
|
||||||
|
CompletedAt: completedAt,
|
||||||
|
Column4: showAll,
|
||||||
|
})
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return &MyTasksPayload{}, err
|
return &MyTasksPayload{}, err
|
||||||
}
|
}
|
||||||
} else if input.Sort == MyTasksSortProject {
|
} else if input.Sort == MyTasksSortProject {
|
||||||
tasks, err = r.Repository.GetAssignedTasksProjectForUserID(ctx, userID)
|
tasks, err = r.Repository.GetAssignedTasksProjectForUserID(ctx, db.GetAssignedTasksProjectForUserIDParams{
|
||||||
|
UserID: userID,
|
||||||
|
Complete: complete,
|
||||||
|
CompletedAt: completedAt,
|
||||||
|
Column4: showAll,
|
||||||
|
})
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return &MyTasksPayload{}, err
|
return &MyTasksPayload{}, err
|
||||||
}
|
}
|
||||||
} else if input.Sort == MyTasksSortDueDate {
|
} else if input.Sort == MyTasksSortDueDate {
|
||||||
tasks, err = r.Repository.GetAssignedTasksDueDateForUserID(ctx, userID)
|
tasks, err = r.Repository.GetAssignedTasksDueDateForUserID(ctx, db.GetAssignedTasksDueDateForUserIDParams{
|
||||||
|
UserID: userID,
|
||||||
|
Complete: complete,
|
||||||
|
CompletedAt: completedAt,
|
||||||
|
Column4: showAll,
|
||||||
|
})
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return &MyTasksPayload{}, err
|
return &MyTasksPayload{}, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user