Files
birthday/apk/context/birthdays-context.tsx

135 lines
2.9 KiB
TypeScript

import {
createContext,
ReactNode,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { syncBirthdayNotifications } from "@/utils/birthday-notifications";
export interface BirthdayEntry {
id: string;
name: string;
date: string;
}
interface AddBirthdayInput {
name: string;
date: string;
}
interface BirthdaysContextValue {
birthdays: BirthdayEntry[];
addBirthday: (input: AddBirthdayInput) => void;
deleteBirthday: (id: string) => void;
}
const STORAGE_KEY = "birthdays";
const BirthdaysContext = createContext<BirthdaysContextValue | undefined>(
undefined
);
export function BirthdaysProvider({ children }: { children: ReactNode }) {
const [birthdays, setBirthdays] = useState<BirthdayEntry[]>([]);
const [isLoaded, setIsLoaded] = useState(false);
// Load birthdays on app start from storage
useEffect(() => {
const loadBirthdays = async () => {
try {
const stored = await AsyncStorage.getItem(STORAGE_KEY);
if (stored) {
setBirthdays(JSON.parse(stored));
}
} catch(e) {
console.log("Error loading birthdays", e);
} finally {
setIsLoaded(true);
}
};
loadBirthdays();
}, []);
// Save birthdays whenever they change
useEffect(() => {
if (!isLoaded) return;
const saveBirthdays = async () => {
try {
await AsyncStorage.setItem(
STORAGE_KEY,
JSON.stringify(birthdays)
);
} catch(e) {
console.log("Error saving birthdays", e);
}
};
saveBirthdays();
}, [birthdays, isLoaded]);
useEffect(() => {
if (!isLoaded) {
return;
}
const synchronizeNotifications = async () => {
try {
await syncBirthdayNotifications(birthdays);
} catch (error) {
console.log("Error syncing birthday notifications", error);
}
};
synchronizeNotifications();
}, [birthdays, isLoaded]);
const value = useMemo(
() => ({
birthdays,
addBirthday: ({ name, date }: AddBirthdayInput) => {
const trimmedName = name.trim();
if (!trimmedName) {
return;
}
setBirthdays((currentBirthdays) => [
...currentBirthdays,
{
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
name: trimmedName,
date,
},
]);
},
deleteBirthday: (id: string) => {
setBirthdays((currentBirthdays) =>
currentBirthdays.filter((birthday) => birthday.id !== id)
);
},
}),
[birthdays]
);
return (
<BirthdaysContext.Provider value={value}>
{children}
</BirthdaysContext.Provider>
);
}
export function useBirthdays() {
const context = useContext(BirthdaysContext);
if (!context) {
throw new Error("useBirthdays must be used within a BirthdaysProvider");
}
return context;
}