Skip to content

Commit da3d64e

Browse files
committed
add due date to task
1 parent ad84f7c commit da3d64e

File tree

14 files changed

+78
-30
lines changed

14 files changed

+78
-30
lines changed

backend/api/inputs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class CreateTaskInput:
7676
title: str
7777
patient_id: strawberry.ID
7878
description: str | None = None
79+
due_date: datetime | None = None
7980
assignee_id: strawberry.ID | None = None
8081
previous_task_ids: list[strawberry.ID] | None = None
8182
properties: list[PropertyValueInput] | None = None
@@ -86,6 +87,7 @@ class UpdateTaskInput:
8687
title: str | None = None
8788
description: str | None = None
8889
done: bool | None = None
90+
due_date: datetime | None = None
8991
assignee_id: strawberry.ID | None = None
9092
previous_task_ids: list[strawberry.ID] | None = None
9193
properties: list[PropertyValueInput] | None = None

backend/api/resolvers/task.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ async def tasks(
3434
return result.scalars().all()
3535

3636
@strawberry.field
37-
async def recent_tasks(self, info: Info, limit: int = 10) -> list[TaskType]:
37+
async def recent_tasks(
38+
self, info: Info, limit: int = 10
39+
) -> list[TaskType]:
3840
result = await info.context.db.execute(
3941
select(models.Task)
4042
.order_by(desc(models.Task.update_date))
41-
.limit(limit)
43+
.limit(limit),
4244
)
4345
return result.scalars().all()
4446

@@ -52,6 +54,7 @@ async def create_task(self, info: Info, data: CreateTaskInput) -> TaskType:
5254
description=data.description,
5355
patient_id=data.patient_id,
5456
assignee_id=data.assignee_id,
57+
due_date=data.due_date,
5558
)
5659
info.context.db.add(new_task)
5760
if data.properties:
@@ -87,6 +90,8 @@ async def update_task(
8790
task.description = data.description
8891
if data.done is not None:
8992
task.done = data.done
93+
if data.due_date is not None:
94+
task.due_date = data.due_date
9095
if data.assignee_id is not None:
9196
task.assignee_id = data.assignee_id
9297

@@ -101,7 +106,7 @@ async def update_task(
101106
async def complete_task(self, info: Info, id: strawberry.ID) -> TaskType:
102107
db = info.context.db
103108
result = await db.execute(
104-
select(models.Task).where(models.Task.id == id)
109+
select(models.Task).where(models.Task.id == id),
105110
)
106111
task = result.scalars().first()
107112
if not task:
@@ -116,7 +121,7 @@ async def complete_task(self, info: Info, id: strawberry.ID) -> TaskType:
116121
async def reopen_task(self, info: Info, id: strawberry.ID) -> TaskType:
117122
db = info.context.db
118123
result = await db.execute(
119-
select(models.Task).where(models.Task.id == id)
124+
select(models.Task).where(models.Task.id == id),
120125
)
121126
task = result.scalars().first()
122127
if not task:

backend/api/types/task.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class TaskType:
1919
title: str
2020
description: str | None
2121
done: bool
22+
due_date: datetime | None
2223
creation_date: datetime
2324
update_date: datetime | None
2425
assignee_id: strawberry.ID | None

backend/database/migrations/versions/a0b4916b75c6_.py renamed to backend/database/migrations/versions/baace9e34585_.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""empty message
22
3-
Revision ID: a0b4916b75c6
3+
Revision ID: baace9e34585
44
Revises:
5-
Create Date: 2025-12-12 20:54:09.779104
5+
Create Date: 2025-12-12 21:19:42.928171
66
77
"""
88
from typing import Sequence, Union
@@ -12,7 +12,7 @@
1212

1313

1414
# revision identifiers, used by Alembic.
15-
revision: str = 'a0b4916b75c6'
15+
revision: str = 'baace9e34585'
1616
down_revision: Union[str, Sequence[str], None] = None
1717
branch_labels: Union[str, Sequence[str], None] = None
1818
depends_on: Union[str, Sequence[str], None] = None
@@ -63,6 +63,7 @@ def upgrade() -> None:
6363
sa.Column('title', sa.String(), nullable=False),
6464
sa.Column('description', sa.String(), nullable=True),
6565
sa.Column('done', sa.Boolean(), nullable=False),
66+
sa.Column('due_date', sa.DateTime(), nullable=True),
6667
sa.Column('creation_date', sa.DateTime(), nullable=False),
6768
sa.Column('update_date', sa.DateTime(), nullable=True),
6869
sa.Column('assignee_id', sa.String(), nullable=True),

backend/database/models/task.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Task(Base):
3232
title: Mapped[str] = mapped_column(String)
3333
description: Mapped[str | None] = mapped_column(String, nullable=True)
3434
done: Mapped[bool] = mapped_column(Boolean, default=False)
35+
due_date: Mapped[datetime | None] = mapped_column(nullable=True)
3536
creation_date: Mapped[datetime] = mapped_column(default=datetime.now)
3637
update_date: Mapped[datetime | None] = mapped_column(
3738
nullable=True,

web/api/gql/generated.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export type CreatePropertyDefinitionInput = {
4545
export type CreateTaskInput = {
4646
assigneeId?: InputMaybe<Scalars['ID']['input']>;
4747
description?: InputMaybe<Scalars['String']['input']>;
48+
dueDate?: InputMaybe<Scalars['DateTime']['input']>;
4849
patientId: Scalars['ID']['input'];
4950
previousTaskIds?: InputMaybe<Array<Scalars['ID']['input']>>;
5051
properties?: InputMaybe<Array<PropertyValueInput>>;
@@ -317,6 +318,7 @@ export type TaskType = {
317318
creationDate: Scalars['DateTime']['output'];
318319
description?: Maybe<Scalars['String']['output']>;
319320
done: Scalars['Boolean']['output'];
321+
dueDate?: Maybe<Scalars['DateTime']['output']>;
320322
id: Scalars['ID']['output'];
321323
patient: PatientType;
322324
patientId: Scalars['ID']['output'];
@@ -352,6 +354,7 @@ export type UpdateTaskInput = {
352354
assigneeId?: InputMaybe<Scalars['ID']['input']>;
353355
description?: InputMaybe<Scalars['String']['input']>;
354356
done?: InputMaybe<Scalars['Boolean']['input']>;
357+
dueDate?: InputMaybe<Scalars['DateTime']['input']>;
355358
previousTaskIds?: InputMaybe<Array<Scalars['ID']['input']>>;
356359
properties?: InputMaybe<Array<PropertyValueInput>>;
357360
title?: InputMaybe<Scalars['String']['input']>;
@@ -372,7 +375,7 @@ export type UserType = {
372375
export type GetMyTasksQueryVariables = Exact<{ [key: string]: never; }>;
373376

374377

375-
export type GetMyTasksQuery = { __typename?: 'Query', me?: { __typename?: 'UserType', id: string, tasks: Array<{ __typename?: 'TaskType', id: string, title: string, description?: string | null, done: boolean, creationDate: any, updateDate?: any | null, patient: { __typename?: 'PatientType', id: string, name: string, assignedLocation?: { __typename?: 'LocationNodeType', id: string, title: string, parent?: { __typename?: 'LocationNodeType', id: string, title: string } | null } | null }, assignee?: { __typename?: 'UserType', id: string, name: string, avatarUrl?: string | null } | null }> } | null };
378+
export type GetMyTasksQuery = { __typename?: 'Query', me?: { __typename?: 'UserType', id: string, tasks: Array<{ __typename?: 'TaskType', id: string, title: string, description?: string | null, done: boolean, dueDate?: any | null, creationDate: any, updateDate?: any | null, patient: { __typename?: 'PatientType', id: string, name: string, assignedLocation?: { __typename?: 'LocationNodeType', id: string, title: string, parent?: { __typename?: 'LocationNodeType', id: string, title: string } | null } | null }, assignee?: { __typename?: 'UserType', id: string, name: string, avatarUrl?: string | null } | null }> } | null };
376379

377380
export type GetOverviewDataQueryVariables = Exact<{ [key: string]: never; }>;
378381

@@ -416,6 +419,7 @@ export const GetMyTasksDocument = `
416419
title
417420
description
418421
done
422+
dueDate
419423
creationDate
420424
updateDate
421425
patient {

web/api/graphql/GetMyTasks.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ query GetMyTasks {
66
title
77
description
88
done
9+
dueDate
910
creationDate
1011
updateDate
1112
patient {

web/components/layout/Page.tsx

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
ExpansionIcon,
1212
IconButton,
1313
MarkdownInterpreter,
14+
Menu,
15+
MenuItem,
1416
SolidButton,
1517
useLocalStorage
1618
} from '@helpwave/hightide'
@@ -22,6 +24,7 @@ import { usePathname } from 'next/navigation'
2224
import { TasksLogo } from '@/components/TasksLogo'
2325
import { useRouter } from 'next/router'
2426
import { useGlobalContext } from '@/context/GlobalContext'
27+
import { logout } from '@/api/auth/authService'
2528

2629
export const StagingDisclaimerDialog = () => {
2730
const config = getConfig()
@@ -77,6 +80,7 @@ type HeaderProps = HTMLAttributes<HTMLHeadElement>
7780
export const Header = ({ ...props }: HeaderProps) => {
7881
const router = useRouter()
7982
const { user } = useGlobalContext()
83+
const translation = useTasksTranslation()
8084

8185
return (
8286
<header
@@ -97,19 +101,32 @@ export const Header = ({ ...props }: HeaderProps) => {
97101
<SettingsIcon />
98102
</IconButton>
99103
</div>
100-
<SolidButton color="neutral" className="gap-x-1.75">
101-
<div className="flex-row-1.5">
102-
{user?.name}
103-
<ExpansionIcon isExpanded={false} />
104-
</div>
105-
<Avatar
106-
fullyRounded={true}
107-
image={user?.avatarUrl ? {
108-
avatarUrl: user.avatarUrl,
109-
alt: user.name
110-
} : undefined}
111-
/>
112-
</SolidButton>
104+
<Menu
105+
trigger={(bag, ref) => (
106+
<SolidButton
107+
ref={ref}
108+
color="neutral"
109+
className="gap-x-1.75"
110+
onClick={bag.toggleOpen}
111+
>
112+
<div className="flex-row-1.5">
113+
{user?.name}
114+
<ExpansionIcon isExpanded={bag.isOpen} />
115+
</div>
116+
<Avatar
117+
fullyRounded={true}
118+
image={user?.avatarUrl ? {
119+
avatarUrl: user.avatarUrl,
120+
alt: user.name
121+
} : undefined}
122+
/>
123+
</SolidButton>
124+
)}
125+
>
126+
<MenuItem onClick={() => logout()}>
127+
{translation('logout') ?? 'Logout'}
128+
</MenuItem>
129+
</Menu>
113130
</div>
114131
</header>
115132
)

web/context/GlobalContext.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export const GlobalProvider: React.FC<{ children: React.ReactNode }> = ({ childr
5252
const myOpenTasksCount = data?.me?.tasks?.filter(t => !t.done).length ?? 0
5353
const totalPatientsCount = data?.patients?.length ?? 0
5454

55-
// Calculate patients in current location if selected
5655
const locationPatientsCount = selectedLocation
5756
? data?.patients?.filter(p => p.assignedLocation?.id === selectedLocation).length ?? 0
5857
: totalPatientsCount

web/i18n/translations.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type TasksTranslationEntries = {
3131
'login': string,
3232
'loginRequired': string,
3333
'loginRequiredDescription': string,
34+
'logout': string,
3435
'myOpenTasks': string,
3536
'myTasks': string,
3637
'name': string,
@@ -101,6 +102,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
101102
'login': `Login`,
102103
'loginRequired': `Login benötigt`,
103104
'loginRequiredDescription': `Um diese Seite benutzen zu können musst du eingeloggt sein.`,
105+
'logout': `Abmelden`,
104106
'myOpenTasks': `Meine offenen Aufgaben`,
105107
'myTasks': `Meine Aufgaben`,
106108
'name': `Name`,
@@ -216,6 +218,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
216218
'login': `Login`,
217219
'loginRequired': `Login required`,
218220
'loginRequiredDescription': `To use this site you need to be logged in.`,
221+
'logout': `Logout`,
219222
'myOpenTasks': `My Open Tasks`,
220223
'myTasks': `My tasks`,
221224
'name': `Name`,

0 commit comments

Comments
 (0)