mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Clean up useTimeAgo

+278 -75
+136 -25
src/lib/hooks/__tests__/useTimeAgo.test.ts
··· 1 1 import {describe, expect, it} from '@jest/globals' 2 - import {MessageDescriptor} from '@lingui/core' 3 2 import {addDays, subDays, subHours, subMinutes, subSeconds} from 'date-fns' 4 3 5 4 import {dateDiff} from '../useTimeAgo' 6 - 7 - const lingui: any = (obj: MessageDescriptor) => obj.message 8 5 9 6 const base = new Date('2024-06-17T00:00:00Z') 10 7 11 8 describe('dateDiff', () => { 12 9 it(`works with numbers`, () => { 13 - expect(dateDiff(subDays(base, 3), Number(base), {lingui})).toEqual('3d') 10 + const earlier = subDays(base, 3) 11 + expect(dateDiff(earlier, Number(base))).toEqual({ 12 + value: 3, 13 + unit: 'day', 14 + earlier, 15 + later: base, 16 + }) 14 17 }) 15 18 it(`works with strings`, () => { 16 - expect(dateDiff(subDays(base, 3), base.toString(), {lingui})).toEqual('3d') 19 + const earlier = subDays(base, 3) 20 + expect(dateDiff(earlier, base.toString())).toEqual({ 21 + value: 3, 22 + unit: 'day', 23 + earlier, 24 + later: base, 25 + }) 17 26 }) 18 27 it(`works with dates`, () => { 19 - expect(dateDiff(subDays(base, 3), base, {lingui})).toEqual('3d') 28 + const earlier = subDays(base, 3) 29 + expect(dateDiff(earlier, base)).toEqual({ 30 + value: 3, 31 + unit: 'day', 32 + earlier, 33 + later: base, 34 + }) 20 35 }) 21 36 22 37 it(`equal values return now`, () => { 23 - expect(dateDiff(base, base, {lingui})).toEqual('now') 38 + expect(dateDiff(base, base)).toEqual({ 39 + value: 0, 40 + unit: 'now', 41 + earlier: base, 42 + later: base, 43 + }) 24 44 }) 25 45 it(`future dates return now`, () => { 26 - expect(dateDiff(addDays(base, 3), base, {lingui})).toEqual('now') 46 + const earlier = addDays(base, 3) 47 + expect(dateDiff(earlier, base)).toEqual({ 48 + value: 0, 49 + unit: 'now', 50 + earlier, 51 + later: base, 52 + }) 27 53 }) 28 54 29 55 it(`values < 5 seconds ago return now`, () => { 30 56 const then = subSeconds(base, 4) 31 - expect(dateDiff(then, base, {lingui})).toEqual('now') 57 + expect(dateDiff(then, base)).toEqual({ 58 + value: 0, 59 + unit: 'now', 60 + earlier: then, 61 + later: base, 62 + }) 32 63 }) 33 64 it(`values >= 5 seconds ago return seconds`, () => { 34 65 const then = subSeconds(base, 5) 35 - expect(dateDiff(then, base, {lingui})).toEqual('5s') 66 + expect(dateDiff(then, base)).toEqual({ 67 + value: 5, 68 + unit: 'second', 69 + earlier: then, 70 + later: base, 71 + }) 36 72 }) 37 73 38 74 it(`values < 1 min return seconds`, () => { 39 75 const then = subSeconds(base, 59) 40 - expect(dateDiff(then, base, {lingui})).toEqual('59s') 76 + expect(dateDiff(then, base)).toEqual({ 77 + value: 59, 78 + unit: 'second', 79 + earlier: then, 80 + later: base, 81 + }) 41 82 }) 42 83 it(`values >= 1 min return minutes`, () => { 43 84 const then = subSeconds(base, 60) 44 - expect(dateDiff(then, base, {lingui})).toEqual('1m') 85 + expect(dateDiff(then, base)).toEqual({ 86 + value: 1, 87 + unit: 'minute', 88 + earlier: then, 89 + later: base, 90 + }) 45 91 }) 46 92 it(`minutes round down`, () => { 47 93 const then = subSeconds(base, 119) 48 - expect(dateDiff(then, base, {lingui})).toEqual('1m') 94 + expect(dateDiff(then, base)).toEqual({ 95 + value: 1, 96 + unit: 'minute', 97 + earlier: then, 98 + later: base, 99 + }) 49 100 }) 50 101 51 102 it(`values < 1 hour return minutes`, () => { 52 103 const then = subMinutes(base, 59) 53 - expect(dateDiff(then, base, {lingui})).toEqual('59m') 104 + expect(dateDiff(then, base)).toEqual({ 105 + value: 59, 106 + unit: 'minute', 107 + earlier: then, 108 + later: base, 109 + }) 54 110 }) 55 111 it(`values >= 1 hour return hours`, () => { 56 112 const then = subMinutes(base, 60) 57 - expect(dateDiff(then, base, {lingui})).toEqual('1h') 113 + expect(dateDiff(then, base)).toEqual({ 114 + value: 1, 115 + unit: 'hour', 116 + earlier: then, 117 + later: base, 118 + }) 58 119 }) 59 120 it(`hours round down`, () => { 60 121 const then = subMinutes(base, 119) 61 - expect(dateDiff(then, base, {lingui})).toEqual('1h') 122 + expect(dateDiff(then, base)).toEqual({ 123 + value: 1, 124 + unit: 'hour', 125 + earlier: then, 126 + later: base, 127 + }) 62 128 }) 63 129 64 130 it(`values < 1 day return hours`, () => { 65 131 const then = subHours(base, 23) 66 - expect(dateDiff(then, base, {lingui})).toEqual('23h') 132 + expect(dateDiff(then, base)).toEqual({ 133 + value: 23, 134 + unit: 'hour', 135 + earlier: then, 136 + later: base, 137 + }) 67 138 }) 68 139 it(`values >= 1 day return days`, () => { 69 140 const then = subHours(base, 24) 70 - expect(dateDiff(then, base, {lingui})).toEqual('1d') 141 + expect(dateDiff(then, base)).toEqual({ 142 + value: 1, 143 + unit: 'day', 144 + earlier: then, 145 + later: base, 146 + }) 71 147 }) 72 148 it(`days round down`, () => { 73 149 const then = subHours(base, 47) 74 - expect(dateDiff(then, base, {lingui})).toEqual('1d') 150 + expect(dateDiff(then, base)).toEqual({ 151 + value: 1, 152 + unit: 'day', 153 + earlier: then, 154 + later: base, 155 + }) 75 156 }) 76 157 77 158 it(`values < 30 days return days`, () => { 78 159 const then = subDays(base, 29) 79 - expect(dateDiff(then, base, {lingui})).toEqual('29d') 160 + expect(dateDiff(then, base)).toEqual({ 161 + value: 29, 162 + unit: 'day', 163 + earlier: then, 164 + later: base, 165 + }) 80 166 }) 81 167 it(`values >= 30 days return months`, () => { 82 168 const then = subDays(base, 30) 83 - expect(dateDiff(then, base, {lingui})).toEqual('1mo') 169 + expect(dateDiff(then, base)).toEqual({ 170 + value: 1, 171 + unit: 'month', 172 + earlier: then, 173 + later: base, 174 + }) 84 175 }) 85 176 it(`months round down`, () => { 86 177 const then = subDays(base, 59) 87 - expect(dateDiff(then, base, {lingui})).toEqual('1mo') 178 + expect(dateDiff(then, base)).toEqual({ 179 + value: 1, 180 + unit: 'month', 181 + earlier: then, 182 + later: base, 183 + }) 88 184 }) 89 185 it(`values are rounded by increments of 30`, () => { 90 186 const then = subDays(base, 61) 91 - expect(dateDiff(then, base, {lingui})).toEqual('2mo') 187 + expect(dateDiff(then, base)).toEqual({ 188 + value: 2, 189 + unit: 'month', 190 + earlier: then, 191 + later: base, 192 + }) 92 193 }) 93 194 94 195 it(`values < 360 days return months`, () => { 95 196 const then = subDays(base, 359) 96 - expect(dateDiff(then, base, {lingui})).toEqual('11mo') 197 + expect(dateDiff(then, base)).toEqual({ 198 + value: 11, 199 + unit: 'month', 200 + earlier: then, 201 + later: base, 202 + }) 97 203 }) 98 204 it(`values >= 360 days return the earlier value`, () => { 99 205 const then = subDays(base, 360) 100 - expect(dateDiff(then, base, {lingui})).toEqual(then.toLocaleDateString()) 206 + expect(dateDiff(then, base)).toEqual({ 207 + value: 12, 208 + unit: 'month', 209 + earlier: then, 210 + later: base, 211 + }) 101 212 }) 102 213 })
+142 -50
src/lib/hooks/useTimeAgo.ts
··· 1 1 import {useCallback} from 'react' 2 - import {msg, plural} from '@lingui/macro' 3 - import {I18nContext, useLingui} from '@lingui/react' 2 + import {I18n} from '@lingui/core' 3 + import {defineMessage, msg, plural} from '@lingui/macro' 4 + import {useLingui} from '@lingui/react' 4 5 import {differenceInSeconds} from 'date-fns' 5 6 6 - export type TimeAgoOptions = { 7 - lingui: I18nContext['_'] 8 - format?: 'long' | 'short' 7 + export type DateDiffFormat = 'long' | 'short' 8 + 9 + type DateDiff = { 10 + value: number 11 + unit: 'now' | 'second' | 'minute' | 'hour' | 'day' | 'month' 12 + earlier: Date 13 + later: Date 9 14 } 10 15 16 + const NOW = 5 17 + const MINUTE = 60 18 + const HOUR = MINUTE * 60 19 + const DAY = HOUR * 24 20 + const MONTH_30 = DAY * 30 21 + 11 22 export function useGetTimeAgo() { 12 - const {_} = useLingui() 23 + const {i18n} = useLingui() 13 24 return useCallback( 14 25 ( 15 26 earlier: number | string | Date, 16 27 later: number | string | Date, 17 - options?: Omit<TimeAgoOptions, 'lingui'>, 28 + options?: {format: DateDiffFormat}, 18 29 ) => { 19 - return dateDiff(earlier, later, {lingui: _, format: options?.format}) 30 + const diff = dateDiff(earlier, later) 31 + return formatDateDiff({diff, i18n, format: options?.format}) 20 32 }, 21 - [_], 33 + [i18n], 22 34 ) 23 35 } 24 - 25 - const NOW = 5 26 - const MINUTE = 60 27 - const HOUR = MINUTE * 60 28 - const DAY = HOUR * 24 29 - const MONTH_30 = DAY * 30 30 36 31 37 /** 32 - * Returns the difference between `earlier` and `later` dates, formatted as a 33 - * natural language string. 38 + * Returns the difference between `earlier` and `later` dates, based on 39 + * opinionated rules. 34 40 * 35 41 * - All month are considered exactly 30 days. 36 42 * - Dates assume `earlier` <= `later`, and will otherwise return 'now'. 37 - * - Differences >= 360 days are returned as the "M/D/YYYY" string 38 43 * - All values round down 39 44 */ 40 45 export function dateDiff( 41 46 earlier: number | string | Date, 42 47 later: number | string | Date, 43 - options: TimeAgoOptions, 44 - ): string { 45 - const _ = options.lingui 46 - const format = options?.format || 'short' 47 - const long = format === 'long' 48 - const diffSeconds = differenceInSeconds(new Date(later), new Date(earlier)) 48 + ): DateDiff { 49 + let diff = { 50 + value: 0, 51 + unit: 'now' as DateDiff['unit'], 52 + } 53 + const e = new Date(earlier) 54 + const l = new Date(later) 55 + const diffSeconds = differenceInSeconds(l, e) 49 56 50 57 if (diffSeconds < NOW) { 51 - return _(msg`now`) 58 + diff = { 59 + value: 0, 60 + unit: 'now' as DateDiff['unit'], 61 + } 52 62 } else if (diffSeconds < MINUTE) { 53 - return `${diffSeconds}${ 54 - long ? ` ${plural(diffSeconds, {one: 'second', other: 'seconds'})}` : 's' 55 - }` 63 + diff = { 64 + value: diffSeconds, 65 + unit: 'second' as DateDiff['unit'], 66 + } 56 67 } else if (diffSeconds < HOUR) { 57 - const diff = Math.floor(diffSeconds / MINUTE) 58 - return `${diff}${ 59 - long ? ` ${plural(diff, {one: 'minute', other: 'minutes'})}` : 'm' 60 - }` 68 + const value = Math.floor(diffSeconds / MINUTE) 69 + diff = { 70 + value, 71 + unit: 'minute' as DateDiff['unit'], 72 + } 61 73 } else if (diffSeconds < DAY) { 62 - const diff = Math.floor(diffSeconds / HOUR) 63 - return `${diff}${ 64 - long ? ` ${plural(diff, {one: 'hour', other: 'hours'})}` : 'h' 65 - }` 74 + const value = Math.floor(diffSeconds / HOUR) 75 + diff = { 76 + value, 77 + unit: 'hour' as DateDiff['unit'], 78 + } 66 79 } else if (diffSeconds < MONTH_30) { 67 - const diff = Math.floor(diffSeconds / DAY) 68 - return `${diff}${ 69 - long ? ` ${plural(diff, {one: 'day', other: 'days'})}` : 'd' 70 - }` 80 + const value = Math.floor(diffSeconds / DAY) 81 + diff = { 82 + value, 83 + unit: 'day' as DateDiff['unit'], 84 + } 71 85 } else { 72 - const diff = Math.floor(diffSeconds / MONTH_30) 73 - if (diff < 12) { 74 - return `${diff}${ 75 - long ? ` ${plural(diff, {one: 'month', other: 'months'})}` : 'mo' 76 - }` 77 - } else { 78 - const str = new Date(earlier).toLocaleDateString() 86 + const value = Math.floor(diffSeconds / MONTH_30) 87 + diff = { 88 + value, 89 + unit: 'month' as DateDiff['unit'], 90 + } 91 + } 79 92 80 - if (long) { 81 - return _(msg`on ${str}`) 93 + return { 94 + ...diff, 95 + earlier: e, 96 + later: l, 97 + } 98 + } 99 + 100 + /** 101 + * Accepts a `DateDiff` and teturns the difference between `earlier` and 102 + * `later` dates, formatted as a natural language string. 103 + * 104 + * - All month are considered exactly 30 days. 105 + * - Dates assume `earlier` <= `later`, and will otherwise return 'now'. 106 + * - Differences >= 360 days are returned as the "M/D/YYYY" string 107 + * - All values round down 108 + */ 109 + export function formatDateDiff({ 110 + diff, 111 + format = 'short', 112 + i18n, 113 + }: { 114 + diff: DateDiff 115 + format?: DateDiffFormat 116 + i18n: I18n 117 + }): string { 118 + const long = format === 'long' 119 + 120 + switch (diff.unit) { 121 + case 'now': { 122 + return i18n._(msg`now`) 123 + } 124 + case 'second': { 125 + return long 126 + ? i18n._(plural(diff.value, {one: '# second', other: '# seconds'})) 127 + : i18n._( 128 + defineMessage({ 129 + message: `${diff.value}s`, 130 + comment: `How many seconds have passed, displayed in a narrow form`, 131 + }), 132 + ) 133 + } 134 + case 'minute': { 135 + return long 136 + ? i18n._(plural(diff.value, {one: '# minute', other: '# minutes'})) 137 + : i18n._( 138 + defineMessage({ 139 + message: `${diff.value}m`, 140 + comment: `How many minutes have passed, displayed in a narrow form`, 141 + }), 142 + ) 143 + } 144 + case 'hour': { 145 + return long 146 + ? i18n._(plural(diff.value, {one: '# hour', other: '# hours'})) 147 + : i18n._( 148 + defineMessage({ 149 + message: `${diff.value}h`, 150 + comment: `How many hours have passed, displayed in a narrow form`, 151 + }), 152 + ) 153 + } 154 + case 'day': { 155 + return long 156 + ? i18n._(plural(diff.value, {one: '# day', other: '# days'})) 157 + : i18n._( 158 + defineMessage({ 159 + message: `${diff.value}d`, 160 + comment: `How many days have passed, displayed in a narrow form`, 161 + }), 162 + ) 163 + } 164 + case 'month': { 165 + if (diff.value < 12) { 166 + return long 167 + ? i18n._(plural(diff.value, {one: '# month', other: '# months'})) 168 + : i18n._( 169 + defineMessage({ 170 + message: `${diff.value}mo`, 171 + comment: `How many months have passed, displayed in a narrow form`, 172 + }), 173 + ) 82 174 } 83 - return str 175 + return i18n.date(new Date(diff.earlier)) 84 176 } 85 177 } 86 178 }