diff --git a/app/actions/data.ts b/app/actions/data.ts index 5948946..a1316c4 100644 --- a/app/actions/data.ts +++ b/app/actions/data.ts @@ -76,7 +76,7 @@ async function loadData(type: DataType): Promise { await fs.access(filePath) } catch { // File doesn't exist, create it with default data - const initialData = getDefaultData(type) + const initialData = getDefaultData(type) await fs.writeFile(filePath, JSON.stringify(initialData, null, 2)) return initialData as T } @@ -136,7 +136,7 @@ async function calculateServerFreshnessToken(): Promise { // Wishlist specific functions export async function loadWishlistData(): Promise { const user = await getCurrentUser() - if (!user) return getDefaultWishlistData() + if (!user) return getDefaultWishlistData() const data = await loadData('wishlist') return { @@ -173,7 +173,7 @@ export async function saveWishlistItems(data: WishlistData): Promise { // Habits specific functions export async function loadHabitsData(): Promise { const user = await getCurrentUser() - if (!user) return getDefaultHabitsData() + if (!user) return getDefaultHabitsData() const data = await loadData('habits') return { habits: data.habits.filter(x => user.isAdmin || x.userIds?.includes(user.id)) @@ -208,14 +208,14 @@ export async function saveHabitsData(data: HabitsData): Promise { export async function loadCoinsData(): Promise { try { const user = await getCurrentUser() - if (!user) return getDefaultCoinsData() + if (!user) return getDefaultCoinsData() const data = await loadData('coins') return { ...data, transactions: user.isAdmin ? data.transactions : data.transactions.filter(x => x.userId === user.id) } } catch { - return getDefaultCoinsData() + return getDefaultCoinsData() } } @@ -278,7 +278,7 @@ export async function addCoins({ } export async function loadSettings(): Promise { - const defaultSettings = getDefaultSettings() + const defaultSettings = getDefaultSettings() try { const user = await getCurrentUser() @@ -370,7 +370,7 @@ export async function loadUsersData(): Promise { try { return await loadData('auth') } catch { - return getDefaultUsersData() + return getDefaultUsersData() } } diff --git a/lib/atoms.ts b/lib/atoms.ts index 750a5fa..423a127 100644 --- a/lib/atoms.ts +++ b/lib/atoms.ts @@ -16,6 +16,7 @@ import { atom } from "jotai"; import { atomFamily, atomWithStorage } from "jotai/utils"; import { DateTime } from "luxon"; import { + CoinsData, CompletionCache, Freq, getDefaultCoinsData, @@ -25,7 +26,12 @@ import { getDefaultUsersData, getDefaultWishlistData, Habit, - UserId + HabitsData, + ServerSettings, + Settings, + UserData, + UserId, + WishlistData } from "./types"; export interface BrowserSettings { @@ -40,12 +46,12 @@ export const browserSettingsAtom = atomWithStorage('browserSettings', { expandedWishlist: false } as BrowserSettings) -export const usersAtom = atom(getDefaultUsersData()) -export const settingsAtom = atom(getDefaultSettings()); -export const habitsAtom = atom(getDefaultHabitsData()); -export const coinsAtom = atom(getDefaultCoinsData()); -export const wishlistAtom = atom(getDefaultWishlistData()); -export const serverSettingsAtom = atom(getDefaultServerSettings()); +export const usersAtom = atom(getDefaultUsersData()) +export const settingsAtom = atom(getDefaultSettings()); +export const habitsAtom = atom(getDefaultHabitsData()); +export const coinsAtom = atom(getDefaultCoinsData()); +export const wishlistAtom = atom(getDefaultWishlistData()); +export const serverSettingsAtom = atom(getDefaultServerSettings()); // Derived atom for coins earned today export const coinsEarnedTodayAtom = atom((get) => { diff --git a/lib/types.ts b/lib/types.ts index 51462d6..dca59f3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -96,52 +96,58 @@ export interface WishlistData { } // Default value functions -export const getDefaultUsersData = (): UserData => ({ - users: [ - { - id: crypto.randomUUID(), - username: 'admin', - // password: '', // No default password for admin initially? Or set a secure default? - isAdmin: true, - lastNotificationReadTimestamp: undefined, // Initialize as undefined - } - ] -}); +export function getDefaultUsersData(): UserData { + return { + users: [ + { + id: crypto.randomUUID(), + username: 'admin', + // password: '', // No default password for admin initially? Or set a secure default? + isAdmin: true, + lastNotificationReadTimestamp: undefined, // Initialize as undefined + } + ] + } as UserData; +}; -export const getDefaultHabitsData = (): HabitsData => ({ - habits: [] -}); +export function getDefaultHabitsData(): HabitsData { + return { habits: [] } as HabitsData; +} +export function getDefaultTasksData(): TasksData { + return { tasks: [] } as TasksData; +}; -export const getDefaultCoinsData = (): CoinsData => ({ - balance: 0, - transactions: [] -}); +export function getDefaultCoinsData(): CoinsData { + return { balance: 0, transactions: [] } as CoinsData; +}; -export const getDefaultWishlistData = (): WishlistData => ({ - items: [] -}); +export function getDefaultWishlistData(): WishlistData { + return { items: [] } as WishlistData; +} -export const getDefaultSettings = (): Settings => ({ - ui: { - useNumberFormatting: true, - useGrouping: true, - }, - system: { - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - weekStartDay: 1, // Monday - autoBackupEnabled: true, // Add this line (default to true) - language: 'en', // Default language - }, - profile: {} -}); +export function getDefaultSettings(): Settings { + return { + ui: { + useNumberFormatting: true, + useGrouping: true, + }, + system: { + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + weekStartDay: 1, // Monday + autoBackupEnabled: true, // Add this line (default to true) + language: 'en', // Default language + }, + profile: {} + } as Settings; +}; -export const getDefaultServerSettings = (): ServerSettings => ({ - isDemo: false -}) +export function getDefaultServerSettings(): ServerSettings { + return { isDemo: false } as ServerSettings; +} // Map of data types to their default values -export const DATA_DEFAULTS = { +export const DATA_DEFAULTS: { [key: string]: () => T } = { wishlist: getDefaultWishlistData, habits: getDefaultHabitsData, coins: getDefaultCoinsData, diff --git a/lib/utils.test.ts b/lib/utils.test.ts index 21bdac7..f0eb222 100644 --- a/lib/utils.test.ts +++ b/lib/utils.test.ts @@ -942,11 +942,11 @@ describe('convertMachineReadableFrequencyToHumanReadable', () => { }) describe('freshness utilities', () => { - const mockSettings: Settings = getDefaultSettings(); - const mockHabits: HabitsData = getDefaultHabitsData(); - const mockCoins: CoinsData = getDefaultCoinsData(); - const mockWishlist: WishlistData = getDefaultWishlistData(); - const mockUsers: UserData = getDefaultUsersData(); + const mockSettings: Settings = getDefaultSettings(); + const mockHabits: HabitsData = getDefaultHabitsData(); + const mockCoins: CoinsData = getDefaultCoinsData(); + const mockWishlist: WishlistData = getDefaultWishlistData(); + const mockUsers: UserData = getDefaultUsersData(); // Add a user to mockUsers for more realistic testing mockUsers.users.push({ @@ -991,11 +991,11 @@ describe('freshness utilities', () => { }); test('should handle empty data consistently', () => { - const emptySettings = getDefaultSettings(); - const emptyHabits = getDefaultHabitsData(); - const emptyCoins = getDefaultCoinsData(); - const emptyWishlist = getDefaultWishlistData(); - const emptyUsers = getDefaultUsersData(); + const emptySettings = getDefaultSettings(); + const emptyHabits = getDefaultHabitsData(); + const emptyCoins = getDefaultCoinsData(); + const emptyWishlist = getDefaultWishlistData(); + const emptyUsers = getDefaultUsersData(); const string1 = prepareDataForHashing(emptySettings, emptyHabits, emptyCoins, emptyWishlist, emptyUsers); const string2 = prepareDataForHashing(emptySettings, emptyHabits, emptyCoins, emptyWishlist, emptyUsers);