Skip to content

Commit

Permalink
Merge pull request #249 from priyanshuverma-dev/bug-ui-improvements
Browse files Browse the repository at this point in the history
fixes: Chatbot and Images Separation, UI fixes
  • Loading branch information
kom-senapati authored Nov 3, 2024
2 parents bb45fb6 + e33cfda commit 548f666
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 100 deletions.
8 changes: 5 additions & 3 deletions app/api_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,7 @@ def api_delete_chatbot(chatbot_id: int) -> Union[Response, tuple[Response, int]]
db.session.commit()

return (
jsonify(
{"message": f"Chatbot '{chatbot.id}' has been deleted successfully."}
),
jsonify({"message": f"Chatbot '{chatbot.id}' has been deleted successfully."}),
200,
)

Expand Down Expand Up @@ -560,6 +558,7 @@ def api_get_data():
"user_bots",
"trend_today",
"leaderboard",
"user_images",
}
queues = [q for q in queues if q in valid_queues]
response = {"success": True}
Expand Down Expand Up @@ -593,6 +592,9 @@ def api_get_data():
Chatbot.user_id == o_uid
).all()
response["user_bots"] = [bot.to_dict() for bot in o_chatbots]
if "user_images" in queues:
o_images: List[Image] = Image.query.filter(Image.user_id == o_uid).all()
response["user_images"] = [image.to_dict() for image in o_images]

if "trend_today" in queues:
chatbot_of_the_day: Chatbot = (
Expand Down
Binary file modified client/bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.1",
"@tanstack/react-query": "^5.59.15",
"axios": "^1.7.7",
"class-variance-authority": "^0.7.0",
Expand Down
36 changes: 12 additions & 24 deletions client/src/components/ChatbotCard.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Flag, Heart, MessageSquare, Share2, Trash2 } from "lucide-react"; // Import the Trash icon
import { useShareModal } from "@/stores/modal-store";
import { useDeleteChatbotModal, useShareModal } from "@/stores/modal-store";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { likeAndReport, deleteChatbot } from "@/lib/queries"; // Ensure you have a deleteChatbot function
import { likeAndReport } from "@/lib/queries"; // Ensure you have a deleteChatbot function
import { Card, CardContent, CardFooter, CardHeader } from "./ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
import { Button } from "./ui/button";
import { Link, useNavigate } from "react-router-dom";
import { toast } from "react-hot-toast"; // Optional for notifications

