Skip to content

Commit 8c12e16

Browse files
committed
refactor: extract hackathon countdown resolver
1 parent 6e4f39e commit 8c12e16

1 file changed

Lines changed: 64 additions & 3 deletions

File tree

components/Activity/Hackathon/utility.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TableCellValue, TableFormView } from 'mobx-lark';
1+
import { TableCellUser, TableCellValue, TableFormView } from 'mobx-lark';
22
import { formatDate } from 'web-utility';
33

44
import type { HackathonScheduleTone } from './Schedule';
@@ -33,11 +33,72 @@ export const buildAgendaTypeLabelMap = ({
3333
export const isPublicForm = ({ shared_limit }: TableFormView) =>
3434
['anyone_editable'].includes(shared_limit as string);
3535

36+
type NamedLike = { name?: string | null };
37+
type TextLike = TableCellValue | NamedLike | null | undefined;
38+
type TextListLike = TextLike | TextLike[];
39+
40+
const textOf = (value: TextLike) => {
41+
if (!value) return '';
42+
43+
if (typeof value === 'object' && !Array.isArray(value))
44+
return 'name' in value ? (value.name || '').trim() : '';
45+
46+
const text = value.toString().trim();
47+
48+
return text === '[object Object]' ? '' : text;
49+
};
50+
51+
export const firstTextOf = (value: TextListLike) =>
52+
(Array.isArray(value) ? value.map(textOf).find(Boolean) : textOf(value)) || '';
53+
54+
export const textListOf = (value: TextListLike) =>
55+
(Array.isArray(value) ? value : [value]).map(textOf).filter(Boolean);
56+
57+
export const relationNameOf = (value: TextListLike) => firstTextOf(value);
58+
59+
export const userOf = (value?: TableCellValue | TableCellUser) =>
60+
value && typeof value === 'object' && !Array.isArray(value) && 'name' in value
61+
? (value as TableCellUser)
62+
: undefined;
63+
3664
export const formatMoment = (value?: TableCellValue) => (value ? formatDate(value as string) : '');
3765

3866
export const formatPeriod = (startedAt?: TableCellValue, endedAt?: TableCellValue) =>
3967
[formatMoment(startedAt), formatMoment(endedAt)].filter(Boolean).join(' - ');
4068

69+
export const timeOf = (value?: TableCellValue) => {
70+
const time = new Date((value as string) || 0).getTime();
71+
72+
return Number.isFinite(time) ? time : NaN;
73+
};
74+
75+
export interface CountdownWindow {
76+
startedAt?: TableCellValue;
77+
endedAt?: TableCellValue;
78+
}
79+
80+
export const resolveCountdownState = <T extends CountdownWindow>(
81+
items: T[],
82+
now: number,
83+
startTime?: TableCellValue,
84+
endTime?: TableCellValue,
85+
) => {
86+
const nextItem = items.find(({ startedAt, endedAt }) => {
87+
const started = timeOf(startedAt);
88+
const ended = timeOf(endedAt);
89+
90+
return Number.isFinite(started) && Number.isFinite(ended) && now <= ended;
91+
});
92+
const nextStartedAt = timeOf(nextItem?.startedAt);
93+
const countdownTo =
94+
(Number.isFinite(nextStartedAt) && nextStartedAt > now
95+
? (nextItem?.startedAt as string | undefined)
96+
: (nextItem?.endedAt as string | undefined)) ||
97+
(timeOf(startTime) > now ? (startTime as string | undefined) : (endTime as string | undefined));
98+
99+
return { nextItem, countdownTo };
100+
};
101+
41102
export const previewText = (items: TableCellValue[], fallback: string) =>
42103
items
43104
.map(item => item?.toString())
@@ -95,8 +156,8 @@ export const dateKeyOf = (value?: TableCellValue) => {
95156
export const compactDateKeyOf = (value?: TableCellValue) => dateKeyOf(value).replace('-', '.');
96157

97158
export const daysBetween = (startedAt?: TableCellValue, endedAt?: TableCellValue) => {
98-
const start = new Date((startedAt as string) || '').getTime();
99-
const end = new Date((endedAt as string) || '').getTime();
159+
const start = timeOf(startedAt);
160+
const end = timeOf(endedAt);
100161

101162
if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) return 0;
102163

0 commit comments

Comments
 (0)