Skip to content

Commit

Permalink
chore: refactor pages
Browse files Browse the repository at this point in the history
  • Loading branch information
jedwards1230 committed Apr 23, 2024
1 parent 2f84793 commit 5cbf5dd
Show file tree
Hide file tree
Showing 81 changed files with 2,077 additions and 1,707 deletions.
55 changes: 52 additions & 3 deletions client/src/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,62 @@
import { Redirect } from "expo-router";
import { Redirect, withLayoutContext } from "expo-router";
import {
createDrawerNavigator,
DrawerContentComponentProps,
type DrawerNavigationOptions,
} from "@react-navigation/drawer";
import { Platform } from "react-native";
import { useEffect } from "react";

import Drawer from "@/components/DrawerNav/Drawer";
import { useUserData } from "@/hooks/stores/useUserData";
import { useBreakpoints } from "@/hooks/useBreakpoints";
import ThreadHistory from "@/components/ThreadDrawer/ThreadHistory";
import NativeSafeAreaView from "@/components/NativeSafeAreaView";

export const Drawer = withLayoutContext(createDrawerNavigator().Navigator);

export default function HomeLayout() {
const session = useUserData.use.session();
const bp = useBreakpoints();

const screenOptions: DrawerNavigationOptions = {
drawerType: "slide",
drawerPosition: "left",
headerShown: false,
// TODO: "rgba(0, 0, 0, 0.5)" | "rgba(255, 255, 255, 0.1)"
overlayColor: Platform.OS === "web" ? "transparent" : "rgba(0, 0, 0, 0.5)",
drawerStyle: { ...(Platform.OS === "web" && bp.md && { width: 300 }) },
};

if (!session) return <Redirect href={{ pathname: "/(auth)" }} />;
return <Drawer />;
return (
<Drawer
defaultStatus={Platform.OS === "web" && bp.md ? "open" : "closed"}
drawerContent={(p) => <DrawerContent {...p} />}
screenOptions={screenOptions}
initialRouteName="index"
/>
);
}

function DrawerContent(props: DrawerContentComponentProps) {
const { md } = useBreakpoints();

useEffect(() => {
if (Platform.OS === "web" && md) {
props.navigation.openDrawer();
} else {
props.navigation.closeDrawer();
}
}, [md]);

return (
<NativeSafeAreaView
className="flex-1 border-r-0 bg-secondary text-foreground"
{...props}
>
<ThreadHistory />
</NativeSafeAreaView>
);
}

export { ErrorBoundary } from "expo-router";
7 changes: 7 additions & 0 deletions client/src/app/(app)/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SettingsView } from "@/views/settings/SettingsView";

export default function SettingsPage() {
return <SettingsView />;
}

export { ErrorBoundary } from "expo-router";
7 changes: 7 additions & 0 deletions client/src/app/(app)/tools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ToolView } from "@/views/tools/ToolView";

export default function Tools() {
return <ToolView />;
}

export { ErrorBoundary } from "expo-router";
22 changes: 11 additions & 11 deletions client/src/app/+not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { View } from "react-native";
import { Text } from "@/components/ui/Text";

export default function NotFoundScreen() {
return (
<>
<Stack.Screen options={{ title: "Oops!" }} />
<View className="flex items-center justify-center flex-1 p-4">
<Text className="text-2xl font-bold">This screen doesn't exist.</Text>
return (
<>
<Stack.Screen options={{ title: "Oops!" }} />
<View className="flex items-center justify-center flex-1 p-4 bg-background text-foreground">
<Text className="text-2xl font-bold">This screen doesn't exist.</Text>

<Link className="py-4 mt-4" href="/">
<Text className="text-[#2e78b7]">Go to home screen!</Text>
</Link>
</View>
</>
);
<Link className="py-4 mt-4" href="/">
<Text className="text-[#2e78b7]">Go to home screen!</Text>
</Link>
</View>
</>
);
}
118 changes: 59 additions & 59 deletions client/src/components/ChatHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,76 @@ import { NativeScrollEvent, NativeSyntheticEvent, ScrollView, View } from "react
import { useEffect, useRef, useState } from "react";