export function ChatbotCard({
chatbot,
Expand All @@ -18,31 +17,14 @@ export function ChatbotCard({
const shareModel = useShareModal();
const rq = useQueryClient();
const navigate = useNavigate();

const deleteModal = useDeleteChatbotModal();
const likeMutation = useMutation({
mutationFn: likeAndReport,
onSuccess: () => rq.invalidateQueries({ queryKey: queryKeys }),
});

const deleteMutation = useMutation({
mutationFn: deleteChatbot, // Your API function to delete a chatbot
onSuccess: () => {
rq.invalidateQueries({ queryKey: queryKeys });
toast.success("Chatbot deleted successfully!"); // Notify the user
},
onError: () => {
toast.error("Failed to delete the chatbot."); // Error handling
},
});

const handleDelete = () => {
if (window.confirm("Are you sure you want to delete this chatbot?")) {
deleteMutation.mutate(String(chatbot.id)); // Convert to string
}
};

return (
<Card className="w-full max-w-sm mx-auto h-full">
<Card className="w-full max-w-sm mx-auto h-fit">
<Link to={`/hub/${chatbot.id}`}>
<CardHeader className="flex flex-row items-center gap-4">
<Avatar className="w-16 h-16">
Expand All @@ -55,7 +37,9 @@ export function ChatbotCard({
</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<h2 className="text-2xl font-bold">{chatbot.latest_version.name}</h2>
<h2 className="text-2xl font-bold">
{chatbot.latest_version.name}
</h2>
<p className="text-sm text-muted-foreground">
Created by @{chatbot.latest_version.modified_by}
</p>
Expand Down Expand Up @@ -134,7 +118,11 @@ export function ChatbotCard({
<Button
variant="destructive" // Use a destructive variant for delete
size="icon"
onClick={handleDelete}
onClick={() =>
deleteModal.onOpen({
id: chatbot.id,
})
}
>
<Trash2 className="h-2 w-2" />
<span className="sr-only">Delete</span>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ImageCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function ImageCard({ image }: { image: ImageGen }) {
});

return (
<Card className="w-full max-w-sm mx-auto overflow-hidden h-full">
<Card className="w-full max-w-sm mx-auto overflow-hidden h-fit">
<CardHeader className="p-0">
<div className="relative aspect-square">
<img
Expand Down
53 changes: 53 additions & 0 deletions client/src/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"

import { cn } from "@/lib/utils"

const Tabs = TabsPrimitive.Root

const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName

const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName

const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName

export { Tabs, TabsList, TabsTrigger, TabsContent }
4 changes: 3 additions & 1 deletion client/src/lib/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const deleteChatbot = async (id: string): Promise<void> => {
}
);
return data;
}
};

export const deleteAllChats = async (id: string): Promise<void> => {
const token = localStorage.getItem("token");
Expand Down Expand Up @@ -146,6 +146,7 @@ interface DataResponse {
system_bots?: Chatbot[]; // Optional property
my_bots?: Chatbot[]; // Optional property
my_images?: ImageGen[]; // Optional property
user_images?: ImageGen[]; // Optional property
public_bots?: Chatbot[]; // Optional property
user_bots?: Chatbot[]; // Optional property
public_images?: ImageGen[]; // Optional property
Expand All @@ -165,6 +166,7 @@ const validQueues = [
"user_bots",
"trend_today",
"leaderboard",
"user_images",
] as const;

type ValidQueue = (typeof validQueues)[number];
Expand Down
134 changes: 81 additions & 53 deletions client/src/pages/Hub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,8 @@ import { fetchData } from "@/lib/queries";
import { chatbotCategories } from "@/lib/utils";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
// Function to shuffle an array
const shuffleArray = (array: any[]) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]]; // Swap elements
}
return array;
};

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

export default function HubPage() {
const [searchTerm, setSearchTerm] = useState("");
Expand All @@ -45,29 +39,13 @@ export default function HubPage() {
});

// Combine and shuffle bots and images
const combinedData = [];
if (botsData?.public_bots) {
combinedData.push(
...botsData.public_bots.map((bot) => ({ type: "bot", data: bot }))
);
}
if (imagesData?.public_images) {
combinedData.push(
...imagesData.public_images.map((image) => ({
type: "image",
data: image,
}))
);
}

const shuffledData = shuffleArray(combinedData);
const filteredData = shuffledData.filter((item) => {
const matchesSearchTerm = item.data.latest_version.prompt
const filteredBotsData = botsData?.public_bots?.filter((item) => {
const matchesSearchTerm = item.latest_version.prompt
.toLowerCase()
.includes(searchTerm.toLowerCase());
const matchesCategory =
selectedCategory === "All" ||
item.data.category?.toLowerCase() === selectedCategory.toLowerCase();
item.category?.toLowerCase() === selectedCategory.toLowerCase();

return matchesSearchTerm && matchesCategory;
});
Expand All @@ -79,31 +57,81 @@ export default function HubPage() {
<h2 className="text-2xl font-semibold mb-6 p-3">
Chatbots and AI Images Hub
</h2>
{/* Search Bar and Category Filter */}
<div className="flex gap-4 mb-6 w-full max-w-2xl">
<Input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<Select
value={selectedCategory}
onValueChange={(v) => setSelectedCategory(v)}
>
<SelectTrigger>
<SelectValue placeholder="Category" />
</SelectTrigger>
<SelectContent>
{["All", ...chatbotCategories].map((category) => (
<SelectItem key={category} value={category}>
{category}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 auto-rows-[minmax(300px, auto)]">

<Tabs defaultValue="chatbots">
<div className="flex space-x-2">
<div className="flex gap-4 mb-6 w-full max-w-2xl">
<Input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<Select
value={selectedCategory}
onValueChange={(v) => setSelectedCategory(v)}
>
<SelectTrigger>
<SelectValue placeholder="Category" />
</SelectTrigger>
<SelectContent>
{["All", ...chatbotCategories].map((category) => (
<SelectItem key={category} value={category}>
{category}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<TabsList>
<TabsTrigger value="chatbots">Chatbots</TabsTrigger>
<TabsTrigger value="images">Images</TabsTrigger>
</TabsList>
</div>

<TabsContent value="chatbots">
<div className="grid grid-flow-dense grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full min-h-screen">
{botsLoading ? (
<BotsLoading />
) : botsError ? (
<div className="col-span-1 text-red-500 text-center">
{botsError?.message}
</div>
) : botsData && botsData.public_bots!.length > 0 ? (
filteredBotsData?.map((item) => (
<ChatbotCard
chatbot={item}
queryKeys={["user_bots"]}
key={item.latest_version.name}
/>
))
) : (
<div className="col-span-1 text-center">No bots available.</div>
)}
</div>
</TabsContent>
<TabsContent value="images">
<div className="grid grid-flow-dense grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full min-h-screen">
{imagesLoading ? (
<BotsLoading />
) : imagesError ? (
<div className="col-span-1 text-red-500 text-center">
{imagesError?.message}
</div>
) : imagesData && imagesData.public_images!.length > 0 ? (
imagesData.public_images!.map((item) => (
<ImageCard image={item} key={item.prompt} />
))
) : (
<div className="col-span-1 text-center">
No Images available.
</div>
)}
</div>
</TabsContent>
</Tabs>

{/* <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 auto-rows-[minmax(300px, auto)]">
{botsLoading || imagesLoading ? (
<BotsLoading />
) : botsError || imagesError ? (
Expand All @@ -129,7 +157,7 @@ export default function HubPage() {
No bots or images available.
</div>
)}
</div>
</div> */}
</div>
</>
);
Expand Down
Loading

0 comments on commit 548f666

Please sign in to comment.