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