mirror of
https://github.com/ManInDark/HabitTrove.git
synced 2026-01-20 22:24:28 +01:00
Added jotai (#14)
* Added jotai * cache settings by using jotai state * use hydrateAtom with SSR * remove useSettings * fix test
This commit is contained in:
@@ -17,7 +17,6 @@ export default function ChangelogModal({ isOpen, onClose }: ChangelogModalProps)
|
||||
if (isOpen) {
|
||||
const loadChangelog = async () => {
|
||||
const content = await getChangelog()
|
||||
console.log(content)
|
||||
setChangelog(content)
|
||||
}
|
||||
loadChangelog()
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Coins } from 'lucide-react'
|
||||
import { formatNumber } from '@/lib/utils/formatNumber'
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
|
||||
export default function CoinBalance({ coinBalance }: { coinBalance: number }) {
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { t2d, d2s, getNow, isSameDate } from '@/lib/utils'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { formatNumber } from '@/lib/utils/formatNumber'
|
||||
@@ -12,10 +11,12 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { toast } from '@/hooks/use-toast'
|
||||
import { useCoins } from '@/hooks/useCoins'
|
||||
import Link from 'next/link'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
|
||||
export default function CoinsManager() {
|
||||
const { balance, transactions, addAmount, removeAmount } = useCoins()
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
const DEFAULT_AMOUNT = '0'
|
||||
const [amount, setAmount] = useState(DEFAULT_AMOUNT)
|
||||
|
||||
@@ -212,7 +213,7 @@ export default function CoinsManager() {
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">
|
||||
{d2s({ dateTime: t2d({ timestamp: transaction.timestamp, timezone: settings.system.timezone }) })}
|
||||
{d2s({ dateTime: t2d({ timestamp: transaction.timestamp, timezone: settings.system.timezone }), timezone: settings.system.timezone })}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Circle, Coins, ArrowRight, CircleCheck, ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
import { getTodayInTimezone } from '@/lib/utils'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
@@ -24,7 +25,7 @@ export default function DailyOverview({
|
||||
onComplete,
|
||||
onUndo
|
||||
}: UpcomingItemsProps) {
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
const today = getTodayInTimezone(settings.system.timezone)
|
||||
const todayCompletions = habits.filter(habit =>
|
||||
habit.completions.includes(today)
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { DateTime } from 'luxon'
|
||||
import { d2s } from '@/lib/utils'
|
||||
import { d2s, getNow } from '@/lib/utils'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
|
||||
interface DynamicTimeProps {
|
||||
timezone: string
|
||||
}
|
||||
|
||||
export function DynamicTime({ timezone }: DynamicTimeProps) {
|
||||
const [time, setTime] = useState(DateTime.now().setZone(timezone))
|
||||
export function DynamicTime() {
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
const [time, setTime] = useState<DateTime>(getNow({ timezone: settings.system.timezone }))
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
@@ -21,7 +24,7 @@ export function DynamicTime({ timezone }: DynamicTimeProps) {
|
||||
|
||||
return (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{d2s({ dateTime: time })}
|
||||
{d2s({ dateTime: time, timezone: settings.system.timezone })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,11 +8,12 @@ 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 { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
import { DateTime } from 'luxon'
|
||||
|
||||
export default function HabitCalendar() {
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
const [selectedDate, setSelectedDate] = useState<DateTime>(getNow({ timezone: settings.system.timezone }))
|
||||
const [habits, setHabits] = useState<Habit[]>([])
|
||||
|
||||
@@ -20,12 +21,6 @@ export default function HabitCalendar() {
|
||||
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)
|
||||
@@ -50,7 +45,7 @@ export default function HabitCalendar() {
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={selectedDate.toJSDate()}
|
||||
onSelect={(e) => e && setSelectedDate(DateTime.fromJSDate(e))}
|
||||
// onSelect={(e) => e && setSelectedDate(DateTime.fromJSDate(e))}
|
||||
className="rounded-md border"
|
||||
modifiers={{
|
||||
completed: (date) => getHabitsForDate(date).length > 0,
|
||||
@@ -65,7 +60,7 @@ export default function HabitCalendar() {
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
{selectedDate ? (
|
||||
<>Habits for {d2s({ dateTime: selectedDate })}</>
|
||||
<>Habits for {d2s({ dateTime: selectedDate, timezone: settings.system.timezone })}</>
|
||||
) : (
|
||||
'Select a date'
|
||||
)}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import HeatMap from '@uiw/react-heat-map'
|
||||
import { Habit } from '@/lib/types'
|
||||
import { getNow } from '@/lib/utils'
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
|
||||
interface HabitHeatmapProps {
|
||||
habits: Habit[]
|
||||
@@ -26,7 +27,7 @@ export default function HabitHeatmap({ habits }: HabitHeatmapProps) {
|
||||
count
|
||||
}))
|
||||
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
|
||||
// Get start date (30 days ago)
|
||||
const now = getNow({ timezone: settings.system.timezone })
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Habit } from '@/lib/types'
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
import { getTodayInTimezone } from '@/lib/utils'
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -15,7 +16,7 @@ interface HabitItemProps {
|
||||
}
|
||||
|
||||
export default function HabitItem({ habit, onEdit, onDelete, onComplete, onUndo }: HabitItemProps) {
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
const today = getTodayInTimezone(settings.system.timezone)
|
||||
const isCompletedToday = habit.completions?.includes(today)
|
||||
const [isHighlighted, setIsHighlighted] = useState(false)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { BarChart } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { getTodayInTimezone } from '@/lib/utils'
|
||||
import { loadHabitsData } from '@/app/actions/data'
|
||||
import { Habit } from '@/lib/types'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
|
||||
export default function HabitOverview() {
|
||||
const [habits, setHabits] = useState<Habit[]>([])
|
||||
@@ -17,7 +18,7 @@ export default function HabitOverview() {
|
||||
fetchHabits()
|
||||
}, [])
|
||||
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
const today = getTodayInTimezone(settings.system.timezone)
|
||||
|
||||
const completedToday = habits.filter(habit =>
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
|
||||
import { Habit } from '@/lib/types'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
import { d2s, getNow } from '@/lib/utils'
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'
|
||||
import { useAtom } from 'jotai'
|
||||
import { settingsAtom } from '@/lib/atoms'
|
||||
|
||||
interface HabitStreakProps {
|
||||
habits: Habit[]
|
||||
}
|
||||
|
||||
export default function HabitStreak({ habits }: HabitStreakProps) {
|
||||
const { settings } = useSettings()
|
||||
const [settings] = useAtom(settingsAtom)
|
||||
// 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' });
|
||||
return d2s({ dateTime: d.minus({ days: i }), format: 'yyyy-MM-dd', timezone: settings.system.timezone });
|
||||
}).reverse()
|
||||
|
||||
const completions = dates.map(date => {
|
||||
|
||||
16
components/jotai-hydrate.tsx
Normal file
16
components/jotai-hydrate.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
'use client'
|
||||
|
||||
import { settingsAtom } from "@/lib/atoms"
|
||||
import { useHydrateAtoms } from "jotai/utils"
|
||||
import { Settings } from "@/lib/types"
|
||||
|
||||
export function JotaiHydrate({
|
||||
children,
|
||||
initialSettings
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
initialSettings: Settings
|
||||
}) {
|
||||
useHydrateAtoms([[settingsAtom, initialSettings]])
|
||||
return children
|
||||
}
|
||||
11
components/jotai-providers.tsx
Normal file
11
components/jotai-providers.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { Provider } from 'jotai'
|
||||
|
||||
export const JotaiProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<Provider>
|
||||
{children}
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user