Files
money/packages/ui/src/index.tsx
2025-12-05 17:05:23 -05:00

96 lines
2.2 KiB
TypeScript

import { createContext, use, useEffect, useRef } from "react";
import { Transactions } from "./transactions";
import { View } from "react-native";
import { Settings } from "./settings";
import type { AuthData } from "@money/shared/auth";
import { Budget } from "./budget";
import { ShortcutProvider, ShortcutDebug, keysStore } from "../lib/shortcuts";
import { useShortcut } from "../lib/shortcuts/hooks";
const PAGES = {
"/": {
screen: <Transactions />,
key: "1",
},
"/budget": {
screen: <Budget />,
key: "2",
},
"/settings": {
screen: <Settings />,
key: "3",
children: {
"/accounts": {},
"/family": {},
},
},
};
type Join<A extends string, B extends string> = `${A}${B}` extends `${infer X}`
? X
: never;
type ChildRoutes<Parent extends string, Children> = {
[K in keyof Children & string]: K extends `/${string}`
? Join<Parent, K>
: never;
}[keyof Children & string];
type Routes<T> = {
[K in keyof T & string]:
| K
| (T[K] extends { children: infer C } ? ChildRoutes<K, C> : never);
}[keyof T & string];
export type Route = Routes<typeof PAGES>;
interface RouterContextType {
auth: AuthData | null;
route: Route;
setRoute: (route: Route) => void;
}
export const RouterContext = createContext<RouterContextType>({
auth: null,
route: "/",
setRoute: () => {},
});
type AppProps = {
auth: AuthData | null;
route: Route;
setRoute: (page: Route) => void;
};
export function App({ auth, route, setRoute }: AppProps) {
return (
<RouterContext.Provider value={{ auth, route, setRoute }}>
<ShortcutProvider>
<ShortcutDebug />
<Main />
</ShortcutProvider>
</RouterContext.Provider>
);
}
function Main() {
const { route, setRoute } = use(RouterContext);
for (const [route, page] of Object.entries(PAGES)) {
useShortcut(page.key, () => setRoute(route as Route));
}
const match =
route in PAGES
? (route as keyof typeof PAGES)
: (Object.keys(PAGES)
.sort((a, b) => b.length - a.length)
.find((p) => route.startsWith(p)) as keyof typeof PAGES);
return (
<View style={{ backgroundColor: "white", flex: 1 }}>
{PAGES[match].screen}
</View>
);
}