refactor: better shortcut hook
This commit is contained in:
72
packages/ui/src/budget.tsx
Normal file
72
packages/ui/src/budget.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { use } from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import { RouterContext } from ".";
|
||||
import { queries, type Mutators, type Schema } from "@money/shared";
|
||||
import { useQuery, useZero } from "@rocicorp/zero/react";
|
||||
import * as Table from "../components/Table";
|
||||
import { Button } from "../components/Button";
|
||||
|
||||
const COLUMNS: Table.Column[] = [{ name: "label", label: "Name" }];
|
||||
|
||||
export function Budget() {
|
||||
const { auth } = use(RouterContext);
|
||||
const [budgets] = useQuery(queries.getBudgets(auth));
|
||||
// const [items] = useQuery(queries.getBudgetCategories(auth));
|
||||
|
||||
const items: any[] = [];
|
||||
|
||||
const z = useZero<Schema, Mutators>();
|
||||
|
||||
const newBudget = () => {
|
||||
const id = new Date().getTime().toString();
|
||||
z.mutate.budget.create({
|
||||
id,
|
||||
});
|
||||
};
|
||||
|
||||
if (budgets.length == 0)
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flex: 1,
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontFamily: "mono" }}>
|
||||
No budgets, please create a new budget
|
||||
</Text>
|
||||
<Button onPress={newBudget} shortcut="n">
|
||||
New budget
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
|
||||
const budget = budgets[0]!;
|
||||
|
||||
return (
|
||||
<>
|
||||
<View>
|
||||
<Text style={{ fontFamily: "mono" }}>
|
||||
Selected Budget: {budget.label}
|
||||
</Text>
|
||||
</View>
|
||||
<Table.Provider
|
||||
data={items}
|
||||
columns={COLUMNS}
|
||||
onKey={(event) => {
|
||||
if (event.name == "n" && event.shift) {
|
||||
newBudget();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ flexShrink: 0 }}>
|
||||
<Table.Body />
|
||||
</View>
|
||||
</View>
|
||||
</Table.Provider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +1,24 @@
|
||||
import { createContext, use } from "react";
|
||||
import { createContext, use, useEffect, useRef } from "react";
|
||||
import { Transactions } from "./transactions";
|
||||
import { View, Text } from "react-native";
|
||||
import { View } from "react-native";
|
||||
import { Settings } from "./settings";
|
||||
import { useKeyboard } from "./useKeyboard";
|
||||
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: "2",
|
||||
key: "3",
|
||||
children: {
|
||||
"/accounts": {},
|
||||
"/family": {},
|
||||
@@ -59,7 +65,10 @@ type AppProps = {
|
||||
export function App({ auth, route, setRoute }: AppProps) {
|
||||
return (
|
||||
<RouterContext.Provider value={{ auth, route, setRoute }}>
|
||||
<Main />
|
||||
<ShortcutProvider>
|
||||
<ShortcutDebug />
|
||||
<Main />
|
||||
</ShortcutProvider>
|
||||
</RouterContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -67,17 +76,9 @@ export function App({ auth, route, setRoute }: AppProps) {
|
||||
function Main() {
|
||||
const { route, setRoute } = use(RouterContext);
|
||||
|
||||
useKeyboard((key) => {
|
||||
const screen = Object.entries(PAGES).find(
|
||||
([, screen]) => screen.key == key.name,
|
||||
);
|
||||
|
||||
if (!screen) return;
|
||||
|
||||
const [route] = screen as [Route, never];
|
||||
|
||||
setRoute(route);
|
||||
});
|
||||
for (const [route, page] of Object.entries(PAGES)) {
|
||||
useShortcut(page.key, () => setRoute(route as Route));
|
||||
}
|
||||
|
||||
const match =
|
||||
route in PAGES
|
||||
|
||||
@@ -4,8 +4,6 @@ import { RouterContext, type Route } from ".";
|
||||
import { General } from "./settings/general";
|
||||
import { Accounts } from "./settings/accounts";
|
||||
import { Family } from "./settings/family";
|
||||
import { useKeyboard } from "./useKeyboard";
|
||||
import { Modal } from "react-native-opentui";
|
||||
|
||||
type SettingsRoute = Extract<Route, `/settings${string}`>;
|
||||
|
||||
@@ -32,28 +30,27 @@ type Tab = keyof typeof TABS;
|
||||
export function Settings() {
|
||||
const { route, setRoute } = use(RouterContext);
|
||||
|
||||
useKeyboard(
|
||||
(key) => {
|
||||
if (key.name == "h") {
|
||||
const currentIdx = Object.entries(TABS).findIndex(
|
||||
([tabRoute, _]) => tabRoute == route,
|
||||
);
|
||||
const routes = Object.keys(TABS) as SettingsRoute[];
|
||||
const last = routes[currentIdx - 1];
|
||||
if (!last) return;
|
||||
setRoute(last);
|
||||
} else if (key.name == "l") {
|
||||
const currentIdx = Object.entries(TABS).findIndex(
|
||||
([tabRoute, _]) => tabRoute == route,
|
||||
);
|
||||
const routes = Object.keys(TABS) as SettingsRoute[];
|
||||
const next = routes[currentIdx + 1];
|
||||
if (!next) return;
|
||||
setRoute(next);
|
||||
}
|
||||
},
|
||||
[route],
|
||||
);
|
||||
// useKeyboard(
|
||||
// (key) => {
|
||||
// if (key.name == "h") {
|
||||
// const currentIdx = Object.entries(TABS).findIndex(
|
||||
// ([tabRoute, _]) => tabRoute == route,
|
||||
// );
|
||||
// const routes = Object.keys(TABS) as SettingsRoute[];
|
||||
// const last = routes[currentIdx - 1];
|
||||
// if (!last) return;
|
||||
// setRoute(last);
|
||||
// } else if (key.name == "l") {
|
||||
// const currentIdx = Object.entries(TABS).findIndex(
|
||||
// ([tabRoute, _]) => tabRoute == route,
|
||||
// );
|
||||
// const routes = Object.keys(TABS) as SettingsRoute[];
|
||||
// const next = routes[currentIdx + 1];
|
||||
// if (!next) return;
|
||||
// setRoute(next);
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
|
||||
return (
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { queries, type Mutators, type Schema } from "@money/shared";
|
||||
import { use, useEffect, useState } from "react";
|
||||
import { RouterContext } from "..";
|
||||
import { View, Text, Linking } from "react-native";
|
||||
import { useKeyboard } from "../useKeyboard";
|
||||
import { Button } from "../../components/Button";
|
||||
import * as Table from "../../components/Table";
|
||||
import * as Dialog from "../../components/Dialog";
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { useKeyboard as useOpentuiKeyboard } from "@opentui/react";
|
||||
|
||||
export function useKeyboard(
|
||||
handler: Parameters<typeof useOpentuiKeyboard>[0],
|
||||
_deps: any[] = [],
|
||||
) {
|
||||
return useOpentuiKeyboard(handler);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { useEffect } from "react";
|
||||
import type { KeyboardEvent } from "react";
|
||||
import type { KeyEvent } from "@opentui/core";
|
||||
|
||||
function convertName(keyName: string): string {
|
||||
const result = keyName.toLowerCase();
|
||||
if (result == "arrowdown") return "down";
|
||||
if (result == "arrowup") return "up";
|
||||
return result;
|
||||
}
|
||||
|
||||
export function useKeyboard(
|
||||
handler: (key: KeyEvent) => void,
|
||||
deps: any[] = [],
|
||||
) {
|
||||
useEffect(() => {
|
||||
const handlerWeb = (event: KeyboardEvent) => {
|
||||
// @ts-ignore
|
||||
handler({
|
||||
name: convertName(event.key),
|
||||
ctrl: event.ctrlKey,
|
||||
meta: event.metaKey,
|
||||
shift: event.shiftKey,
|
||||
option: event.metaKey,
|
||||
sequence: "",
|
||||
number: false,
|
||||
raw: "",
|
||||
eventType: "press",
|
||||
source: "raw",
|
||||
code: event.code,
|
||||
super: false,
|
||||
hyper: false,
|
||||
capsLock: false,
|
||||
numLock: false,
|
||||
baseCode: event.keyCode,
|
||||
preventDefault: () => event.preventDefault(),
|
||||
});
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
window.addEventListener("keydown", handlerWeb);
|
||||
return () => {
|
||||
// @ts-ignore
|
||||
window.removeEventListener("keydown", handlerWeb);
|
||||
};
|
||||
}, deps);
|
||||
}
|
||||
Reference in New Issue
Block a user