@mrck-labs/vanaheim-shared 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -10
- package/dist/atoms/index.d.mts +92 -0
- package/dist/atoms/index.d.ts +92 -0
- package/dist/atoms/index.js +82 -0
- package/dist/atoms/index.js.map +1 -0
- package/dist/atoms/index.mjs +47 -0
- package/dist/atoms/index.mjs.map +1 -0
- package/dist/date/index.d.mts +176 -0
- package/dist/date/index.d.ts +176 -0
- package/dist/date/index.js +347 -0
- package/dist/date/index.js.map +1 -0
- package/dist/date/index.mjs +290 -0
- package/dist/date/index.mjs.map +1 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +600 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +557 -3
- package/dist/index.mjs.map +1 -1
- package/dist/query/index.d.mts +321 -0
- package/dist/query/index.d.ts +321 -0
- package/dist/query/index.js +257 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/index.mjs +232 -0
- package/dist/query/index.mjs.map +1 -0
- package/dist/utils/index.d.mts +2 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +25 -1
package/dist/index.mjs
CHANGED
|
@@ -112,7 +112,7 @@ function formatTotalTime(seconds) {
|
|
|
112
112
|
}
|
|
113
113
|
return `${mins}m`;
|
|
114
114
|
}
|
|
115
|
-
function formatCurrency(amount, currency, locale = "
|
|
115
|
+
function formatCurrency(amount, currency, locale = "de-CH") {
|
|
116
116
|
return new Intl.NumberFormat(locale, {
|
|
117
117
|
style: "currency",
|
|
118
118
|
currency,
|
|
@@ -149,12 +149,12 @@ function formatDueDate(dueDate) {
|
|
|
149
149
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
150
150
|
const dueDay = new Date(due);
|
|
151
151
|
dueDay.setHours(0, 0, 0, 0);
|
|
152
|
-
const
|
|
152
|
+
const isOverdue2 = dueDay < today;
|
|
153
153
|
if (dueDay.getTime() === today.getTime()) {
|
|
154
154
|
return { text: "Today", isOverdue: false };
|
|
155
155
|
} else if (dueDay.getTime() === tomorrow.getTime()) {
|
|
156
156
|
return { text: "Tomorrow", isOverdue: false };
|
|
157
|
-
} else if (
|
|
157
|
+
} else if (isOverdue2) {
|
|
158
158
|
const daysAgo = Math.ceil(
|
|
159
159
|
(today.getTime() - dueDay.getTime()) / (1e3 * 60 * 60 * 24)
|
|
160
160
|
);
|
|
@@ -296,6 +296,517 @@ function calculateFocusStats(sessions) {
|
|
|
296
296
|
completionRate
|
|
297
297
|
};
|
|
298
298
|
}
|
|
299
|
+
|
|
300
|
+
// src/query/index.ts
|
|
301
|
+
var queryKeys = {
|
|
302
|
+
// -------------------------------------------------------------------------
|
|
303
|
+
// Expenses
|
|
304
|
+
// -------------------------------------------------------------------------
|
|
305
|
+
expenses: {
|
|
306
|
+
all: ["expenses"],
|
|
307
|
+
lists: () => [...queryKeys.expenses.all, "list"],
|
|
308
|
+
list: (filters) => [...queryKeys.expenses.lists(), filters],
|
|
309
|
+
detail: (id) => [...queryKeys.expenses.all, "detail", id]
|
|
310
|
+
},
|
|
311
|
+
// Expense Categories
|
|
312
|
+
expenseCategories: {
|
|
313
|
+
all: ["expenseCategories"],
|
|
314
|
+
list: () => [...queryKeys.expenseCategories.all, "list"]
|
|
315
|
+
},
|
|
316
|
+
// Expense Payments
|
|
317
|
+
expensePayments: {
|
|
318
|
+
all: ["expensePayments"],
|
|
319
|
+
lists: () => [...queryKeys.expensePayments.all, "list"],
|
|
320
|
+
list: (filters) => [...queryKeys.expensePayments.lists(), filters],
|
|
321
|
+
detail: (id) => [...queryKeys.expensePayments.all, "detail", id]
|
|
322
|
+
},
|
|
323
|
+
// -------------------------------------------------------------------------
|
|
324
|
+
// Income
|
|
325
|
+
// -------------------------------------------------------------------------
|
|
326
|
+
incomes: {
|
|
327
|
+
all: ["incomes"],
|
|
328
|
+
lists: () => [...queryKeys.incomes.all, "list"],
|
|
329
|
+
list: (filters) => [...queryKeys.incomes.lists(), filters],
|
|
330
|
+
detail: (id) => [...queryKeys.incomes.all, "detail", id]
|
|
331
|
+
},
|
|
332
|
+
// Income Categories
|
|
333
|
+
incomeCategories: {
|
|
334
|
+
all: ["incomeCategories"],
|
|
335
|
+
list: () => [...queryKeys.incomeCategories.all, "list"]
|
|
336
|
+
},
|
|
337
|
+
// Income Payments
|
|
338
|
+
incomePayments: {
|
|
339
|
+
all: ["incomePayments"],
|
|
340
|
+
lists: () => [...queryKeys.incomePayments.all, "list"],
|
|
341
|
+
list: (filters) => [...queryKeys.incomePayments.lists(), filters],
|
|
342
|
+
detail: (id) => [...queryKeys.incomePayments.all, "detail", id]
|
|
343
|
+
},
|
|
344
|
+
// Exchange Rates
|
|
345
|
+
exchangeRates: {
|
|
346
|
+
all: ["exchangeRates"],
|
|
347
|
+
list: () => [...queryKeys.exchangeRates.all, "list"]
|
|
348
|
+
},
|
|
349
|
+
// -------------------------------------------------------------------------
|
|
350
|
+
// Focus
|
|
351
|
+
// -------------------------------------------------------------------------
|
|
352
|
+
focusSessions: {
|
|
353
|
+
all: ["focusSessions"],
|
|
354
|
+
lists: () => [...queryKeys.focusSessions.all, "list"],
|
|
355
|
+
list: (filters) => [...queryKeys.focusSessions.lists(), filters],
|
|
356
|
+
today: () => [...queryKeys.focusSessions.all, "today"],
|
|
357
|
+
active: () => [...queryKeys.focusSessions.all, "active"],
|
|
358
|
+
detail: (id) => [...queryKeys.focusSessions.all, "detail", id]
|
|
359
|
+
},
|
|
360
|
+
// Focus Categories
|
|
361
|
+
focusCategories: {
|
|
362
|
+
all: ["focusCategories"],
|
|
363
|
+
list: () => [...queryKeys.focusCategories.all, "list"]
|
|
364
|
+
},
|
|
365
|
+
// -------------------------------------------------------------------------
|
|
366
|
+
// Settings
|
|
367
|
+
// -------------------------------------------------------------------------
|
|
368
|
+
settings: {
|
|
369
|
+
all: ["settings"],
|
|
370
|
+
detail: (key) => [...queryKeys.settings.all, key]
|
|
371
|
+
},
|
|
372
|
+
// -------------------------------------------------------------------------
|
|
373
|
+
// EF Work (Lieu Days & Links)
|
|
374
|
+
// -------------------------------------------------------------------------
|
|
375
|
+
lieuDays: {
|
|
376
|
+
all: ["lieuDays"],
|
|
377
|
+
list: () => [...queryKeys.lieuDays.all, "list"],
|
|
378
|
+
balance: () => [...queryKeys.lieuDays.all, "balance"],
|
|
379
|
+
detail: (id) => [...queryKeys.lieuDays.all, "detail", id]
|
|
380
|
+
},
|
|
381
|
+
efLinks: {
|
|
382
|
+
all: ["efLinks"],
|
|
383
|
+
list: () => [...queryKeys.efLinks.all, "list"],
|
|
384
|
+
detail: (id) => [...queryKeys.efLinks.all, "detail", id]
|
|
385
|
+
},
|
|
386
|
+
// -------------------------------------------------------------------------
|
|
387
|
+
// Banking
|
|
388
|
+
// -------------------------------------------------------------------------
|
|
389
|
+
bankConnections: {
|
|
390
|
+
all: ["bankConnections"],
|
|
391
|
+
list: () => [...queryKeys.bankConnections.all, "list"],
|
|
392
|
+
detail: (id) => [...queryKeys.bankConnections.all, "detail", id]
|
|
393
|
+
},
|
|
394
|
+
bankTransactions: {
|
|
395
|
+
all: ["bankTransactions"],
|
|
396
|
+
lists: () => [...queryKeys.bankTransactions.all, "list"],
|
|
397
|
+
list: (filters) => [...queryKeys.bankTransactions.lists(), filters],
|
|
398
|
+
stats: (connectionId) => [...queryKeys.bankTransactions.all, "stats", connectionId]
|
|
399
|
+
},
|
|
400
|
+
// -------------------------------------------------------------------------
|
|
401
|
+
// Health
|
|
402
|
+
// -------------------------------------------------------------------------
|
|
403
|
+
healthCategories: {
|
|
404
|
+
all: ["healthCategories"],
|
|
405
|
+
list: () => [...queryKeys.healthCategories.all, "list"],
|
|
406
|
+
detail: (id) => [...queryKeys.healthCategories.all, "detail", id]
|
|
407
|
+
},
|
|
408
|
+
healthHabits: {
|
|
409
|
+
all: ["healthHabits"],
|
|
410
|
+
lists: () => [...queryKeys.healthHabits.all, "list"],
|
|
411
|
+
list: (filters) => [...queryKeys.healthHabits.lists(), filters],
|
|
412
|
+
detail: (id) => [...queryKeys.healthHabits.all, "detail", id]
|
|
413
|
+
},
|
|
414
|
+
healthCompletions: {
|
|
415
|
+
all: ["healthCompletions"],
|
|
416
|
+
lists: () => [...queryKeys.healthCompletions.all, "list"],
|
|
417
|
+
list: (filters) => [...queryKeys.healthCompletions.lists(), filters],
|
|
418
|
+
forHabit: (habitId) => [...queryKeys.healthCompletions.all, "habit", habitId],
|
|
419
|
+
forDate: (date) => [...queryKeys.healthCompletions.all, "date", date]
|
|
420
|
+
},
|
|
421
|
+
healthStats: {
|
|
422
|
+
all: ["healthStats"],
|
|
423
|
+
forDate: (date) => [...queryKeys.healthStats.all, date ?? "today"]
|
|
424
|
+
},
|
|
425
|
+
// -------------------------------------------------------------------------
|
|
426
|
+
// Prompts
|
|
427
|
+
// -------------------------------------------------------------------------
|
|
428
|
+
promptCategories: {
|
|
429
|
+
all: ["promptCategories"],
|
|
430
|
+
list: () => [...queryKeys.promptCategories.all, "list"],
|
|
431
|
+
detail: (id) => [...queryKeys.promptCategories.all, "detail", id]
|
|
432
|
+
},
|
|
433
|
+
promptLabels: {
|
|
434
|
+
all: ["promptLabels"],
|
|
435
|
+
list: () => [...queryKeys.promptLabels.all, "list"],
|
|
436
|
+
detail: (id) => [...queryKeys.promptLabels.all, "detail", id]
|
|
437
|
+
},
|
|
438
|
+
prompts: {
|
|
439
|
+
all: ["prompts"],
|
|
440
|
+
lists: () => [...queryKeys.prompts.all, "list"],
|
|
441
|
+
list: (filters) => [...queryKeys.prompts.lists(), filters],
|
|
442
|
+
detail: (id) => [...queryKeys.prompts.all, "detail", id]
|
|
443
|
+
},
|
|
444
|
+
// -------------------------------------------------------------------------
|
|
445
|
+
// Training
|
|
446
|
+
// -------------------------------------------------------------------------
|
|
447
|
+
trainingActivities: {
|
|
448
|
+
all: ["trainingActivities"],
|
|
449
|
+
list: () => [...queryKeys.trainingActivities.all, "list"],
|
|
450
|
+
detail: (id) => [...queryKeys.trainingActivities.all, "detail", id],
|
|
451
|
+
byStravaType: (stravaType) => [...queryKeys.trainingActivities.all, "strava", stravaType]
|
|
452
|
+
},
|
|
453
|
+
trainingSessions: {
|
|
454
|
+
all: ["trainingSessions"],
|
|
455
|
+
lists: () => [...queryKeys.trainingSessions.all, "list"],
|
|
456
|
+
list: (filters) => [...queryKeys.trainingSessions.lists(), filters],
|
|
457
|
+
detail: (id) => [...queryKeys.trainingSessions.all, "detail", id],
|
|
458
|
+
byStravaId: (stravaActivityId) => [...queryKeys.trainingSessions.all, "strava", stravaActivityId]
|
|
459
|
+
},
|
|
460
|
+
plannedSessions: {
|
|
461
|
+
all: ["plannedSessions"],
|
|
462
|
+
lists: () => [...queryKeys.plannedSessions.all, "list"],
|
|
463
|
+
list: (filters) => [...queryKeys.plannedSessions.lists(), filters],
|
|
464
|
+
detail: (id) => [...queryKeys.plannedSessions.all, "detail", id],
|
|
465
|
+
upcoming: () => [...queryKeys.plannedSessions.all, "upcoming"]
|
|
466
|
+
},
|
|
467
|
+
races: {
|
|
468
|
+
all: ["races"],
|
|
469
|
+
lists: () => [...queryKeys.races.all, "list"],
|
|
470
|
+
list: (filters) => [...queryKeys.races.lists(), filters],
|
|
471
|
+
detail: (id) => [...queryKeys.races.all, "detail", id],
|
|
472
|
+
next: () => [...queryKeys.races.all, "next"]
|
|
473
|
+
},
|
|
474
|
+
trainingStats: {
|
|
475
|
+
all: ["trainingStats"],
|
|
476
|
+
forRange: (dateFrom, dateTo) => [...queryKeys.trainingStats.all, dateFrom, dateTo]
|
|
477
|
+
},
|
|
478
|
+
// Strava
|
|
479
|
+
strava: {
|
|
480
|
+
all: ["strava"],
|
|
481
|
+
athlete: () => [...queryKeys.strava.all, "athlete"],
|
|
482
|
+
connected: () => [...queryKeys.strava.all, "connected"],
|
|
483
|
+
activities: (options) => [...queryKeys.strava.all, "activities", options]
|
|
484
|
+
},
|
|
485
|
+
// -------------------------------------------------------------------------
|
|
486
|
+
// Journal
|
|
487
|
+
// -------------------------------------------------------------------------
|
|
488
|
+
journalEntries: {
|
|
489
|
+
all: ["journalEntries"],
|
|
490
|
+
lists: () => [...queryKeys.journalEntries.all, "list"],
|
|
491
|
+
list: (filters) => [...queryKeys.journalEntries.lists(), filters],
|
|
492
|
+
forDate: (date) => [...queryKeys.journalEntries.all, "date", date]
|
|
493
|
+
},
|
|
494
|
+
// Journal data (aggregated)
|
|
495
|
+
journalData: {
|
|
496
|
+
all: ["journalData"],
|
|
497
|
+
forDate: (date) => [...queryKeys.journalData.all, date]
|
|
498
|
+
},
|
|
499
|
+
// -------------------------------------------------------------------------
|
|
500
|
+
// Chat
|
|
501
|
+
// -------------------------------------------------------------------------
|
|
502
|
+
chatConversations: {
|
|
503
|
+
all: ["chatConversations"],
|
|
504
|
+
list: () => [...queryKeys.chatConversations.all, "list"],
|
|
505
|
+
detail: (id) => [...queryKeys.chatConversations.all, "detail", id]
|
|
506
|
+
},
|
|
507
|
+
chatMessages: {
|
|
508
|
+
all: ["chatMessages"],
|
|
509
|
+
forConversation: (conversationId) => [...queryKeys.chatMessages.all, "conversation", conversationId]
|
|
510
|
+
},
|
|
511
|
+
// -------------------------------------------------------------------------
|
|
512
|
+
// Google Calendar
|
|
513
|
+
// -------------------------------------------------------------------------
|
|
514
|
+
googleCalendar: {
|
|
515
|
+
all: ["googleCalendar"],
|
|
516
|
+
calendars: () => [...queryKeys.googleCalendar.all, "calendars"],
|
|
517
|
+
events: (calendarId, timeMin, timeMax) => [...queryKeys.googleCalendar.all, "events", calendarId, timeMin, timeMax]
|
|
518
|
+
},
|
|
519
|
+
// -------------------------------------------------------------------------
|
|
520
|
+
// Linear
|
|
521
|
+
// -------------------------------------------------------------------------
|
|
522
|
+
linear: {
|
|
523
|
+
all: ["linear"],
|
|
524
|
+
issues: (filters) => [...queryKeys.linear.all, "issues", filters],
|
|
525
|
+
projects: () => [...queryKeys.linear.all, "projects"]
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// src/atoms/focus.ts
|
|
530
|
+
import { atom } from "jotai";
|
|
531
|
+
var timerStatusAtom = atom("idle");
|
|
532
|
+
var targetSecondsAtom = atom(25 * 60);
|
|
533
|
+
var elapsedSecondsAtom = atom(0);
|
|
534
|
+
var activeSessionAtom = atom(null);
|
|
535
|
+
var remainingSecondsAtom = atom((get) => {
|
|
536
|
+
const target = get(targetSecondsAtom);
|
|
537
|
+
const elapsed = get(elapsedSecondsAtom);
|
|
538
|
+
return Math.max(0, target - elapsed);
|
|
539
|
+
});
|
|
540
|
+
var progressAtom = atom((get) => {
|
|
541
|
+
const target = get(targetSecondsAtom);
|
|
542
|
+
const elapsed = get(elapsedSecondsAtom);
|
|
543
|
+
if (target === 0) return 0;
|
|
544
|
+
return Math.min(1, elapsed / target);
|
|
545
|
+
});
|
|
546
|
+
var formattedRemainingAtom = atom((get) => {
|
|
547
|
+
return formatTime(get(remainingSecondsAtom));
|
|
548
|
+
});
|
|
549
|
+
var formattedElapsedAtom = atom((get) => {
|
|
550
|
+
return formatTime(get(elapsedSecondsAtom));
|
|
551
|
+
});
|
|
552
|
+
var progressPercentAtom = atom((get) => {
|
|
553
|
+
return get(progressAtom) * 100;
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// src/date/index.ts
|
|
557
|
+
function normalizeToMidnight(date) {
|
|
558
|
+
const d = new Date(date);
|
|
559
|
+
d.setHours(0, 0, 0, 0);
|
|
560
|
+
return d;
|
|
561
|
+
}
|
|
562
|
+
function getTodayMidnight() {
|
|
563
|
+
return normalizeToMidnight(/* @__PURE__ */ new Date());
|
|
564
|
+
}
|
|
565
|
+
function formatDateString(date) {
|
|
566
|
+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
567
|
+
}
|
|
568
|
+
function getTodayString() {
|
|
569
|
+
return formatDateString(/* @__PURE__ */ new Date());
|
|
570
|
+
}
|
|
571
|
+
function parseLocalDate(dateStr) {
|
|
572
|
+
return /* @__PURE__ */ new Date(dateStr + "T00:00:00");
|
|
573
|
+
}
|
|
574
|
+
function isToday(dateStr) {
|
|
575
|
+
if (!dateStr) return false;
|
|
576
|
+
return dateStr === getTodayString();
|
|
577
|
+
}
|
|
578
|
+
function isOverdue(dateStr) {
|
|
579
|
+
if (!dateStr) return false;
|
|
580
|
+
return dateStr < getTodayString();
|
|
581
|
+
}
|
|
582
|
+
function isDueSoon(dateStr, daysThreshold = 7) {
|
|
583
|
+
if (!dateStr) return false;
|
|
584
|
+
if (isOverdue(dateStr)) return false;
|
|
585
|
+
const today = getTodayMidnight();
|
|
586
|
+
const targetDate = parseLocalDate(dateStr);
|
|
587
|
+
const diffMs = targetDate.getTime() - today.getTime();
|
|
588
|
+
const diffDays = Math.ceil(diffMs / (1e3 * 60 * 60 * 24));
|
|
589
|
+
return diffDays >= 0 && diffDays <= daysThreshold;
|
|
590
|
+
}
|
|
591
|
+
function addDays(dateStr, days) {
|
|
592
|
+
const date = parseLocalDate(dateStr);
|
|
593
|
+
date.setDate(date.getDate() + days);
|
|
594
|
+
return formatDateString(date);
|
|
595
|
+
}
|
|
596
|
+
function subtractDays(dateStr, days) {
|
|
597
|
+
return addDays(dateStr, -days);
|
|
598
|
+
}
|
|
599
|
+
function getYesterdayString() {
|
|
600
|
+
return subtractDays(getTodayString(), 1);
|
|
601
|
+
}
|
|
602
|
+
function getTomorrowString() {
|
|
603
|
+
return addDays(getTodayString(), 1);
|
|
604
|
+
}
|
|
605
|
+
function getStartOfDayISO(dateStr) {
|
|
606
|
+
const date = parseLocalDate(dateStr);
|
|
607
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).toISOString();
|
|
608
|
+
}
|
|
609
|
+
function getEndOfDayISO(dateStr) {
|
|
610
|
+
const date = parseLocalDate(dateStr);
|
|
611
|
+
return new Date(
|
|
612
|
+
date.getFullYear(),
|
|
613
|
+
date.getMonth(),
|
|
614
|
+
date.getDate(),
|
|
615
|
+
23,
|
|
616
|
+
59,
|
|
617
|
+
59,
|
|
618
|
+
999
|
|
619
|
+
).toISOString();
|
|
620
|
+
}
|
|
621
|
+
function getWeekStart(date) {
|
|
622
|
+
const d = new Date(date);
|
|
623
|
+
const day = d.getDay();
|
|
624
|
+
const diff = d.getDate() - day + (day === 0 ? -6 : 1);
|
|
625
|
+
d.setDate(diff);
|
|
626
|
+
d.setHours(0, 0, 0, 0);
|
|
627
|
+
return d;
|
|
628
|
+
}
|
|
629
|
+
function getWeekEnd(weekStart) {
|
|
630
|
+
const d = new Date(weekStart);
|
|
631
|
+
d.setDate(d.getDate() + 6);
|
|
632
|
+
return d;
|
|
633
|
+
}
|
|
634
|
+
function getPreviousWeek(weekStart) {
|
|
635
|
+
const d = new Date(weekStart);
|
|
636
|
+
d.setDate(d.getDate() - 7);
|
|
637
|
+
return d;
|
|
638
|
+
}
|
|
639
|
+
function getNextWeek(weekStart) {
|
|
640
|
+
const d = new Date(weekStart);
|
|
641
|
+
d.setDate(d.getDate() + 7);
|
|
642
|
+
return d;
|
|
643
|
+
}
|
|
644
|
+
function getWeekStartString(baseDate = /* @__PURE__ */ new Date()) {
|
|
645
|
+
return formatDateString(getWeekStart(baseDate));
|
|
646
|
+
}
|
|
647
|
+
function getWeekEndString(baseDate = /* @__PURE__ */ new Date()) {
|
|
648
|
+
return formatDateString(getWeekEnd(getWeekStart(baseDate)));
|
|
649
|
+
}
|
|
650
|
+
function formatWeekRange(weekStart) {
|
|
651
|
+
const weekEnd = getWeekEnd(weekStart);
|
|
652
|
+
const startMonth = weekStart.toLocaleDateString("en-US", { month: "short" });
|
|
653
|
+
const endMonth = weekEnd.toLocaleDateString("en-US", { month: "short" });
|
|
654
|
+
if (startMonth === endMonth) {
|
|
655
|
+
return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekStart.getFullYear()}`;
|
|
656
|
+
}
|
|
657
|
+
return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekStart.getFullYear()}`;
|
|
658
|
+
}
|
|
659
|
+
function formatFullDate(dateStr) {
|
|
660
|
+
const date = parseLocalDate(dateStr);
|
|
661
|
+
return date.toLocaleDateString("en-US", {
|
|
662
|
+
weekday: "long",
|
|
663
|
+
year: "numeric",
|
|
664
|
+
month: "long",
|
|
665
|
+
day: "numeric"
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
function formatDateLong(dateStr) {
|
|
669
|
+
const date = parseLocalDate(dateStr);
|
|
670
|
+
return date.toLocaleDateString("en-GB", {
|
|
671
|
+
weekday: "long",
|
|
672
|
+
day: "numeric",
|
|
673
|
+
month: "long"
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
function formatMonthYear(date) {
|
|
677
|
+
return date.toLocaleDateString("en-US", {
|
|
678
|
+
month: "long",
|
|
679
|
+
year: "numeric"
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
function formatTimeHHMM(date) {
|
|
683
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
684
|
+
return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
685
|
+
}
|
|
686
|
+
function formatTimeWithSeconds(date) {
|
|
687
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
688
|
+
return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
689
|
+
}
|
|
690
|
+
function formatDateHeader(dateStr) {
|
|
691
|
+
const today = getTodayString();
|
|
692
|
+
if (dateStr < today) {
|
|
693
|
+
return "Overdue";
|
|
694
|
+
}
|
|
695
|
+
if (dateStr === today) {
|
|
696
|
+
return "Today";
|
|
697
|
+
}
|
|
698
|
+
const tomorrowStr = getTomorrowString();
|
|
699
|
+
if (dateStr === tomorrowStr) {
|
|
700
|
+
return "Tomorrow";
|
|
701
|
+
}
|
|
702
|
+
const date = parseLocalDate(dateStr);
|
|
703
|
+
return date.toLocaleDateString("en-US", {
|
|
704
|
+
weekday: "long",
|
|
705
|
+
month: "short",
|
|
706
|
+
day: "numeric"
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
function formatDueDateString(dateStr) {
|
|
710
|
+
if (!dateStr) return "No due date";
|
|
711
|
+
const today = getTodayString();
|
|
712
|
+
const tomorrowStr = getTomorrowString();
|
|
713
|
+
if (dateStr < today) {
|
|
714
|
+
const date2 = parseLocalDate(dateStr);
|
|
715
|
+
return `Overdue \u2022 ${date2.toLocaleDateString("en-US", { month: "short", day: "numeric" })}`;
|
|
716
|
+
}
|
|
717
|
+
if (dateStr === today) {
|
|
718
|
+
return "Today";
|
|
719
|
+
}
|
|
720
|
+
if (dateStr === tomorrowStr) {
|
|
721
|
+
return "Tomorrow";
|
|
722
|
+
}
|
|
723
|
+
const date = parseLocalDate(dateStr);
|
|
724
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
725
|
+
const dateYear = date.getFullYear();
|
|
726
|
+
return date.toLocaleDateString("en-US", {
|
|
727
|
+
month: "short",
|
|
728
|
+
day: "numeric",
|
|
729
|
+
year: dateYear !== currentYear ? "numeric" : void 0
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
function formatRelativeTimeExtended(dateStr) {
|
|
733
|
+
const date = typeof dateStr === "string" ? new Date(dateStr) : dateStr;
|
|
734
|
+
const now = /* @__PURE__ */ new Date();
|
|
735
|
+
const diffMs = now.getTime() - date.getTime();
|
|
736
|
+
const diffMins = Math.floor(diffMs / 6e4);
|
|
737
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
738
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
739
|
+
if (diffMins < 1) return "Just now";
|
|
740
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
741
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
742
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
743
|
+
return date.toLocaleDateString();
|
|
744
|
+
}
|
|
745
|
+
function formatRelativeDueDate(dateStr, options) {
|
|
746
|
+
const { duePrefix = "Due", overduePrefix = "" } = options || {};
|
|
747
|
+
const date = parseLocalDate(dateStr);
|
|
748
|
+
const now = normalizeToMidnight(/* @__PURE__ */ new Date());
|
|
749
|
+
const diffMs = date.getTime() - now.getTime();
|
|
750
|
+
const diffDays = Math.round(diffMs / (1e3 * 60 * 60 * 24));
|
|
751
|
+
if (diffDays < 0) {
|
|
752
|
+
const absDays = Math.abs(diffDays);
|
|
753
|
+
return overduePrefix ? `${overduePrefix} ${absDays} day${absDays !== 1 ? "s" : ""} overdue` : `${absDays} day${absDays !== 1 ? "s" : ""} overdue`;
|
|
754
|
+
}
|
|
755
|
+
if (diffDays === 0) return `${duePrefix} today`;
|
|
756
|
+
if (diffDays === 1) return `${duePrefix} tomorrow`;
|
|
757
|
+
if (diffDays <= 7) return `${duePrefix} in ${diffDays} days`;
|
|
758
|
+
return date.toLocaleDateString("en-GB", { day: "numeric", month: "short" });
|
|
759
|
+
}
|
|
760
|
+
function formatRelativePayDate(dateStr) {
|
|
761
|
+
const date = parseLocalDate(dateStr);
|
|
762
|
+
const now = normalizeToMidnight(/* @__PURE__ */ new Date());
|
|
763
|
+
const diffMs = date.getTime() - now.getTime();
|
|
764
|
+
const diffDays = Math.round(diffMs / (1e3 * 60 * 60 * 24));
|
|
765
|
+
if (diffDays < 0) {
|
|
766
|
+
const absDays = Math.abs(diffDays);
|
|
767
|
+
return `${absDays} day${absDays !== 1 ? "s" : ""} ago`;
|
|
768
|
+
}
|
|
769
|
+
if (diffDays === 0) return "Today";
|
|
770
|
+
if (diffDays === 1) return "Tomorrow";
|
|
771
|
+
if (diffDays <= 7) return `In ${diffDays} days`;
|
|
772
|
+
return date.toLocaleDateString("en-GB", { day: "numeric", month: "short" });
|
|
773
|
+
}
|
|
774
|
+
function formatDateLocalized(date, format = "medium") {
|
|
775
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
776
|
+
switch (format) {
|
|
777
|
+
case "short":
|
|
778
|
+
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
779
|
+
case "medium":
|
|
780
|
+
return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
781
|
+
case "long":
|
|
782
|
+
return d.toLocaleDateString("en-US", {
|
|
783
|
+
weekday: "long",
|
|
784
|
+
month: "long",
|
|
785
|
+
day: "numeric",
|
|
786
|
+
year: "numeric"
|
|
787
|
+
});
|
|
788
|
+
case "weekday":
|
|
789
|
+
return d.toLocaleDateString("en-US", { weekday: "short" });
|
|
790
|
+
default:
|
|
791
|
+
return d.toLocaleDateString();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function formatTimeLocalized(date, format = "short") {
|
|
795
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
796
|
+
switch (format) {
|
|
797
|
+
case "short":
|
|
798
|
+
return d.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: true });
|
|
799
|
+
case "withSeconds":
|
|
800
|
+
return d.toLocaleTimeString("en-US", {
|
|
801
|
+
hour: "2-digit",
|
|
802
|
+
minute: "2-digit",
|
|
803
|
+
second: "2-digit",
|
|
804
|
+
hour12: true
|
|
805
|
+
});
|
|
806
|
+
default:
|
|
807
|
+
return d.toLocaleTimeString();
|
|
808
|
+
}
|
|
809
|
+
}
|
|
299
810
|
export {
|
|
300
811
|
API_URLS,
|
|
301
812
|
CLOUD_AGENT_STATUSES,
|
|
@@ -313,29 +824,72 @@ export {
|
|
|
313
824
|
LINEAR_PRIORITY_COLORS,
|
|
314
825
|
LINEAR_PRIORITY_LABELS,
|
|
315
826
|
SETTING_KEYS,
|
|
827
|
+
activeSessionAtom,
|
|
828
|
+
addDays,
|
|
316
829
|
calculateFocusStats,
|
|
317
830
|
calculateLieuBalance,
|
|
318
831
|
calculateMonthlyExpenses,
|
|
319
832
|
calculateMonthlyIncome,
|
|
320
833
|
calculateMonthlySavings,
|
|
321
834
|
calculateSavingsRate,
|
|
835
|
+
elapsedSecondsAtom,
|
|
322
836
|
formatCurrency,
|
|
323
837
|
formatDate,
|
|
838
|
+
formatDateHeader,
|
|
839
|
+
formatDateLocalized,
|
|
840
|
+
formatDateLong,
|
|
841
|
+
formatDateString,
|
|
324
842
|
formatDueDate,
|
|
843
|
+
formatDueDateString,
|
|
844
|
+
formatFullDate,
|
|
845
|
+
formatMonthYear,
|
|
846
|
+
formatRelativeDueDate,
|
|
847
|
+
formatRelativePayDate,
|
|
325
848
|
formatRelativeTime,
|
|
849
|
+
formatRelativeTimeExtended,
|
|
326
850
|
formatTime,
|
|
851
|
+
formatTimeHHMM,
|
|
852
|
+
formatTimeLocalized,
|
|
853
|
+
formatTimeWithSeconds,
|
|
327
854
|
formatTotalTime,
|
|
855
|
+
formatWeekRange,
|
|
856
|
+
formattedElapsedAtom,
|
|
857
|
+
formattedRemainingAtom,
|
|
328
858
|
generateId,
|
|
329
859
|
generateRandomColor,
|
|
330
860
|
generateShortId,
|
|
861
|
+
getEndOfDayISO,
|
|
862
|
+
getNextWeek,
|
|
863
|
+
getPreviousWeek,
|
|
331
864
|
getRepoName,
|
|
865
|
+
getStartOfDayISO,
|
|
866
|
+
getTodayMidnight,
|
|
867
|
+
getTodayString,
|
|
868
|
+
getTomorrowString,
|
|
869
|
+
getWeekEnd,
|
|
870
|
+
getWeekEndString,
|
|
871
|
+
getWeekStart,
|
|
872
|
+
getWeekStartString,
|
|
873
|
+
getYesterdayString,
|
|
874
|
+
isDueSoon,
|
|
332
875
|
isNonEmptyString,
|
|
876
|
+
isOverdue,
|
|
333
877
|
isPositiveNumber,
|
|
878
|
+
isToday,
|
|
334
879
|
isValidCurrency,
|
|
335
880
|
isValidEmail,
|
|
336
881
|
isValidFrequency,
|
|
337
882
|
isValidISODate,
|
|
338
883
|
isValidUrl,
|
|
884
|
+
normalizeToMidnight,
|
|
885
|
+
parseLocalDate,
|
|
886
|
+
progressAtom,
|
|
887
|
+
progressPercentAtom,
|
|
888
|
+
queryKeys,
|
|
889
|
+
remainingSecondsAtom,
|
|
890
|
+
subtractDays,
|
|
891
|
+
targetSecondsAtom,
|
|
892
|
+
timerStatusAtom,
|
|
339
893
|
toMonthlyAmount,
|
|
340
894
|
toYearlyAmount,
|
|
341
895
|
truncate
|