import { Button } from "@/components/ui/Button";
import { AntDesign } from "@/components/ui/Icon";
import { Icon } from "@/components/ui/Icon";
import {
MessageGroup,
useGroupedMessages,
MessageGroup,
useGroupedMessages,
} from "@/components/MessageGroups/MessageGroup";

export default function ChatHistory({
isLoading,
threadId,
isLoading,
threadId,
}: {
isLoading: boolean;
threadId: string;
isLoading: boolean;
threadId: string;
}) {
const viewRef = useRef<View>(null);
const scrollViewRef = useRef<ScrollView>(null);
const [showScrollButton, setShowScrollButton] = useState(false);
const { messageGroups, isError } = useGroupedMessages(threadId);
const viewRef = useRef<View>(null);
const scrollViewRef = useRef<ScrollView>(null);
const [showScrollButton, setShowScrollButton] = useState(false);
const { messageGroups, isError } = useGroupedMessages(threadId);

const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent;
const isCloseToBottom =
contentOffset.y + layoutMeasurement.height > contentSize.height - 50;
setShowScrollButton(!isCloseToBottom);
};
const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent;
const isCloseToBottom =
contentOffset.y + layoutMeasurement.height > contentSize.height - 50;
setShowScrollButton(!isCloseToBottom);
};

const scrollToBottom = () =>
messageGroups.length > 0 &&
scrollViewRef.current?.scrollToEnd({ animated: true });
const scrollToBottom = () =>
messageGroups.length > 0 &&
scrollViewRef.current?.scrollToEnd({ animated: true });

useEffect(() => {
if (!viewRef.current) return;
viewRef.current.measure((x, y, width, height) => {
if (height > 0) scrollToBottom();
});
}, []);
useEffect(() => {
if (!viewRef.current) return;
viewRef.current.measure((x, y, width, height) => {
if (height > 0) scrollToBottom();
});
}, []);

if (isError) return null;
return (
<View ref={viewRef} className="relative flex flex-1 w-full gap-4">
{messageGroups.length > 0 && (
<ScrollView
ref={scrollViewRef}
onScroll={onScroll}
scrollEventThrottle={50}
className="scroll-smooth"
>
{messageGroups.map((item, index) => (
<MessageGroup
key={index.toString()}
item={item}
index={index}
isLoading={isLoading}
messageGroups={messageGroups}
/>
))}
</ScrollView>
)}
{showScrollButton && (
<View className="absolute left-0 right-0 flex items-center bottom-4">
<ScrollButton onPress={scrollToBottom} />
</View>
)}
</View>
);
if (isError) return null;
return (
<View ref={viewRef} className="relative flex flex-1 w-full gap-4">
{messageGroups.length > 0 && (
<ScrollView
ref={scrollViewRef}
onScroll={onScroll}
scrollEventThrottle={50}
className="scroll-smooth"
>
{messageGroups.map((item, index) => (
<MessageGroup
key={index.toString()}
item={item}
index={index}
isLoading={isLoading}
messageGroups={messageGroups}
/>
))}
</ScrollView>
)}
{showScrollButton && (
<View className="absolute left-0 right-0 flex items-center bottom-4">
<ScrollButton onPress={scrollToBottom} />
</View>
)}
</View>
);
}

function ScrollButton({ onPress }: { onPress: () => void }) {
return (
<Button variant="outline" size="icon" onPress={onPress} className="rounded-full">
<AntDesign name="down" size={18} className="text-foreground/90" />
</Button>
);
return (
<Button variant="outline" size="icon" onPress={onPress} className="rounded-full">
<Icon type="AntDesign" name="down" size={18} className="text-foreground/90" />
</Button>
);
}
128 changes: 64 additions & 64 deletions client/src/components/ChatInput/ChatInputContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,83 +2,83 @@ import { Platform, Pressable, View } from "react-native";
import { useEffect, useState } from "react";

