Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes: Anonymous Chat UI, Navigation bug, UI consistency #291

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 18 additions & 27 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Route, Routes, useLocation } from "react-router-dom";
import { Route } from "react-router-dom";
import { Toaster } from "react-hot-toast";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import DashboardPage from "./pages/Dashboard";
Expand Down Expand Up @@ -29,7 +29,6 @@ import CustomSwitch from "./lib/custom-switch";
const queryClient = new QueryClient();

function App() {
const location = useLocation();
return (
<SettingsProvider>
<QueryClientProvider client={queryClient}>
Expand All @@ -44,33 +43,25 @@ function App() {
<Toaster />
<AnimatePresence mode="wait">
<CustomSwitch>
<Routes location={location} key={location.pathname}>
<Route path="*" element={<NotFound />} />
<Route path="/" element={<LandingPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignupPage />} />
<Route path="/anonymous" element={<AnonymousPage />} />
<Route path="*" element={<NotFound />} />
<Route path="/" element={<LandingPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignupPage />} />
<Route path="/anonymous" element={<AnonymousPage />} />

<Route element={<ProtectedRoute />}>
<Route path="/chatbot/:id" element={<ChatbotPage />} />
<Route path="/imagine" element={<ImaginePage />} />
<Route element={<ProtectedRoute />}>
<Route path="/chatbot/:id" element={<ChatbotPage />} />
<Route path="/imagine" element={<ImaginePage />} />

<Route path="/dashboard" element={<DashboardPage />} />
<Route path="/hub" element={<HubPage />} />
<Route
path="/hub/:chatbotId"
element={<ChatbotViewPage />}
/>
<Route path="/profile" element={<ProfilePage />} />
<Route
path="/profile/:username"
element={<ProfilePage />}
/>
<Route path="/leaderboard" element={<LeaderboardPage />} />
<Route path="/images" element={<MyImagesPage />} />
<Route path="/chatbots" element={<MyChatbotsPage />} />
</Route>
</Routes>
<Route path="/dashboard" element={<DashboardPage />} />
<Route path="/hub" element={<HubPage />} />
<Route path="/hub/:chatbotId" element={<ChatbotViewPage />} />
<Route path="/profile" element={<ProfilePage />} />
<Route path="/profile/:username" element={<ProfilePage />} />
<Route path="/leaderboard" element={<LeaderboardPage />} />
<Route path="/images" element={<MyImagesPage />} />
<Route path="/chatbots" element={<MyChatbotsPage />} />
</Route>
</CustomSwitch>
</AnimatePresence>
</AuthProvider>
Expand Down
4 changes: 3 additions & 1 deletion client/src/lib/custom-switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ const CustomSwitch = ({ children }: { children: React.ReactNode }) => {
return (
<>
{progress && <TopBarProgress />}
<Routes>{children}</Routes>
<Routes location={location} key={location.pathname}>
{children}
</Routes>
</>
);
};
Expand Down
100 changes: 84 additions & 16 deletions client/src/pages/Anonymous.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,35 @@ import { messageSchema } from "@/lib/schemas";
import { SERVER_URL } from "@/lib/utils";
import { zodResolver } from "@hookform/resolvers/zod";
import axios from "axios";
import { ArrowLeft, Loader2, SendIcon } from "lucide-react";
import { ArrowLeft, Loader2, SendIcon, Sparkles } from "lucide-react";
import { useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
import Markdown from "react-markdown";
import { Link } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { z } from "zod";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
useTranslateMagicModal,
usettHMagic,
useTtsMagicModal,
} from "@/stores/modal-store";

function AnonymousPage() {
const [loading, setLoading] = useState(false); // Loading state for request
const [messages, setMessages] = useState<Chat[]>([]);
const { t } = useTranslation();
const { currentConfig } = useSettings();
const ttsMagicModal = useTtsMagicModal();
const ttHMagicModal = usettHMagic();
const translateMagicModal = useTranslateMagicModal();
const navigate = useNavigate();
const form = useForm<z.infer<typeof messageSchema>>({
resolver: zodResolver(messageSchema),
defaultValues: {
Expand Down Expand Up @@ -86,14 +101,16 @@ function AnonymousPage() {
<div className="flex flex-col border-x-2 border-lighter dark:border-darker max-w-7xl mx-auto rounded-sm dark:bg-dark bg-light dark:text-dark h-screen">
<div className="flex items-center justify-between m-3">
<div className="flex items-center space-x-2">
<Link
to={"/dashboard"}
className="shadow bg-blue-500 text-white rounded-full transition-colors hover:bg-blue-600"
<Button
onClick={() => navigate(-1)}
variant={"outline"}
size={"icon"}
className="rounded-full"
>
<ArrowLeft className="w-10 h-10 p-2" />
</Link>
<ArrowLeft className="w-10 h-10" />
</Button>
<img
src="https://robohash.org/Anonymous Bot"
src="https://robohash.org/Anonymous"
alt={`Anonymous Bot's avatar`}
className="w-10 h-10 border rounded-full dark:border-darker mr-3"
/>
Expand All @@ -107,16 +124,67 @@ function AnonymousPage() {
<div className="flex-1 overflow-y-auto p-6 space-y-6 h-full no-scrollbar">
{messages.map((chat) => (
<>
<div className="flex justify-end">
<div className="max-w-xs bg-blue-500 text-white rounded-xl p-4 drop-shadow shadow">
<p className="text-sm">{chat.user_query}</p>
<div className="flex justify-end m-2">
<div className="bg-secondary rounded-full p-4">
<p className="text-sm text-secondary-foreground">
{chat.user_query}
</p>
</div>
</div>
<div className="flex justify-start items-center space-x-2 mb-2">
<div className="max-w-md bg-white dark:bg-dark dark:text-dark/90 text-gray-900 rounded-xl p-4 drop-shadow-md shadow border border-gray-100 dark:border-darker flex flex-col">
<p className="text-sm flex-1">
<Markdown>{chat.response}</Markdown>
</p>
<div className="flex items-start justify-start py-3">
<img
src="https://robohash.org/Anonymous"
alt={`Anonymous's avatar`}
className="w-10 h-10 border rounded-full mx-4"
/>

<div className="mr-4">
<Markdown className="text-sm">{chat.response}</Markdown>
<div className="flex justify-start py-2">
<DropdownMenu>
<DropdownMenuTrigger>
<Button
className="rounded-full hover:bg-primary/10 bg-primary/5"
variant={"ghost"}
size={"icon"}
>
<Sparkles className="text-primary" />
<span className="sr-only">
{t("chatbot_page.action")}
</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
onClick={() =>
translateMagicModal.onOpen({
text: chat.response,
})
}
>
{t("chatbot_page.translate")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
ttsMagicModal.onOpen({
text: chat.response,
})
}
>
{t("chatbot_page.listen")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
ttHMagicModal.onOpen({
text: chat.response,
})
}
>
Handwriting
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
</>
Expand Down
78 changes: 40 additions & 38 deletions client/src/pages/Leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,48 +66,50 @@ function LeaderboardPage() {
const topUsers = leaderboard.slice(0, 3);

return (
<div className="container mx-auto p-6 h-full min-h-screen">
<>
<Navbar />
<h1 className="text-4xl font-bold my-6 text-center">
{t("navbar.leaderboard")}
</h1>
<div className="container mx-auto p-6 h-full min-h-screen">
<h1 className="text-4xl font-bold my-6 text-center">
{t("navbar.leaderboard")}
</h1>

{/* Top Leader Section */}
<div className="flex justify-around my-6">
{topUsers.map((user, idx) => (
<div
key={user.id}
className="p-4 border shadow rounded-lg text-center w-1/4"
>
<h3 className="text-2xl font-bold">Top {idx + 1} </h3>
<p className="text-lg font-semibold">{user.name}</p>
</div>
))}
</div>
{/* Top Leader Section */}
<div className="flex justify-around my-6">
{topUsers.map((user, idx) => (
<div
key={user.id}
className="p-4 border shadow rounded-lg text-center w-1/4"
>
<h3 className="text-2xl font-bold">Top {idx + 1} </h3>
<p className="text-lg font-semibold">{user.name}</p>
</div>
))}
</div>

<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Rank</TableHead>
<TableHead>{t("navbar.profile")}</TableHead>
<TableHead>{t("auth.username")}</TableHead>
<TableHead className="text-right">{t("points")}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{leaderboard.map((user, idx) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{idx + 1}</TableCell>
<TableCell>{user.name}</TableCell>
<TableCell>@{user.username}</TableCell>
<TableCell className="text-right">
{user.contribution_score} pts
</TableCell>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Rank</TableHead>
<TableHead>{t("navbar.profile")}</TableHead>
<TableHead>{t("auth.username")}</TableHead>
<TableHead className="text-right">{t("points")}</TableHead>
</TableRow>
))}
</TableBody>
</Table>
</div>
</TableHeader>
<TableBody>
{leaderboard.map((user, idx) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{idx + 1}</TableCell>
<TableCell>{user.name}</TableCell>
<TableCell>@{user.username}</TableCell>
<TableCell className="text-right">
{user.contribution_score} pts
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</>
);
}
export default transition(LeaderboardPage);