refactor: replace moment library with luxon

This commit is contained in:
dohsimpson
2025-01-02 18:26:52 -05:00
parent 01c75e5412
commit e2ae2bafa7
12 changed files with 193 additions and 92 deletions

View File

@@ -2,7 +2,7 @@
import { useState } from 'react'
import { useSettings } from '@/hooks/useSettings'
import { getDateInTimezone } from '@/lib/utils'
import { t2d, d2s, getNow, isSameDate } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { formatNumber } from '@/lib/utils/formatNumber'
import { History } from 'lucide-react'
@@ -145,8 +145,7 @@ export default function CoinsManager() {
<div className="text-sm text-blue-800 dark:text-blue-100 mb-1">Today's Transactions</div>
<div className="text-2xl font-bold text-blue-900 dark:text-blue-50">
{transactions.filter(t =>
getDateInTimezone(t.timestamp, settings.system.timezone).toDateString() ===
getDateInTimezone(new Date(), settings.system.timezone).toDateString()
isSameDate(getNow({}), t2d({ timestamp: t.timestamp }))
).length} 📊
</div>
</div>
@@ -213,7 +212,7 @@ export default function CoinsManager() {
</span>
</div>
<p className="text-sm text-gray-500">
{getDateInTimezone(transaction.timestamp, settings.system.timezone).toLocaleString()}
{d2s({ dateTime: t2d({ timestamp: transaction.timestamp, timezone: settings.system.timezone }) })}
</p>
</div>
<span

View File

@@ -1,18 +1,19 @@
'use client'
import { useEffect, useState } from 'react'
import moment from 'moment-timezone'
import { DateTime } from 'luxon'
import { d2s } from '@/lib/utils'
interface DynamicTimeProps {
timezone: string
}
export function DynamicTime({ timezone }: DynamicTimeProps) {
const [time, setTime] = useState(moment())
const [time, setTime] = useState(DateTime.now().setZone(timezone))
useEffect(() => {
const timer = setInterval(() => {
setTime(moment())
setTime((prevTime) => prevTime.plus({ seconds: 1 }))
}, 1000)
return () => clearInterval(timer)
@@ -20,7 +21,7 @@ export function DynamicTime({ timezone }: DynamicTimeProps) {
return (
<div className="text-sm text-muted-foreground">
{time.tz(timezone).format('dddd, MMMM D, YYYY h:mm:ss A')}
{d2s({ dateTime: time })}
</div>
)
}

View File

@@ -7,15 +7,25 @@ import { Badge } from '@/components/ui/badge'
import { loadHabitsData } from '@/app/actions/data'
import { Habit } from '@/lib/types'
import { d2s, getNow } from '@/lib/utils'
import { useSettings } from '@/hooks/useSettings'
import { DateTime } from 'luxon'
export default function HabitCalendar() {
const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date())
const { settings } = useSettings()
const [selectedDate, setSelectedDate] = useState<DateTime>(getNow({ timezone: settings.system.timezone }))
const [habits, setHabits] = useState<Habit[]>([])
useEffect(() => {
fetchHabitsData()
}, [])
// Update selectedDate when timezone changes
useEffect(() => {
const now = getNow({ timezone: settings.system.timezone })
setSelectedDate(now)
}, [settings])
const fetchHabitsData = async () => {
const data = await loadHabitsData()
setHabits(data.habits)
@@ -39,8 +49,8 @@ export default function HabitCalendar() {
<CardContent>
<Calendar
mode="single"
selected={selectedDate}
onSelect={setSelectedDate}
selected={selectedDate.toJSDate()}
onSelect={(e) => e && setSelectedDate(DateTime.fromJSDate(e))}
className="rounded-md border"
modifiers={{
completed: (date) => getHabitsForDate(date).length > 0,
@@ -55,7 +65,7 @@ export default function HabitCalendar() {
<CardHeader>
<CardTitle>
{selectedDate ? (
<>Habits for {selectedDate.toLocaleDateString()}</>
<>Habits for {d2s({ dateTime: selectedDate })}</>
) : (
'Select a date'
)}
@@ -65,7 +75,7 @@ export default function HabitCalendar() {
{selectedDate && (
<ul className="space-y-2">
{habits.map((habit) => {
const isCompleted = getHabitsForDate(selectedDate).some(h => h.id === habit.id)
const isCompleted = getHabitsForDate(selectedDate.toJSDate()).some(h => h.id === habit.id)
return (
<li key={habit.id} className="flex items-center justify-between">
<span>{habit.name}</span>

View File

@@ -2,7 +2,7 @@
import HeatMap from '@uiw/react-heat-map'
import { Habit } from '@/lib/types'
import { getDateInTimezone } from '@/lib/utils'
import { getNow } from '@/lib/utils'
import { useSettings } from '@/hooks/useSettings'
interface HabitHeatmapProps {
@@ -29,9 +29,8 @@ export default function HabitHeatmap({ habits }: HabitHeatmapProps) {
const { settings } = useSettings()
// Get start date (30 days ago)
const now = getDateInTimezone(new Date(), settings.system.timezone)
const startDate = now
startDate.setDate(now.getDate() - 30)
const now = getNow({ timezone: settings.system.timezone })
const startDate = now.minus({ days: 30 }).toJSDate()
return (
<div className="p-4 bg-white rounded-lg shadow">

View File

@@ -3,7 +3,7 @@
import { Habit } from '@/lib/types'
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { useSettings } from '@/hooks/useSettings'
import { getDateInTimezone } from '@/lib/utils'
import { d2s, getNow } from '@/lib/utils'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'
interface HabitStreakProps {
@@ -12,20 +12,21 @@ interface HabitStreakProps {
export default function HabitStreak({ habits }: HabitStreakProps) {
const { settings } = useSettings()
// Get the last 30 days of data
const dates = Array.from({ length: 30 }, (_, i) => {
const d = getDateInTimezone(new Date(), settings.system.timezone)
d.setDate(d.getDate() - i)
return d.toISOString().split('T')[0]
// Get the last 7 days of data
const dates = Array.from({ length: 7 }, (_, i) => {
const d = getNow({ timezone: settings.system.timezone });
return d2s({ dateTime: d.minus({ days: i }), format: 'yyyy-MM-dd' });
}).reverse()
// Count completed habits per day
const completions = dates.map(date => ({
date: new Date(date).toLocaleDateString(),
completed: habits.filter(habit =>
habit.completions.includes(date)
).length
}))
const completions = dates.map(date => {
const completedCount = habits.reduce((count, habit) => {
return count + (habit.completions.includes(date) ? 1 : 0);
}, 0);
return {
date,
completed: completedCount
};
});
return (
<Card>