import { FormSubmission } from "@/hooks/useChat";
import { MaterialIcons } from "@/components/ui/Icon";
import { Icon } from "@/components/ui/Icon";
import ChatInput from "./ChatInput";
import { CommandTray } from "../CommandTray";
import { FileTray, FileInputButton } from "../FileTray";

export function ChatInputContainer({
handleSubmit,
abort,
loading = false,
threadId,
handleSubmit,
abort,
loading = false,
threadId,
}: {
handleSubmit: FormSubmission;
abort: () => void;
loading?: boolean;
threadId: string | null;
handleSubmit: FormSubmission;
abort: () => void;
loading?: boolean;
threadId: string | null;
}) {
const [input, setInput] = useState("");
useEffect(() => setInput(""), [threadId]);
const [input, setInput] = useState("");
useEffect(() => setInput(""), [threadId]);

const handleSend = async () => {
try {
await handleSubmit(input);
setInput("");
} catch (error) {
alert(error);
}
};
const handleSend = async () => {
try {
await handleSubmit(input);
setInput("");
} catch (error) {
alert(error);
}
};

return (
<View className="w-full px-2 pt-2 web:mb-2">
<View className="relative flex flex-col items-center justify-between w-full px-1 mt-2 mb-2 border border-2 border-input rounded-xl web:mx-auto md:max-w-[90%] lg:max-w-[75%]">
<FileTray />
<CommandTray input={input} />
<View className="flex flex-row items-center justify-between w-full pl-2 pr-2 web:pr-10">
<ChatInput
threadId={threadId}
input={input}
setInput={setInput}
handleSubmit={handleSend}
/>
<FileInputButton />
{loading ? (
<StopButton abort={abort} />
) : (
<SendButton handleSend={handleSend} />
)}
</View>
</View>
</View>
);
return (
<View className="w-full px-2 pt-2 web:mb-2">
<View className="relative flex flex-col items-center justify-between w-full px-1 mt-2 mb-2 border border-2 border-input rounded-xl web:mx-auto md:max-w-[90%] lg:max-w-[75%]">
<FileTray />
<CommandTray input={input} />
<View className="flex flex-row items-center justify-between w-full pl-2 pr-2 web:pr-10">
<ChatInput
threadId={threadId}
input={input}
setInput={setInput}
handleSubmit={handleSend}
/>
<FileInputButton />
{loading ? (
<StopButton abort={abort} />
) : (
<SendButton handleSend={handleSend} />
)}
</View>
</View>
</View>
);
}

function SendButton({ handleSend }: { handleSend: () => void }) {
return (
<Pressable
onPress={handleSend}
className="absolute right-0 p-1 bg-transparent rounded-full web:right-2"
>
<MaterialIcons
name={Platform.select({
web: "keyboard-arrow-up",
default: "chevron-right",
})}
size={22}
className="text-foreground"
/>
</Pressable>
);
return (
<Pressable
onPress={handleSend}
className="absolute right-0 p-1 bg-transparent rounded-full web:right-2"
>
<Icon
type="MaterialIcons"
name={Platform.select({
web: "keyboard-arrow-up",
default: "chevron-right",
})}
size={22}
/>
</Pressable>
);
}

function StopButton({ abort }: { abort: () => void }) {
return (
<Pressable
onPress={abort}
className="absolute right-0 p-1 bg-transparent rounded-full web:right-2"
>
<MaterialIcons name="stop" size={22} className="text-foreground" />
</Pressable>
);
return (
<Pressable
onPress={abort}
className="absolute right-0 p-1 bg-transparent rounded-full web:right-2"
>
<Icon type="MaterialIcons" name="stop" size={22} />
</Pressable>
);
}
Loading

0 comments on commit 5cbf5dd

Please sign in to comment.