Skip to content

Commit f933a4a

Browse files
authored
Merge pull request #3993 from Northeastern-Electric-Racing/dates-fix
dates fix
2 parents ed6214a + c26fff8 commit f933a4a

63 files changed

Lines changed: 357 additions & 306 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"concat-stream": "^2.0.0",
2323
"cookie-parser": "^1.4.5",
2424
"cors": "^2.8.5",
25+
"dayjs": "^1.11.19",
2526
"decimal.js": "^10.4.3",
2627
"dotenv": "^16.0.1",
2728
"express": "^5.0.0",

src/backend/src/prisma/seed.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import ProjectsService from '../services/projects.services.js';
3131
import { Decimal } from 'decimal.js';
3232
import BillOfMaterialsService from '../services/boms.services.js';
3333
import UsersService from '../services/users.services.js';
34-
import { transformDate } from '../utils/datetime.utils.js';
34+
import { toDateString } from 'shared';
3535
import { writeFileSync, readFileSync } from 'fs';
3636
import WbsElementTemplatesService from '../services/wbs-element-templates.services.js';
3737
import RecruitmentServices from '../services/recruitment.services.js';
@@ -1137,7 +1137,7 @@ const performSeed: () => Promise<void> = async () => {
11371137
'Bodywork Concept of Design',
11381138
changeRequestProject1Id,
11391139
WorkPackageStage.Design,
1140-
weeksAgo(12).toISOString().split('T')[0],
1140+
toDateString(weeksAgo(12)),
11411141
6,
11421142
[],
11431143
[],
@@ -1183,7 +1183,7 @@ const performSeed: () => Promise<void> = async () => {
11831183
'Adhesive Shear Strength Test',
11841184
changeRequestProject1Id,
11851185
WorkPackageStage.Research,
1186-
weeksAgo(10).toISOString().split('T')[0],
1186+
toDateString(weeksAgo(10)),
11871187
5,
11881188
[],
11891189
[],
@@ -1201,7 +1201,7 @@ const performSeed: () => Promise<void> = async () => {
12011201
'Manufacture Wiring Harness',
12021202
changeRequestProject5Id,
12031203
WorkPackageStage.Manufacturing,
1204-
weeksAgo(9).toISOString().split('T')[0],
1204+
toDateString(weeksAgo(9)),
12051205
4,
12061206
[],
12071207
[],
@@ -1234,7 +1234,7 @@ const performSeed: () => Promise<void> = async () => {
12341234
'Install Wiring Harness',
12351235
changeRequestProject5Id,
12361236
WorkPackageStage.Install,
1237-
weeksAgo(5).toISOString().split('T')[0],
1237+
toDateString(weeksAgo(5)),
12381238
6,
12391239
[],
12401240
[],
@@ -1267,7 +1267,7 @@ const performSeed: () => Promise<void> = async () => {
12671267
'Design Plush',
12681268
changeRequestProject6Id,
12691269
WorkPackageStage.Design,
1270-
weeksAgo(16).toISOString().split('T')[0],
1270+
toDateString(weeksAgo(16)),
12711271
7,
12721272
[],
12731273
[],
@@ -1300,7 +1300,7 @@ const performSeed: () => Promise<void> = async () => {
13001300
'Put Plush Together',
13011301
changeRequestProject6Id,
13021302
WorkPackageStage.Manufacturing,
1303-
weeksAgo(9).toISOString().split('T')[0],
1303+
toDateString(weeksAgo(9)),
13041304
5,
13051305
[],
13061306
[],
@@ -1333,7 +1333,7 @@ const performSeed: () => Promise<void> = async () => {
13331333
'Plush Testing',
13341334
changeRequestProject6Id,
13351335
WorkPackageStage.Testing,
1336-
weeksAgo(4).toISOString().split('T')[0],
1336+
toDateString(weeksAgo(4)),
13371337
4,
13381338
[],
13391339
[],
@@ -1367,7 +1367,7 @@ const performSeed: () => Promise<void> = async () => {
13671367
'Design Laser Canon',
13681368
changeRequestProject7Id,
13691369
WorkPackageStage.Design,
1370-
weeksAgo(8).toISOString().split('T')[0],
1370+
toDateString(weeksAgo(8)),
13711371
5,
13721372
[],
13731373
[],
@@ -1400,7 +1400,7 @@ const performSeed: () => Promise<void> = async () => {
14001400
'Laser Canon Research',
14011401
changeRequestProject7Id,
14021402
WorkPackageStage.Research,
1403-
weeksAgo(3).toISOString().split('T')[0],
1403+
toDateString(weeksAgo(3)),
14041404
6,
14051405
[],
14061406
[],
@@ -1418,7 +1418,7 @@ const performSeed: () => Promise<void> = async () => {
14181418
'Laser Canon Testing',
14191419
changeRequestProject7Id,
14201420
WorkPackageStage.Testing,
1421-
weeksFromNow(3).toISOString().split('T')[0],
1421+
toDateString(weeksFromNow(3)),
14221422
4,
14231423
[project3WP1.wbsNum, project3WP2.wbsNum],
14241424
[],
@@ -1437,7 +1437,7 @@ const performSeed: () => Promise<void> = async () => {
14371437
'Stadium Research',
14381438
changeRequestProject8Id,
14391439
WorkPackageStage.Research,
1440-
weeksAgo(14).toISOString().split('T')[0],
1440+
toDateString(weeksAgo(14)),
14411441
7,
14421442
[],
14431443
[],
@@ -1470,7 +1470,7 @@ const performSeed: () => Promise<void> = async () => {
14701470
'Stadium Install',
14711471
changeRequestProject8Id,
14721472
WorkPackageStage.Install,
1473-
weeksAgo(7).toISOString().split('T')[0],
1473+
toDateString(weeksAgo(7)),
14741474
6,
14751475
[],
14761476
[],
@@ -1488,7 +1488,7 @@ const performSeed: () => Promise<void> = async () => {
14881488
'Stadium Testing',
14891489
changeRequestProject8Id,
14901490
WorkPackageStage.Testing,
1491-
weeksAgo(1).toISOString().split('T')[0],
1491+
toDateString(weeksAgo(1)),
14921492
5,
14931493
[],
14941494
[],
@@ -2411,7 +2411,7 @@ const performSeed: () => Promise<void> = async () => {
24112411
leadId: batman.userId,
24122412
managerId: cyborg.userId,
24132413
duration: 5,
2414-
startDate: transformDate(new Date()),
2414+
startDate: toDateString(new Date()),
24152415
stage: WorkPackageStage.Design,
24162416
blockedBy: [],
24172417
descriptionBullets: [],
@@ -2425,7 +2425,7 @@ const performSeed: () => Promise<void> = async () => {
24252425
'Slim and Light Car',
24262426
newWorkPackageChangeRequest.crId,
24272427
WorkPackageStage.Design,
2428-
weeksAgo(2).toISOString().split('T')[0],
2428+
toDateString(weeksAgo(2)),
24292429
5,
24302430
[],
24312431
[],
@@ -2453,7 +2453,7 @@ const performSeed: () => Promise<void> = async () => {
24532453
leadId: batman.userId,
24542454
managerId: cyborg.userId,
24552455
duration: 5,
2456-
startDate: transformDate(new Date()),
2456+
startDate: toDateString(new Date()),
24572457
stage: WorkPackageStage.Design,
24582458
blockedBy: [],
24592459
descriptionBullets: [],

src/backend/src/routes/calendar.routes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { body, param } from 'express-validator';
33
import {
44
intMinZero,
55
isDate,
6+
isDateOnly,
67
nonEmptyString,
78
validateInputs,
89
isEventStatus,
@@ -185,7 +186,7 @@ calendarRouter.post(
185186
body('availability').isArray(),
186187
body('availability.*.availability').isArray(),
187188
intMinZero(body('availability.*.availability.*')),
188-
isDate(body('availability.*.dateSet')),
189+
isDateOnly(body('availability.*.dateSet')),
189190
validateInputs,
190191
CalendarController.markUserConfirmed
191192
);

src/backend/src/routes/change-requests.routes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ChangeRequestReason, ChangeRequestType } from 'shared';
44
import ChangeRequestsController from '../controllers/change-requests.controllers.js';
55
import {
66
intMinZero,
7+
isDateOnly,
78
nonEmptyString,
89
projectProposedChangesValidators,
910
validateInputs,
@@ -38,7 +39,7 @@ changeRequestsRouter.post(
3839
intMinZero(body('wbsNum.projectNumber')),
3940
intMinZero(body('wbsNum.workPackageNumber')),
4041
body('type').custom((value) => value === ChangeRequestType.Activation),
41-
body('startDate').custom((value) => !isNaN(Date.parse(value))),
42+
isDateOnly(body('startDate')),
4243
nonEmptyString(body('leadId')),
4344
nonEmptyString(body('managerId')),
4445
body('confirmDetails').isBoolean(),

src/backend/src/routes/recruitment.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import express from 'express';
2-
import { isDate, nonEmptyString, validateInputs } from '../utils/validation.utils.js';
2+
import { isDateOnly, nonEmptyString, validateInputs } from '../utils/validation.utils.js';
33
import { body } from 'express-validator';
44
import RecruitmentController from '../controllers/recruitment.controllers.js';
55

@@ -12,7 +12,7 @@ recruitmentRouter.post(
1212
'/milestone/create',
1313
nonEmptyString(body('name')),
1414
nonEmptyString(body('description')),
15-
isDate(body('dateOfEvent')),
15+
isDateOnly(body('dateOfEvent')),
1616
validateInputs,
1717
RecruitmentController.createMilestone
1818
);
@@ -21,7 +21,7 @@ recruitmentRouter.post(
2121
'/milestone/:milestoneId/edit',
2222
nonEmptyString(body('name')),
2323
nonEmptyString(body('description')),
24-
isDate(body('dateOfEvent')),
24+
isDateOnly(body('dateOfEvent')),
2525
validateInputs,
2626
RecruitmentController.editMilestone
2727
);

src/backend/src/routes/reimbursement-requests.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { body } from 'express-validator';
88
import {
99
intMinZero,
1010
isDate,
11-
isOptionalDate,
11+
isOptionalDateOnly,
1212
nonEmptyString,
1313
validateInputs,
1414
validateReimbursementProducts
@@ -115,7 +115,7 @@ reimbursementRequestsRouter.post('/:vendorId/vendors/delete', ReimbursementReque
115115

116116
reimbursementRequestsRouter.post(
117117
'/create',
118-
isOptionalDate(body('dateOfExpense')),
118+
isOptionalDateOnly(body('dateOfExpense')),
119119
nonEmptyString(body('vendorId')),
120120
nonEmptyString(body('indexCodeId')),
121121
nonEmptyString(body('accountCodeId')),
@@ -131,7 +131,7 @@ reimbursementRequestsRouter.get('/:requestId', ReimbursementRequestController.ge
131131

132132
reimbursementRequestsRouter.post(
133133
'/:requestId/edit',
134-
isOptionalDate(body('dateOfExpense')),
134+
isOptionalDateOnly(body('dateOfExpense')),
135135
nonEmptyString(body('vendorId')),
136136
nonEmptyString(body('indexCodeId')),
137137
body('receiptPictures').isArray(),

src/backend/src/routes/tasks.routes.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import express from 'express';
22
import { body } from 'express-validator';
33
import TasksController from '../controllers/tasks.controllers.js';
4-
import { nonEmptyString, isTaskPriority, isTaskStatus, validateInputs, isOptionalDate } from '../utils/validation.utils.js';
4+
import {
5+
nonEmptyString,
6+
isTaskPriority,
7+
isTaskStatus,
8+
validateInputs,
9+
isOptionalDateOnly
10+
} from '../utils/validation.utils.js';
511
import { isDate } from '../utils/validation.utils.js';
612

713
const tasksRouter = express.Router();
@@ -21,8 +27,8 @@ tasksRouter.post(
2127
tasksRouter.post(
2228
'/:wbsNum',
2329
nonEmptyString(body('title')),
24-
isOptionalDate(body('deadline')),
25-
isOptionalDate(body('startDate')),
30+
isOptionalDateOnly(body('deadline')),
31+
isOptionalDateOnly(body('startDate')),
2632
body('notes').isString(),
2733
isTaskPriority(body('priority')),
2834
isTaskStatus(body('status')),
@@ -36,8 +42,8 @@ tasksRouter.post(
3642
'/:taskId/edit',
3743
nonEmptyString(body('title')),
3844
nonEmptyString(body('notes')),
39-
isOptionalDate(body('deadline')),
40-
isOptionalDate(body('startDate')),
45+
isOptionalDateOnly(body('deadline')),
46+
isOptionalDateOnly(body('startDate')),
4147
isTaskPriority(body('priority')),
4248
TasksController.editTask
4349
);

src/backend/src/routes/users.routes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Theme } from '@prisma/client';
22
import express from 'express';
33
import { body } from 'express-validator';
44
import UsersController from '../controllers/users.controllers.js';
5-
import { isRole, nonEmptyString, intMinZero, validateInputs, isDate } from '../utils/validation.utils.js';
5+
import { isRole, nonEmptyString, intMinZero, validateInputs, isDateOnly } from '../utils/validation.utils.js';
66

77
const userRouter = express.Router();
88

@@ -50,7 +50,7 @@ userRouter.post(
5050
body('availability').isArray(),
5151
body('availability.*.availability').isArray(),
5252
intMinZero(body('availability.*.availability.*')),
53-
isDate(body('availability.*.dateSet')),
53+
isDateOnly(body('availability.*.dateSet')),
5454
validateInputs,
5555
UsersController.setUserScheduleSettings
5656
);

src/backend/src/routes/work-packages.routes.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
blockedByValidators,
66
descriptionBulletsValidators,
77
intMinZero,
8-
isDate,
8+
isDateOnly,
99
isWorkPackageStageOrNone,
1010
nonEmptyString,
1111
validateInputs
@@ -35,7 +35,7 @@ workPackagesRouter.post(
3535
nonEmptyString(body('crId').optional()),
3636
nonEmptyString(body('name')),
3737
isWorkPackageStageOrNone(body('stage')),
38-
isDate(body('startDate')),
38+
isDateOnly(body('startDate')),
3939
intMinZero(body('duration')),
4040
intMinZero(body('projectWbsNum.carNumber')),
4141
intMinZero(body('projectWbsNum.projectNumber')),
@@ -51,7 +51,7 @@ workPackagesRouter.post(
5151
nonEmptyString(body('workPackageId')),
5252
nonEmptyString(body('crId')),
5353
nonEmptyString(body('name')),
54-
isDate(body('startDate')),
54+
isDateOnly(body('startDate')),
5555
intMinZero(body('duration')),
5656
isWorkPackageStageOrNone(body('stage')),
5757
...blockedByValidators,
@@ -65,7 +65,7 @@ workPackagesRouter.delete('/:wbsNum/delete', WorkPackagesController.deleteWorkPa
6565
workPackagesRouter.get('/:wbsNum/blocking', WorkPackagesController.getBlockingWorkPackages);
6666
workPackagesRouter.post(
6767
'/slack-upcoming-deadlines',
68-
isDate(body('deadline')),
68+
isDateOnly(body('deadline')),
6969
validateInputs,
7070
WorkPackagesController.slackMessageUpcomingDeadlines
7171
);

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
EventWithAttendees
88
} from '../utils/notifications.utils.js';
99
import { sendMessage } from '../integrations/slack.js';
10-
import { daysBetween, meetingStartTimePipeNumbers, startOfDay, wbsPipe } from 'shared';
10+
import { daysBetween, startOfDay, wbsPipe, formatTimeForSlack } from 'shared';
1111
import { buildDueString, sendThreadResponse } from '../utils/slack.utils.js';
1212
import WorkPackagesService from './work-packages.services.js';
1313
import { addWeeksToDate } from 'shared';
@@ -196,15 +196,15 @@ export default class NotificationsService {
196196
// Get work package names for this event
197197
const workPackageNames = event.workPackages.map((wp) => wp.wbsElement.name).join(', ');
198198

199-
// Extract meeting times from scheduled slots
200-
const meetingTimes = event.scheduledTimes
201-
.map((slot) => (slot.startTime ? new Date(slot.startTime).getHours() : null))
202-
.filter((hour): hour is number => hour !== null)
203-
.sort((a, b) => a - b);
199+
// Get the earliest scheduled start time for display
200+
const [earliestSlot] = event.scheduledTimes
201+
.filter((slot) => slot.startTime)
202+
.sort((a, b) => new Date(a.startTime!).getTime() - new Date(b.startTime!).getTime());
203+
const timeDisplay = earliestSlot ? formatTimeForSlack(new Date(earliestSlot.startTime!)) : 'TBD';
204204

205205
return (
206206
`${usersToSlackPings(event.attendees ?? [])} ${event.title} (${workPackageNames}) ` +
207-
`will be having an event today at ${meetingStartTimePipeNumbers(meetingTimes)} EST! ` +
207+
`will be having an event today at ${timeDisplay} ET! ` +
208208
zoomLink +
209209
questionDocLink
210210
);

0 commit comments

Comments
 (0)