Skip to content

Commit 179f55d

Browse files
committed
Merge branch 'develop' into multitenancy
2 parents cb41273 + f2346c4 commit 179f55d

4 files changed

Lines changed: 98 additions & 27 deletions

File tree

src/backend/src/services/notifications.services.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import {
33
TaskWithAssignees,
44
endOfDayTomorrow,
55
startOfDayTomorrow,
6+
startOfTodayEST,
7+
startOfTomorrowEST,
68
usersToSlackPings,
79
EventWithAttendees
810
} from '../utils/notifications.utils.js';
911
import { sendMessage } from '../integrations/slack.js';
10-
import { daysBetween, startOfDay, wbsPipe, formatTimeForSlack } from 'shared';
12+
import { daysBetween, wbsPipe, formatTimeForSlack } from 'shared';
1113
import { buildDueString, sendThreadResponse } from '../utils/slack.utils.js';
1214
import WorkPackagesService from './work-packages.services.js';
1315
import { addWeeksToDate } from 'shared';
@@ -30,7 +32,7 @@ export default class NotificationsService {
3032
static async sendTaskDeadlineSlackNotifications() {
3133
const endOfDay = endOfDayTomorrow();
3234

33-
if (endOfDay.getDay() === 0 || endOfDay.getDay() === 2 || endOfDay.getDay() === 4) return;
35+
if (endOfDay.getUTCDay() === 0 || endOfDay.getUTCDay() === 2 || endOfDay.getUTCDay() === 4) return;
3436

3537
const tasks = await prisma.task.findMany({
3638
where: {
@@ -81,7 +83,8 @@ export default class NotificationsService {
8183
const messageBlock = tasks
8284
.map((task) => {
8385
// prisma call earlier allows the forced unwrap (deadline is guaranteed to be a non-null value)
84-
const daysUntilDeadline = daysBetween(task.deadline!, new Date());
86+
const todayMidnightUTC = new Date(new Date().setUTCHours(0, 0, 0, 0));
87+
const daysUntilDeadline = daysBetween(task.deadline!, todayMidnightUTC);
8588

8689
return `${usersToSlackPings(task.assignees ?? [])} <https://finishlinebyner.com/projects/${wbsPipe(
8790
task.wbsElement
@@ -121,8 +124,8 @@ export default class NotificationsService {
121124
* Sends Slack notifications for all events scheduled for today whose event type has sendSlackNotifications enabled
122125
*/
123126
static async sendEventSlackNotifications() {
124-
const endOfToday = startOfDayTomorrow();
125-
const startOfToday = startOfDay(new Date());
127+
const endOfToday = startOfTomorrowEST();
128+
const startOfToday = startOfTodayEST();
126129

127130
const events = await prisma.event.findMany({
128131
where: {
@@ -231,7 +234,7 @@ export default class NotificationsService {
231234
* Sends the sponsor task slack notifications for all tasks with a notify date of today
232235
*/
233236
static async sendSponsorTaskNotifications() {
234-
const startOfToday = startOfDay(new Date());
237+
const startOfToday = new Date(new Date().setUTCHours(0, 0, 0, 0));
235238
const endOfToday = startOfDayTomorrow();
236239

237240
const sponsorTasks = await prisma.sponsor_Task.findMany({

src/backend/src/utils/notifications.utils.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ export const userToSlackPing = (user: UserWithSettings) => {
3131
* @returns the beginning of the day tomorrow (at 12am)
3232
*/
3333
export const startOfDayTomorrow = () => {
34-
return new Date(new Date().setHours(24, 0, 0, 0));
34+
const tomorrow = new Date();
35+
tomorrow.setUTCDate(tomorrow.getUTCDate() + 1);
36+
tomorrow.setUTCHours(0, 0, 0, 0);
37+
return tomorrow;
3538
};
3639

3740
/**
@@ -41,6 +44,36 @@ export const startOfDayTomorrow = () => {
4144
export const endOfDayTomorrow = () => {
4245
const startOfDay = startOfDayTomorrow();
4346
const endOfDay = new Date(startOfDay);
44-
endOfDay.setDate(startOfDay.getDate() + 1);
47+
endOfDay.setUTCDate(startOfDay.getUTCDate() + 1);
4548
return endOfDay;
4649
};
50+
51+
const EST_OFFSET_MS = 5 * 60 * 60 * 1000;
52+
53+
/**
54+
* Given a UTC Date, returns the start of that calendar day in EST (UTC-5), expressed as a UTC Date.
55+
* EST is always treated as UTC-5 (no DST adjustment).
56+
* @returns midnight EST of the given date as a UTC Date
57+
*/
58+
export const startOfDateEST = (date: Date): Date => {
59+
const dateInEST = new Date(date.getTime() - EST_OFFSET_MS);
60+
return new Date(Date.UTC(dateInEST.getUTCFullYear(), dateInEST.getUTCMonth(), dateInEST.getUTCDate(), 5, 0, 0, 0));
61+
};
62+
63+
/**
64+
* Gets the start of today in EST (UTC-5), expressed as a UTC Date.
65+
* EST is always treated as UTC-5 (no DST adjustment).
66+
* @returns midnight EST today as a UTC Date
67+
*/
68+
export const startOfTodayEST = (): Date => startOfDateEST(new Date());
69+
70+
/**
71+
* Gets the start of tomorrow in EST (UTC-5), expressed as a UTC Date.
72+
* EST is always treated as UTC-5 (no DST adjustment).
73+
* @returns midnight EST tomorrow as a UTC Date
74+
*/
75+
export const startOfTomorrowEST = (): Date => {
76+
const start = startOfTodayEST();
77+
start.setUTCDate(start.getUTCDate() + 1);
78+
return start;
79+
};

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskColumn.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,22 @@ export const TaskColumn = ({
1313
status,
1414
tasks,
1515
project,
16+
equalizedHeight,
17+
isDragging,
1618
onEditTask,
1719
onDeleteTask,
18-
onAddTask
20+
onAddTask,
21+
onHeightChange
1922
}: {
20-
status: Task['status'];
23+
status: TaskStatus;
2124
tasks: TaskWithIndex[];
2225
project: Project;
26+
equalizedHeight: number;
27+
isDragging: boolean;
2328
onEditTask: (task: Task) => void;
2429
onDeleteTask: (taskId: string) => void;
2530
onAddTask: (task: Task) => void;
31+
onHeightChange: (status: TaskStatus, height: number) => void;
2632
}) => {
2733
const { mutateAsync: createTask } = useCreateTask();
2834
const [showCreateTaskModal, setShowCreateTaskModal] = useState(false);
@@ -62,27 +68,51 @@ export const TaskColumn = ({
6268
<Box
6369
sx={{
6470
flex: 1,
71+
display: 'flex',
72+
flexDirection: 'column',
6573
paddingTop: '8px',
6674
paddingBottom: '16px',
6775
backgroundColor: theme.palette.background.paper,
6876
marginLeft: '5px',
69-
borderRadius: '5px'
77+
borderRadius: '5px',
78+
minHeight: isDragging ? `${equalizedHeight}px` : undefined
7079
}}
7180
>
7281
<Typography align="center" variant="h5">
7382
{statusNames[status]}
7483
</Typography>
84+
<NERButton
85+
sx={{
86+
marginTop: '5px',
87+
backgroundColor: theme.palette.secondary.contrastText,
88+
width: 'calc(100% - 10px)',
89+
marginX: '5px'
90+
}}
91+
onClick={() => setShowCreateTaskModal(true)}
92+
>
93+
+ Add A Task
94+
</NERButton>
7595
<Droppable droppableId={status}>
7696
{(droppableProvided, snapshot) => (
7797
<Box
78-
ref={droppableProvided.innerRef}
98+
ref={(droppableBox: HTMLElement | null) => {
99+
droppableProvided.innerRef(droppableBox); // give dnd lib access to dom node
100+
if (!droppableBox) return;
101+
102+
const observer = new ResizeObserver(() => {
103+
onHeightChange(status, droppableBox.scrollHeight);
104+
});
105+
observer.observe(droppableBox);
106+
return () => observer.disconnect();
107+
}}
79108
{...droppableProvided.droppableProps}
80109
className={snapshot.isDraggingOver ? ' isDraggingOver' : ''}
81110
sx={{
82111
display: 'flex',
83112
flexDirection: 'column',
84113
borderRadius: 5,
85114
padding: '5px',
115+
flex: 1,
86116
'&.isDraggingOver': {
87117
bgcolor: '#dadadf'
88118
}
@@ -102,17 +132,6 @@ export const TaskColumn = ({
102132
</Box>
103133
)}
104134
</Droppable>
105-
<NERButton
106-
sx={{
107-
marginTop: '5px',
108-
backgroundColor: theme.palette.secondary.contrastText,
109-
width: 'calc(100% - 10px)',
110-
marginX: '5px'
111-
}}
112-
onClick={() => setShowCreateTaskModal(true)}
113-
>
114-
+ Add A Task
115-
</NERButton>
116135
</Box>
117136
</>
118137
);

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskListContent.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd';
1+
import { DragDropContext, OnDragEndResponder, OnDragStartResponder } from '@hello-pangea/dnd';
22
import { Box } from '@mui/material';
3-
import { useState } from 'react';
4-
import { Project, Task, TaskWithIndex } from 'shared';
3+
import { useCallback, useState } from 'react';
4+
import { Project, Task, TaskStatus, TaskWithIndex } from 'shared';
55
import { getTasksByStatus, statuses, TasksByStatus } from '.';
66
import { useSetTaskStatus } from '../../../../../hooks/tasks.hooks';
77
import { useToast } from '../../../../../hooks/toasts.hooks';
@@ -19,6 +19,14 @@ export const TaskListContent = ({ project }: TaskListProps) => {
1919

2020
const toast = useToast();
2121

22+
const [isDragging, setIsDragging] = useState(false);
23+
const [columnHeights, setColumnHeights] = useState<Partial<Record<TaskStatus, number>>>({});
24+
const equalizedHeight = Math.max(...(Object.values(columnHeights) as number[]));
25+
26+
const onHeightChange = useCallback((status: TaskStatus, height: number) => {
27+
setColumnHeights((prev) => ({ ...prev, [status]: height }));
28+
}, []);
29+
2230
const onDeleteTask = (taskId: string) => {
2331
setTasksByStatus((prev) => {
2432
const newTasksByStatus = { ...prev };
@@ -54,7 +62,12 @@ export const TaskListContent = ({ project }: TaskListProps) => {
5462
}));
5563
};
5664

65+
const onDragStart: OnDragStartResponder = () => {
66+
setIsDragging(true);
67+
};
68+
5769
const onDragEnd: OnDragEndResponder = async (result) => {
70+
setIsDragging(false);
5871
const { destination, source } = result;
5972

6073
if (!destination) {
@@ -110,17 +123,20 @@ export const TaskListContent = ({ project }: TaskListProps) => {
110123
};
111124

112125
return (
113-
<DragDropContext onDragEnd={onDragEnd}>
126+
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
114127
<Box display="flex">
115128
{statuses.map((status) => (
116129
<TaskColumn
117130
onAddTask={onAddTask}
118131
onDeleteTask={onDeleteTask}
119132
onEditTask={onEditTask}
133+
onHeightChange={onHeightChange}
120134
status={status}
121135
tasks={tasksByStatus[status]}
122136
key={status}
123137
project={project}
138+
equalizedHeight={equalizedHeight}
139+
isDragging={isDragging}
124140
/>
125141
))}
126142
</Box>

0 commit comments

Comments
 (0)