Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions frontend/__tests__/e2e/pages/Home.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ test.describe('Home Page', () => {
test('should have upcoming events', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'Upcoming Events' })).toBeVisible()
await expect(page.getByRole('link', { name: 'Event 1' })).toBeVisible()
await expect(page.getByText('Feb 27,')).toBeVisible()
await expect(page.getByText('Feb 28,')).toBeVisible()
await expect(page.getByText('Feb 27 - 28, 2025')).toBeVisible()
await page.getByRole('link', { name: 'Event 1' }).click()
})
})
5 changes: 1 addition & 4 deletions frontend/__tests__/unit/pages/Home.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { mockAlgoliaData, mockGraphQLData } from '@unit/data/mockHomeData'
import { fetchAlgoliaData } from 'api/fetchAlgoliaData'
import { toast } from 'hooks/useToast'
import { Home } from 'pages'
import { formatDate } from 'utils/dateFormatter'
import { render } from 'wrappers/testUtil'

jest.mock('hooks/useToast', () => ({
Expand Down Expand Up @@ -161,9 +160,7 @@ describe('Home', () => {
expect(screen.getByText('Upcoming Events')).toBeInTheDocument()
mockGraphQLData.upcomingEvents.forEach((event) => {
expect(screen.getByText(event.name)).toBeInTheDocument()
expect(
screen.getByText(`${formatDate(event.startDate)} - ${formatDate(event.endDate)}`)
).toBeInTheDocument()
expect(screen.getByText('Feb 27 - 28, 2025')).toBeInTheDocument()
})
})
})
Expand Down
84 changes: 84 additions & 0 deletions frontend/__tests__/unit/utils/dateFormatter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { formatDate, formatDateRange } from 'utils/dateFormatter'

describe('formatDate function', () => {
beforeEach(() => {
jest.clearAllMocks()
})

test('formats ISO date string correctly', () => {
expect(formatDate('2023-09-01')).toBe('Sep 1, 2023')
})

test('formats Unix timestamp correctly', () => {
// 1630454400 is Sep 1, 2021 in Unix timestamp (seconds)
expect(formatDate(1630454400)).toBe('Sep 1, 2021')
})

test('throws error for invalid date', () => {
expect(() => formatDate('invalid-date')).toThrow('Invalid date')
})

test('handles different date formats', () => {
expect(formatDate('2023/09/01')).toBe('Sep 1, 2023')
expect(formatDate('09/01/2023')).toBe('Sep 1, 2023')
})

test('formats dates with leading zeros correctly', () => {
expect(formatDate('2023-01-05')).toBe('Jan 5, 2023')
})

test('handles different months', () => {
expect(formatDate('2023-12-25')).toBe('Dec 25, 2023')
expect(formatDate('2023-07-04')).toBe('Jul 4, 2023')
})
})

describe('formatDateRange function', () => {
beforeEach(() => {
jest.clearAllMocks()
})

test('formats date range in same month correctly', () => {
expect(formatDateRange('2023-09-01', '2023-09-04')).toBe('Sep 1 - 4, 2023')
})

test('formats date range in different months but same year correctly', () => {
expect(formatDateRange('2023-09-29', '2023-10-02')).toBe('Sep 29 - Oct 2, 2023')
})

test('formats date range in different years correctly', () => {
expect(formatDateRange('2023-12-30', '2024-01-03')).toBe('Dec 30, 2023 - Jan 3, 2024')
})

test('formats Unix timestamp date ranges correctly', () => {
// Sept 1-4, 2021
const startTimestamp = 1630454400 // Sep 1, 2021
const endTimestamp = 1630713600 // Sep 4, 2021
expect(formatDateRange(startTimestamp, endTimestamp)).toBe('Sep 1 - 4, 2021')
})

test('throws error when start date is invalid', () => {
expect(() => formatDateRange('invalid-date', '2023-09-04')).toThrow('Invalid date')
})

test('throws error when end date is invalid', () => {
expect(() => formatDateRange('2023-09-01', 'invalid-date')).toThrow('Invalid date')
})

test('handles month boundaries correctly', () => {
expect(formatDateRange('2023-09-30', '2023-10-02')).toBe('Sep 30 - Oct 2, 2023')
})

test('handles year boundaries correctly', () => {
expect(formatDateRange('2023-12-29', '2024-01-02')).toBe('Dec 29, 2023 - Jan 2, 2024')
})

test('handles single-day ranges correctly', () => {
expect(formatDateRange('2023-09-01', '2023-09-01')).toBe('Sep 1, 2023')
})

test('handles mixed input types correctly', () => {
// Sep 1, 2021 as Unix timestamp and ISO string
expect(formatDateRange(1630454400, '2021-09-04')).toBe('Sep 1 - 4, 2021')
})
})
4 changes: 2 additions & 2 deletions frontend/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ChapterTypeAlgolia } from 'types/chapter'
import { EventType } from 'types/event'
import { MainPageData } from 'types/home'
import { capitalize } from 'utils/capitalize'
import { formatDate } from 'utils/dateFormatter'
import { formatDate, formatDateRange } from 'utils/dateFormatter'
import AnimatedCounter from 'components/AnimatedCounter'
import ChapterMap from 'components/ChapterMap'
import ItemCardList from 'components/ItemCardList'
Expand Down Expand Up @@ -148,7 +148,7 @@ export default function Home() {
<FontAwesomeIcon icon={faCalendar} className="mr-2 h-4 w-4" />
<span>
{event.endDate && event.startDate != event.endDate
? `${formatDate(event.startDate)} - ${formatDate(event.endDate)}`
? formatDateRange(event.startDate, event.endDate)
: formatDate(event.startDate)}
</span>
</div>
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/utils/dateFormatter.ts
Comment thread
idityaGE marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,40 @@ export const formatDate = (input: number | string) => {
day: 'numeric',
})
}

export const formatDateRange = (startDate: number | string, endDate: number | string) => {
const start = typeof startDate === 'number' ? new Date(startDate * 1000) : new Date(startDate)
const end = typeof endDate === 'number' ? new Date(endDate * 1000) : new Date(endDate)

if (isNaN(start.getTime()) || isNaN(end.getTime())) {
throw new Error('Invalid date')
}

if (
start.getTime() === end.getTime() ||
(start.getFullYear() === end.getFullYear() &&
start.getMonth() === end.getMonth() &&
start.getDate() === end.getDate())
) {
return start.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}

// Check if dates are in the same month and year
const sameMonth = start.getMonth() === end.getMonth() && start.getFullYear() === end.getFullYear()
const sameYear = start.getFullYear() === end.getFullYear()

if (sameMonth) {
// Format as "Month Day - Day, Year" (e.g., "Sep 1 - 4, 2025")
return `${start.toLocaleDateString('en-US', { month: 'short' })} ${start.getDate()} - ${end.getDate()}, ${start.getFullYear()}`
Comment thread
idityaGE marked this conversation as resolved.
Outdated
} else if (sameYear) {
// Different months but same year (e.g., "Sep 29 - Oct 2, 2025")
return `${start.toLocaleDateString('en-US', { month: 'short' })} ${start.getDate()} - ${end.toLocaleDateString('en-US', { month: 'short' })} ${end.getDate()}, ${start.getFullYear()}`
} else {
// Different years (e.g., "Dec 30, 2025 - Jan 3, 2026")
return `${start.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })} - ${end.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`
Comment thread
idityaGE marked this conversation as resolved.
Outdated
}
}