| author | |
| committer | |
| log | 9afef94a61466422128da9c3b723b633d4c7ed1d |
| tree | 053a20dd99e24d55ce7a733a2dd59f8a2d4de058 |
| parent | a7b0366cbe1e9eabc9e37eb079a38f6b6691f999 |
| signature | Signed by PGP key B5690EEEBB952194 |
3 files changed, 22 insertions(+), 6 deletions(-)
apps/web/src/components/Sidebar.snooze.test.ts+6-3| ... | ... | @@ -8,15 +8,18 @@ function localDate(year: number, month: number, day: number, hour: number, minut |
| 8 | 8 | } |
| 9 | 9 | |
| 10 | 10 | describe("resolveSnoozePresets", () => { |
| 11 | it("offers hour, evening, tomorrow, next week in the morning", () => { | |
| 11 | it("offers one hour, three hours, evening, tomorrow, and next week in the morning", () => { | |
| 12 | 12 | // Wednesday 2026-04-08 10:00 local. |
| 13 | 13 | const presets = resolveSnoozePresets(localDate(2026, 4, 8, 10), "locale"); |
| 14 | 14 | expect(presets.map((preset) => preset.id)).toEqual([ |
| 15 | 15 | "hour", |
| 16 | "three-hours", | |
| 16 | 17 | "evening", |
| 17 | 18 | "tomorrow", |
| 18 | 19 | "next-week", |
| 19 | 20 | ]); |
| 21 | const threeHours = presets.find((preset) => preset.id === "three-hours"); | |
| 22 | expect(new Date(threeHours!.snoozedUntil).getHours()).toBe(13); | |
| 20 | 23 | const evening = presets.find((preset) => preset.id === "evening"); |
| 21 | 24 | expect(new Date(evening!.snoozedUntil).getHours()).toBe(18); |
| 22 | 25 | const tomorrow = presets.find((preset) => preset.id === "tomorrow"); |
| ... | ... | @@ -45,10 +48,10 @@ describe("resolveSnoozePresets", () => { |
| 45 | 48 | it("drops the evening preset once evening is near or past", () => { |
| 46 | 49 | expect( |
| 47 | 50 | resolveSnoozePresets(localDate(2026, 4, 8, 17, 30), "locale").map((preset) => preset.id), |
| 48 | ).toEqual(["hour", "tomorrow", "next-week"]); | |
| 51 | ).toEqual(["hour", "three-hours", "tomorrow", "next-week"]); | |
| 49 | 52 | expect( |
| 50 | 53 | resolveSnoozePresets(localDate(2026, 4, 8, 21), "locale").map((preset) => preset.id), |
| 51 | ).toEqual(["hour", "tomorrow", "next-week"]); | |
| 54 | ).toEqual(["hour", "three-hours", "tomorrow", "next-week"]); | |
| 52 | 55 | }); |
| 53 | 56 | |
| 54 | 57 | it("puts next week a full week out when today is Monday", () => { |
packages/client-runtime/src/state/threadSettled.ts+10-3| ... | ... | @@ -284,7 +284,7 @@ const HOUR_MS = 60 * 60 * 1_000; |
| 284 | 284 | const EVENING_HOUR = 18; |
| 285 | 285 | const MORNING_HOUR = 9; |
| 286 | 286 | |
| 287 | export type SnoozePresetId = "hour" | "evening" | "tomorrow" | "next-week"; | |
| 287 | export type SnoozePresetId = "hour" | "three-hours" | "evening" | "tomorrow" | "next-week"; | |
| 288 | 288 | |
| 289 | 289 | export interface SnoozePreset { |
| 290 | 290 | readonly id: SnoozePresetId; |
| ... | ... | @@ -317,11 +317,12 @@ function addSnoozeDays(base: Date, days: number): Date { |
| 317 | 317 | |
| 318 | 318 | /** |
| 319 | 319 | * Shared "snooze until" choices for every client. "This evening" only |
| 320 | * appears while it is meaningfully before evening; after that the list | |
| 321 | * starts at "Tomorrow". | |
| 320 | * appears while it is meaningfully before evening; after that the calendar | |
| 321 | * choices start at "Tomorrow". | |
| 322 | 322 | */ |
| 323 | 323 | export function resolveSnoozePresets(now: Date): ReadonlyArray<SnoozePreset> { |
| 324 | 324 | const inAnHour = new Date(now.getTime() + HOUR_MS); |
| 325 | const inThreeHours = new Date(now.getTime() + 3 * HOUR_MS); | |
| 325 | 326 | const presets: SnoozePreset[] = [ |
| 326 | 327 | { |
| 327 | 328 | id: "hour", |
| ... | ... | @@ -329,6 +330,12 @@ export function resolveSnoozePresets(now: Date): ReadonlyArray<SnoozePreset> { |
| 329 | 330 | whenLabel: snoozeTimeOfDayLabel(inAnHour), |
| 330 | 331 | snoozedUntil: inAnHour.toISOString(), |
| 331 | 332 | }, |
| 333 | { | |
| 334 | id: "three-hours", | |
| 335 | label: "In 3 hours", | |
| 336 | whenLabel: snoozeTimeOfDayLabel(inThreeHours), | |
| 337 | snoozedUntil: inThreeHours.toISOString(), | |
| 338 | }, | |
| 332 | 339 | ]; |
| 333 | 340 | |
| 334 | 341 | const evening = snoozeAtHour(now, EVENING_HOUR); |
packages/client-runtime/src/state/threadSnoozed.test.ts+6| ... | ... | @@ -265,10 +265,15 @@ describe("resolveSnoozePresets", () => { |
| 265 | 265 | const presets = resolveSnoozePresets(localDate(2026, 4, 8, 10)); |
| 266 | 266 | expect(presets.map((preset) => preset.id)).toEqual([ |
| 267 | 267 | "hour", |
| 268 | "three-hours", | |
| 268 | 269 | "evening", |
| 269 | 270 | "tomorrow", |
| 270 | 271 | "next-week", |
| 271 | 272 | ]); |
| 273 | expect(presets.find((preset) => preset.id === "three-hours")?.snoozedUntil).toBe( | |
| 274 | localDate(2026, 4, 8, 13).toISOString(), | |
| 275 | ); | |
| 276 | expect(presets.find((preset) => preset.id === "three-hours")?.label).toBe("In 3 hours"); | |
| 272 | 277 | expect(presets.find((preset) => preset.id === "evening")?.label).toBe("This evening"); |
| 273 | 278 | expect( |
| 274 | 279 | new Date(presets.find((preset) => preset.id === "tomorrow")!.snoozedUntil).getHours(), |
| ... | ... | @@ -278,6 +283,7 @@ describe("resolveSnoozePresets", () => { |
| 278 | 283 | it("drops the evening choice once evening is near or past", () => { |
| 279 | 284 | expect(resolveSnoozePresets(localDate(2026, 4, 8, 17, 30)).map((preset) => preset.id)).toEqual([ |
| 280 | 285 | "hour", |
| 286 | "three-hours", | |
| 281 | 287 | "tomorrow", |
| 282 | 288 | "next-week", |
| 283 | 289 | ]); |