Production deployment setup + feature complete

- Dockerfile + deploy.sh for Hetzner server
- Email verification via Better Auth + Resend
- Invite code flow (6-digit OTP, generate/join)
- Settlement share percent fix (payer vs debtor)
- OCR scanner fixes (date display, retry, viewfinder)
- app.json icon/splash/adaptive-icon configured
- iOS deployment target 15.5 (ML Kit requirement)
- DB migration 0014: household_invitations table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
René Schober
2026-03-20 11:54:22 +01:00
parent 4e34270786
commit 9ddc7c6d7a
194 changed files with 55961 additions and 305 deletions

View File

@@ -1,55 +1,28 @@
import React, { createContext, useCallback, useContext, useMemo } from "react";
import { Uniwind, useUniwind } from "uniwind";
import { createContext, useContext, useState, useEffect } from "react";
import { Appearance } from "react-native";
import { Uniwind } from "uniwind";
type ThemeName = "light" | "dark";
type AppThemeContextType = { themeName: string };
type AppThemeContextType = {
currentTheme: string;
isLight: boolean;
isDark: boolean;
setTheme: (theme: ThemeName) => void;
toggleTheme: () => void;
};
const AppThemeContext = createContext<AppThemeContextType | undefined>(undefined);
const AppThemeContext = createContext<AppThemeContextType>({ themeName: "light" });
export const AppThemeProvider = ({ children }: { children: React.ReactNode }) => {
const { theme } = useUniwind();
const isLight = useMemo(() => {
return theme === "light";
}, [theme]);
const isDark = useMemo(() => {
return theme === "dark";
}, [theme]);
const setTheme = useCallback((newTheme: ThemeName) => {
Uniwind.setTheme(newTheme);
}, []);
const toggleTheme = useCallback(() => {
Uniwind.setTheme(theme === "light" ? "dark" : "light");
}, [theme]);
const value = useMemo(
() => ({
currentTheme: theme,
isLight,
isDark,
setTheme,
toggleTheme,
}),
[theme, isLight, isDark, setTheme, toggleTheme],
const [themeName, setThemeName] = useState<string>(
() => Uniwind.currentTheme ?? "light",
);
return <AppThemeContext.Provider value={value}>{children}</AppThemeContext.Provider>;
useEffect(() => {
const sub = Appearance.addChangeListener(({ colorScheme }) => {
setThemeName(colorScheme ?? "light");
});
return () => sub.remove();
}, []);
return (
<AppThemeContext.Provider value={{ themeName }}>
{children}
</AppThemeContext.Provider>
);
};
export function useAppTheme() {
const context = useContext(AppThemeContext);
if (!context) {
throw new Error("useAppTheme must be used within AppThemeProvider");
}
return context;
}
export const useAppTheme = () => useContext(AppThemeContext);