Skip to content

Commit

Permalink
feat: group timeline events by relative dates (#10708)
Browse files Browse the repository at this point in the history
  • Loading branch information
tianrunhe authored Jan 21, 2025
1 parent bf8fc7e commit 4b973a8
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 8 deletions.
37 changes: 35 additions & 2 deletions packages/client/components/TimelineFeedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {useMemo} from 'react'
import {usePaginationFragment} from 'react-relay'
import {Link} from 'react-router-dom'
import useLoadNextOnScrollBottom from '~/hooks/useLoadNextOnScrollBottom'
import {TimelineGroup, getTimeGroup} from '~/utils/date/timelineGroups'
import {TimelineFeedListPaginationQuery} from '../__generated__/TimelineFeedListPaginationQuery.graphql'
import {TimelineFeedList_query$key} from '../__generated__/TimelineFeedList_query.graphql'
import TimelineEvent from './TimelineEvent'
Expand Down Expand Up @@ -43,6 +44,7 @@ const TimelineFeedList = (props: Props) => {
__typename
id
teamId
createdAt
organization {
id
viewerOrganizationUser {
Expand Down Expand Up @@ -106,6 +108,26 @@ const TimelineFeedList = (props: Props) => {
}
}, [timeline.edges])

const groupedFreeHistory = useMemo(() => {
const groups: TimelineGroup[] = []

freeHistory.forEach((edge) => {
const eventDate = new Date(edge.node.createdAt)
const {date: groupDate, label} = getTimeGroup(eventDate)

let group = groups.find((g) => g.date.getTime() === groupDate.getTime())
if (!group) {
group = {date: groupDate, events: [], label}
groups.push(group)
}
group.events.push(edge)
})

// Sort groups by date (newest first)
groups.sort((a, b) => b.date.getTime() - a.date.getTime())
return {groups}
}, [freeHistory])

if (freeHistory.length === 0 && !lockedHistory?.length) {
return (
<div className='text-base'>
Expand All @@ -120,8 +142,19 @@ const TimelineFeedList = (props: Props) => {

return (
<ResultScroller>
{freeHistory.map(({node: timelineEvent}) => (
<TimelineEvent key={timelineEvent.id} timelineEvent={timelineEvent} />
{groupedFreeHistory.groups.map(({date, events, label}) => (
<div key={date.toISOString()}>
<div className='my-2 flex items-center gap-4 py-4'>
<div className='h-[1px] flex-1 bg-slate-400' />
<div className='bg-slate-50 rounded-full border border-slate-200 px-3 py-1 text-sm font-medium text-slate-600'>
{label}
</div>
<div className='h-[1px] flex-1 bg-slate-400' />
</div>
{events.map(({node: timelineEvent}) => (
<TimelineEvent key={timelineEvent.id} timelineEvent={timelineEvent} />
))}
</div>
))}
{lockedHistory && (
<>
Expand Down
12 changes: 6 additions & 6 deletions packages/client/utils/date/relativeDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import humanizeDuration from 'humanize-duration'
import plural from '../plural'

const SECOND = 1000
const MIN = SECOND * 60
const HOUR = MIN * 60
const DAY = HOUR * 24
const YEAR = DAY * 365
const MONTH = DAY * 30
export const SECOND = 1000
export const MIN = SECOND * 60
export const HOUR = MIN * 60
export const DAY = HOUR * 24
export const YEAR = DAY * 365
export const MONTH = DAY * 30

interface Opts {
max?: number
Expand Down
45 changes: 45 additions & 0 deletions packages/client/utils/date/timelineGroups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {DAY, MONTH} from './relativeDate'

interface TimelineGroup {
date: Date
events: any[]
label: string
}

export interface TimelineGrouping {
date: Date
label: string
}

const getStartOfDay = (date: Date): Date => {
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
}

export const getTimeGroup = (date: Date): TimelineGrouping => {
const now = new Date()
const today = getStartOfDay(now)
const yesterday = new Date(today.getTime() - DAY)
const lastWeek = new Date(today.getTime() - 7 * DAY)
const lastMonth = new Date(today.getTime() - 30 * DAY)
const last3Months = new Date(today.getTime() - 3 * MONTH)
const last6Months = new Date(today.getTime() - 6 * MONTH)

const compareDate = getStartOfDay(date)

if (compareDate >= today) {
return {date: today, label: 'πŸŒ… Today'}
} else if (compareDate >= yesterday) {
return {date: yesterday, label: 'πŸŒ™ Yesterday'}
} else if (compareDate >= lastWeek) {
return {date: lastWeek, label: 'πŸ“… This week'}
} else if (compareDate >= lastMonth) {
return {date: lastMonth, label: 'πŸ“† This month'}
} else if (compareDate >= last3Months) {
return {date: last3Months, label: 'πŸ—“οΈ Past 3 months'}
} else if (compareDate >= last6Months) {
return {date: last6Months, label: 'πŸ“š Past 6 months'}
}
return {date: last6Months, label: 'πŸ›οΈ Ancient history'}
}

export type {TimelineGroup}

0 comments on commit 4b973a8

Please sign in to comment.