(date: Date | null)
| 37 | }; |
| 38 | |
| 39 | export const formatScheduleDelta = (date: Date | null): string | null => { |
| 40 | if (!date) { |
| 41 | return null; |
| 42 | } |
| 43 | |
| 44 | const diffMs = date.getTime() - Date.now(); |
| 45 | if (diffMs <= 0) { |
| 46 | return 'now'; |
| 47 | } |
| 48 | |
| 49 | const minutes = Math.max(1, Math.round(diffMs / 60_000)); |
| 50 | if (minutes < 60) { |
| 51 | return `${minutes} minute${minutes === 1 ? '' : 's'} from now`; |
| 52 | } |
| 53 | |
| 54 | const hours = Math.round(minutes / 60); |
| 55 | if (hours < 24) { |
| 56 | return `${hours} hour${hours === 1 ? '' : 's'} from now`; |
| 57 | } |
| 58 | |
| 59 | const days = Math.round(hours / 24); |
| 60 | return `${days} day${days === 1 ? '' : 's'} from now`; |
| 61 | }; |
| 62 | |
| 63 | // Validation copy mirrors the daily-api errors so the client blocks the same |
| 64 | // inputs the server would reject. |
no outgoing calls
no test coverage detected