feat: add ui
This commit is contained in:
@@ -4,6 +4,7 @@ import { useQuery, useZero } from "@rocicorp/zero/react";
|
||||
import { queries, type Mutators, type Schema } from '@money/shared';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'expo-router';
|
||||
import Header from '@/components/Header';
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { data: session } = authClient.useSession();
|
||||
@@ -68,9 +69,7 @@ export default function HomeScreen() {
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Link prefetch href="/settings">
|
||||
<Button title="Settings" />
|
||||
</Link>
|
||||
<Header />
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<View style={{ backgroundColor: '' }}>
|
||||
{balances.map((bal, i) => <View key={bal.id} style={{ backgroundColor: i == accountIdx ? 'black' : undefined}}>
|
||||
|
||||
129
app/settings.tsx
129
app/settings.tsx
@@ -1,8 +1,10 @@
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { authClient } from '@/lib/auth-client';
|
||||
import { Button, Linking, Text } from 'react-native';
|
||||
import { Button, Linking, Platform, Pressable, Text, View } from 'react-native';
|
||||
import { useQuery, useZero } from "@rocicorp/zero/react";
|
||||
import { queries, type Mutators, type Schema } from '@money/shared';
|
||||
import Header from '@/components/Header';
|
||||
import { useEffect, useState, type ReactNode } from 'react';
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { data: session } = authClient.useSession();
|
||||
@@ -11,31 +13,118 @@ export default function HomeScreen() {
|
||||
authClient.signOut();
|
||||
}
|
||||
const z = useZero<Schema, Mutators>();
|
||||
const [user] = useQuery(queries.me(session));
|
||||
const [plaidLink] = useQuery(queries.getPlaidLink(session));
|
||||
const [items] = useQuery(queries.getItems(session));
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Text>Hello {user?.name}</Text>
|
||||
<Button onPress={onLogout} title="Logout" />
|
||||
<Header />
|
||||
|
||||
<Text>{JSON.stringify(plaidLink)}</Text>
|
||||
{plaidLink ? <Button onPress={() => {
|
||||
Linking.openURL(plaidLink.link);
|
||||
}} title="Open Plaid" /> : <Text>No plaid link</Text>}
|
||||
|
||||
<Button onPress={() => {
|
||||
z.mutate.link.create();
|
||||
}} title="Generate Link" />
|
||||
|
||||
{plaidLink && <Button onPress={() => {
|
||||
z.mutate.link.get({ link_token: plaidLink.token });
|
||||
}} title="Check Link" />}
|
||||
|
||||
{plaidLink && <Button onPress={() => {
|
||||
z.mutate.link.updateTransactions();
|
||||
}} title="Update transactions" />}
|
||||
<UI
|
||||
columns={[
|
||||
{
|
||||
name: "Banks",
|
||||
items: items,
|
||||
renderItem: (item, props) => <Row {...props}>{item.name}</Row>
|
||||
},
|
||||
{
|
||||
name: "Family",
|
||||
items: [],
|
||||
renderItem() {
|
||||
return <View></View>;
|
||||
},
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
type Col<T> = {
|
||||
name: string;
|
||||
items: T[];
|
||||
renderItem: (item: T, props: { isSelected: boolean, isActive: boolean }) => ReactNode;
|
||||
}
|
||||
|
||||
type State = {
|
||||
idx: number;
|
||||
columns: Map<number, State>;
|
||||
};
|
||||
|
||||
function UI({ columns }: { columns: Col<any>[] }) {
|
||||
const [col, setCol] = useState(0);
|
||||
const [state, setState] = useState<State>({
|
||||
idx: 0,
|
||||
columns: new Map(
|
||||
Array.from({ length: columns.length })
|
||||
.map((_, i) => ([i, { idx: 0, columns: new Map() }]))
|
||||
)
|
||||
});
|
||||
|
||||
const getColState = (res: State): State => {
|
||||
let i = col;
|
||||
while (i > 0) {
|
||||
res = res.columns.get(res.idx)!;
|
||||
i--;
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
const colState = getColState(state);
|
||||
|
||||
const curr = columns.at(col)!;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (Platform.OS != 'web') return;
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "j") {
|
||||
setState((prev) => {
|
||||
if (prev.idx + 1 == colState.columns.size) return prev;
|
||||
return {...prev, ...{ idx: prev.idx + 1 }};
|
||||
});
|
||||
} else if (event.key === "k") {
|
||||
setState((prev) => {
|
||||
if (prev.idx == 0) return prev;
|
||||
return {...prev, ...{ idx: prev.idx - 1 }};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<Column>
|
||||
{columns.map((c, i) => <Pressable onPress={() => { setCol(i) }}><Row isSelected={col == i} isActive={col == 0}>{c.name}</Row></Pressable>)}
|
||||
</Column>
|
||||
<Column>
|
||||
{curr.items.map((item, i) => curr.renderItem(item, { isSelected: colState.idx == i, isActive: col == 1 }))}
|
||||
</Column>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function Column({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<View>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({ children, isSelected, isActive }: { children: ReactNode, isSelected: boolean, isActive: boolean }) {
|
||||
const color = isSelected ? 'white': undefined;
|
||||
const backgroundColor = isSelected ? (isActive ? 'black' : 'gray'): undefined;
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ fontFamily: 'mono', color, backgroundColor }}>{children}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user