Skip to content

Commit 7a7b5df

Browse files
Merge pull request #86 from thecodingtree/36-date-calculation-for-notes-is-incorrect
Refactored Notes date label
2 parents 3be8d0f + 5faacf5 commit 7a7b5df

File tree

8 files changed

+146
-88
lines changed

8 files changed

+146
-88
lines changed

app/_tests/db.test.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import mockPrisma from '@/libs/__mocks__/prisma';
66

77
import { contactCreator } from '@/server/api/creators';
88

9-
import { DeepMockProxy, mockDeep, mockReset } from 'vitest-mock-extended';
9+
import { mockDeep } from 'vitest-mock-extended';
1010

1111
// 1- mock prisma module
1212
vi.mock('@/libs/__mocks__/prisma');
@@ -36,14 +36,16 @@ describe('DB Example Tests', () => {
3636
testMock.coreEntity.create.mockResolvedValue({
3737
id: '1',
3838
type: 'PROPERTY',
39-
ownerId: '1',
39+
creatorId: '1',
4040
teamId: null,
41+
private: false,
4142
createdAt: new Date(),
4243
updatedAt: new Date(),
4344
});
4445

4546
const result = await contactCreator({
4647
db: testMock,
48+
user: { id: '1', email: 'test@example' },
4749
data: { name: 'test', surName: 'testerson', email: 'test@example' },
4850
});
4951

app/_tests/utils.test.tsx

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { beforeEach, describe, expect, it } from 'vitest';
2+
import { format } from 'date-fns';
3+
4+
import {
5+
DAY_FORMAT,
6+
TIME_FORMAT,
7+
getNoteDateLabel,
8+
getTaskDueLabel,
9+
} from '@/components/content/utils';
10+
11+
// Test all date labels for Notes
12+
describe('getNoteDateLabel', () => {
13+
it('should return the correct date labels Notes', () => {
14+
const now = new Date();
15+
const yesterday = new Date(now);
16+
yesterday.setDate(now.getDate() - 1);
17+
const lastWeek = new Date(now);
18+
lastWeek.setDate(now.getDate() - 7);
19+
const threeWeeksAgo = new Date(now);
20+
threeWeeksAgo.setDate(now.getDate() - 21);
21+
const lastMonth = new Date(now);
22+
lastMonth.setMonth(now.getMonth() - 1);
23+
const lastYear = new Date(now);
24+
lastYear.setFullYear(now.getFullYear() - 1);
25+
26+
expect(getNoteDateLabel(now)).toBe(format(now, TIME_FORMAT));
27+
expect(getNoteDateLabel(yesterday)).toBe(
28+
'Yesterday at ' + format(yesterday, TIME_FORMAT),
29+
);
30+
expect(getNoteDateLabel(lastWeek)).toBe('Last week');
31+
expect(getNoteDateLabel(threeWeeksAgo)).toBe('3 weeks ago');
32+
expect(getNoteDateLabel(lastMonth)).toBe('1 month(s) ago');
33+
expect(getNoteDateLabel(lastYear)).toBe('1 year(s) ago');
34+
});
35+
});
36+
37+
// Test all date labels for Tasks
38+
describe('getTaskDueLabel', () => {
39+
it('should return the correct label for Tasks', () => {
40+
const now = new Date();
41+
const yesterday = new Date(now);
42+
yesterday.setDate(now.getDate() - 1);
43+
const tomorrow = new Date(now);
44+
tomorrow.setDate(now.getDate() + 1);
45+
const thisWeek = new Date(now);
46+
thisWeek.setDate(now.getDate() + 3);
47+
const nextWeek = new Date(now);
48+
nextWeek.setDate(now.getDate() + 7);
49+
50+
expect(getTaskDueLabel(now)).toBe('Today');
51+
expect(getTaskDueLabel(yesterday)).toBe('Overdue');
52+
expect(getTaskDueLabel(tomorrow)).toBe('Tomorrow');
53+
expect(getTaskDueLabel(thisWeek)).toBe(format(thisWeek, DAY_FORMAT));
54+
expect(getTaskDueLabel(nextWeek)).toBe('Next week');
55+
});
56+
});

components/content/Notes.tsx

+2-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
2-
32
import { useState } from 'react';
3+
44
import { Textarea } from '@/components/ui/textarea';
55
import { Button } from '@/components/ui/button';
66

@@ -11,47 +11,9 @@ import {
1111
CardFooter,
1212
} from '@/components/ui/card';
1313
import { getEntityIcon, getEntityLink } from '@/components/entities/utils';
14+
import { getNoteDateLabel } from './utils';
1415
import { NoteResult } from '@/server/note';
1516

16-
const getDaysSinceDate = (date: Date): number => {
17-
return Math.floor(
18-
(new Date().getTime() - new Date(date).getTime()) / 86400000,
19-
);
20-
};
21-
22-
// TODO: This is a very naive implementation of this function
23-
export const getNoteDateLabel = (date: Date): string => {
24-
const daysSinceDate = getDaysSinceDate(date);
25-
26-
if (daysSinceDate === 0) {
27-
return date.toLocaleTimeString('en-US', { timeStyle: 'short' });
28-
}
29-
30-
if (daysSinceDate === 1) {
31-
return (
32-
'Yesterday at ' + date.toLocaleTimeString('en-US', { timeStyle: 'short' })
33-
);
34-
}
35-
36-
if (daysSinceDate < 7) {
37-
return `${daysSinceDate} days ago`;
38-
}
39-
40-
if (daysSinceDate >= 7 && daysSinceDate < 14) {
41-
return 'Last week';
42-
}
43-
44-
if (daysSinceDate >= 14 && daysSinceDate < 31) {
45-
return `${Math.floor(daysSinceDate / 7)} weeks ago}`;
46-
}
47-
48-
if (daysSinceDate >= 31 && daysSinceDate < 365) {
49-
return `${Math.floor(daysSinceDate / 31)} month(s) ago`;
50-
}
51-
52-
return `${Math.floor(daysSinceDate / 365)} year(s) ago`;
53-
};
54-
5517
export function Note({
5618
date,
5719
content,

components/content/Task.tsx

+2-42
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
'use client';
22

3-
import {
4-
isToday,
5-
isTomorrow,
6-
isThisWeek,
7-
isBefore,
8-
differenceInWeeks,
9-
format,
10-
} from 'date-fns';
11-
123
import { useState } from 'react';
134
import { Textarea } from '@/components/ui/textarea';
145
import { Button } from '@/components/ui/button';
@@ -21,39 +12,8 @@ import {
2112
CardDescription,
2213
CardHeader,
2314
} from '@/components/ui/card';
24-
import { getTaskIcon, getTaskDateLabel } from '@/components/tasks/utils';
25-
26-
const getDaysUntilDate = (date: Date): number => {
27-
return Math.floor(
28-
(new Date(date).getTime() - new Date().getTime()) / 86400000,
29-
);
30-
};
31-
32-
export const getTaskDueLabel = (date: Date): string => {
33-
const now = new Date();
34-
35-
if (isBefore(date, now)) {
36-
return 'Overdue';
37-
}
38-
39-
if (isToday(date)) {
40-
return 'Today';
41-
}
42-
43-
if (isTomorrow(date)) {
44-
return 'Tomorrow';
45-
}
46-
47-
if (differenceInWeeks(date, now) === 0) {
48-
return `${format(date, 'EEEE')}`;
49-
}
50-
51-
if (differenceInWeeks(date, now) === 1) {
52-
return 'Next week';
53-
}
54-
55-
return `${differenceInWeeks(date, now)} weeks from now`;
56-
};
15+
import { getTaskIcon } from '@/components/tasks/utils';
16+
import { getTaskDueLabel } from '@/components/content/utils';
5717

5818
export default function Task({
5919
type,

components/content/utils.ts

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {
2+
isPast,
3+
isToday,
4+
isTomorrow,
5+
isYesterday,
6+
differenceInCalendarDays,
7+
differenceInCalendarWeeks,
8+
differenceInCalendarMonths,
9+
differenceInCalendarYears,
10+
format,
11+
} from 'date-fns';
12+
13+
// etc: 12:00 PM
14+
export const TIME_FORMAT = 'h:mm a';
15+
export const DAY_FORMAT = 'EEEE';
16+
17+
export const getNoteDateLabel = (date: Date): string => {
18+
const now = new Date();
19+
const daysSinceDate = differenceInCalendarDays(now, date);
20+
const weeksSinceDate = differenceInCalendarWeeks(now, date);
21+
const monthsSinceDate = differenceInCalendarMonths(now, date);
22+
const yearsSinceDate = differenceInCalendarYears(now, date);
23+
24+
if (isToday(date)) {
25+
return format(date, TIME_FORMAT);
26+
}
27+
28+
if (isYesterday(date)) {
29+
return `Yesterday at ${format(date, TIME_FORMAT)}`;
30+
}
31+
32+
if (weeksSinceDate === 0) {
33+
return `${daysSinceDate} days ago`;
34+
}
35+
36+
if (weeksSinceDate === 1) {
37+
return 'Last week';
38+
}
39+
40+
if (weeksSinceDate > 1 && weeksSinceDate < 4) {
41+
return `${weeksSinceDate} weeks ago`;
42+
}
43+
44+
if (monthsSinceDate >= 1 && monthsSinceDate < 12) {
45+
return `${monthsSinceDate} month(s) ago`;
46+
}
47+
48+
return `${yearsSinceDate} year(s) ago`;
49+
};
50+
51+
export const getTaskDueLabel = (date: Date): string => {
52+
const now = new Date();
53+
54+
if (isPast(date)) {
55+
return 'Overdue';
56+
}
57+
58+
if (isToday(date)) {
59+
return 'Today';
60+
}
61+
62+
if (isTomorrow(date)) {
63+
return 'Tomorrow';
64+
}
65+
66+
if (differenceInCalendarWeeks(date, now) === 0) {
67+
return `${format(date, DAY_FORMAT)}`;
68+
}
69+
70+
if (differenceInCalendarWeeks(date, now) === 1) {
71+
return 'Next week';
72+
}
73+
74+
return `${differenceInCalendarWeeks(date, now)} weeks from now`;
75+
};

components/entities/EntityNotesTable.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
TableCell,
1212
} from '@/components/ui/table';
1313

14-
import { AddNote, getNoteDateLabel } from '@/components/content/Notes';
14+
import { AddNote } from '@/components/content/Notes';
15+
import { getNoteDateLabel } from '@/components/content/utils';
1516

1617
import { NoteType } from '@/server/sharedTypes';
1718

server/api/creators.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const contactCreator = async ({
5252
},
5353
} as Prisma.CoreEntityCreateInput;
5454

55-
const result = await createCoreEntity({ db, data: contactCreateInput });
55+
const result = await createCoreEntity({ db, user, data: contactCreateInput });
5656

5757
return contactDataMapper(result, user);
5858
};

server/coreEntities.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Prisma, PrismaClient, CoreEntityType } from '@prisma/client';
22

3-
import { EntityFilterType } from '@/server/sharedTypes';
3+
import { EntityFilterType, SessionUser } from '@/server/sharedTypes';
44
import { getTeamUser } from './team';
55

66
const coreEntityInclude = Prisma.validator<Prisma.CoreEntityInclude>()({
@@ -132,11 +132,13 @@ export const getCoreEntity = ({
132132
export const createCoreEntity = async ({
133133
db,
134134
data,
135+
user,
135136
}: {
136137
db: PrismaClient;
137138
data: Prisma.CoreEntityCreateInput;
139+
user?: SessionUser;
138140
}) => {
139-
const teamUser = await getTeamUser({ db });
141+
const teamUser = await getTeamUser({ db, user: user?.id });
140142

141143
return db.coreEntity.create({
142144
data: {

0 commit comments

Comments
 (0)