···11/// <reference types="next" />
22-/// <reference types="next/navigation-types/compat/navigation" />
22+/// <reference types="next/image-types/global" />
3344// NOTE: This file should not be edited
55-// see https://nextjs.org/docs/basic-features/typescript for more information.55+// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
+3-6
app/src/app/feed/page.tsx
···33import { useState, useEffect } from 'react';
44import Link from 'next/link';
55import styles from './feed.module.css';
66+import { formatRelativeTime } from '@/lib/time-utils';
6778// Types for our feed entries
89interface FlushingEntry {
···6162 }
6263 };
63646464- // Format date to a readable string
6565- const formatDate = (dateString: string) => {
6666- const date = new Date(dateString);
6767- return date.toLocaleString();
6868- };
6565+ // No longer needed - using formatRelativeTime from time-utils
69667067 return (
7168 <div className={styles.container}>
···116113 @{entry.authorHandle}
117114 </a>
118115 <span className={styles.timestamp}>
119119- {formatDate(entry.createdAt)}
116116+ {formatRelativeTime(entry.createdAt)}
120117 </span>
121118 </div>
122119 <div className={styles.content}>
+1-1
app/src/app/page.tsx
···55import { useRouter } from 'next/navigation';
66import styles from './page.module.css';
77import { useAuth } from '@/lib/auth-context';
88-import { containsBannedWords, sanitizeText } from '@/lib/content-filter';
88+import { containsBannedWords, sanitizeText, formatRelativeTime } from '@/lib/content-filter';
991010// Types for feed entries
1111interface FlushingEntry {
+2-1
app/src/app/profile/[handle]/page.tsx
···55import { useParams } from 'next/navigation';
66import styles from './profile.module.css';
77import { sanitizeText } from '@/lib/content-filter';
88+import { formatRelativeTime } from '@/lib/time-utils';
89910// Types for feed entries
1011interface FlushingEntry {
···229230 </span>
230231 </div>
231232 <span className={styles.timestamp}>
232232- {new Date(entry.created_at).toLocaleString()}
233233+ {formatRelativeTime(entry.created_at)}
233234 </span>
234235 </div>
235236 </div>
+53
app/src/lib/content-filter.ts
···145145 if (!text) return false;
146146147147 return EXPLICIT_SLUR_REGEXES.some(regex => regex.test(text));
148148+}
149149+150150+/**
151151+ * Formats a date into a relative time string (e.g., "5 minutes ago", "2 days ago")
152152+ * @param dateString The date string to format
153153+ * @returns A relative time string
154154+ */
155155+export function formatRelativeTime(dateString: string): string {
156156+ const date = new Date(dateString);
157157+ const now = new Date();
158158+ const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
159159+160160+ // Less than a minute
161161+ if (diffInSeconds < 60) {
162162+ return 'just now';
163163+ }
164164+165165+ // Less than an hour
166166+ if (diffInSeconds < 3600) {
167167+ const minutes = Math.floor(diffInSeconds / 60);
168168+ return `${minutes} ${minutes === 1 ? 'minute' : 'minutes'} ago`;
169169+ }
170170+171171+ // Less than a day
172172+ if (diffInSeconds < 86400) {
173173+ const hours = Math.floor(diffInSeconds / 3600);
174174+ return `${hours} ${hours === 1 ? 'hour' : 'hours'} ago`;
175175+ }
176176+177177+ // Less than a week
178178+ if (diffInSeconds < 604800) {
179179+ const days = Math.floor(diffInSeconds / 86400);
180180+ if (days === 1) {
181181+ return 'yesterday';
182182+ }
183183+ return `${days} days ago`;
184184+ }
185185+186186+ // Less than a month
187187+ if (diffInSeconds < 2592000) {
188188+ const weeks = Math.floor(diffInSeconds / 604800);
189189+ return `${weeks} ${weeks === 1 ? 'week' : 'weeks'} ago`;
190190+ }
191191+192192+ // Less than a year
193193+ if (diffInSeconds < 31536000) {
194194+ const months = Math.floor(diffInSeconds / 2592000);
195195+ return `${months} ${months === 1 ? 'month' : 'months'} ago`;
196196+ }
197197+198198+ // More than a year
199199+ const years = Math.floor(diffInSeconds / 31536000);
200200+ return `${years} ${years === 1 ? 'year' : 'years'} ago`;
148201}
+37
app/src/lib/time-utils.ts
···11+export function formatRelativeTime(dateString: string): string {
22+ const date = new Date(dateString);
33+ const now = new Date();
44+ const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
55+66+ // Less than a minute
77+ if (diffInSeconds < 60) {
88+ return 'just now';
99+ }
1010+1111+ // Minutes
1212+ const minutes = Math.floor(diffInSeconds / 60);
1313+ if (minutes < 60) {
1414+ return `${minutes}m ago`;
1515+ }
1616+1717+ // Hours
1818+ const hours = Math.floor(minutes / 60);
1919+ if (hours < 24) {
2020+ return `${hours}h ago`;
2121+ }
2222+2323+ // Days
2424+ const days = Math.floor(hours / 24);
2525+ if (days < 7) {
2626+ return `${days}d ago`;
2727+ }
2828+2929+ // Weeks
3030+ const weeks = Math.floor(days / 7);
3131+ if (weeks < 5) {
3232+ return `${weeks}w ago`;
3333+ }
3434+3535+ // Fallback to formatted date for older posts
3636+ return date.toLocaleDateString();
3737+}