diff --git a/src/components/FeedDialog.tsx b/src/components/FeedDialog.tsx new file mode 100644 index 0000000..10864ba --- /dev/null +++ b/src/components/FeedDialog.tsx @@ -0,0 +1,83 @@ +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + } from "./ui/dialog"; + import { Input } from "./ui/input"; + import { Label } from "./ui/label"; + import { Checkbox } from "./ui/checkbox"; + import { Button } from "./ui/button"; + import { useState, useEffect } from "react"; + + export interface FeedDialogProps { + open: boolean; + onClose: () => void; + onSubmit: (name: string, isPublic: boolean) => void; + initialName?: string; + initialIsPublic?: boolean; + mode?: "create" | "edit"; + } + + export function FeedDialog({ + open, + onClose, + onSubmit, + initialName = "", + initialIsPublic = false, + mode = "create", + }: FeedDialogProps) { + const [name, setName] = useState(initialName); + const [isPublic, setIsPublic] = useState(initialIsPublic); + + useEffect(() => { + setName(initialName); + setIsPublic(initialIsPublic); + }, [initialName, initialIsPublic]); + + const handleSubmit = () => { + if (name.trim()) { + onSubmit(name.trim(), isPublic); + onClose(); + } + }; + + return ( + + + + {mode === "edit" ? "Edit Feed" : "Create New Feed"} + + +
+
+ + setName(e.target.value)} + placeholder="Enter feed name" + /> +
+ +
+ setIsPublic(Boolean(val))} + /> + +
+
+ + + + +
+
+ ); + } + \ No newline at end of file diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 0000000..ac2dd53 --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,15 @@ +// components/ui/badge.tsx +import { cn } from "@/lib/utils"; + +export function Badge({ children, className }: { children: React.ReactNode; className?: string }) { + return ( + + {children} + + ); +} diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..58ab795 --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,23 @@ +import * as React from "react"; +import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; +import { Check } from "lucide-react"; +import { cn } from "@/lib/utils"; + +export const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)); +Checkbox.displayName = CheckboxPrimitive.Root.displayName; diff --git a/src/lib/api.ts b/src/lib/api.ts index e07fb17..5bc62e9 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -91,11 +91,11 @@ export const addNewFeed = async (name: string, isPublic: boolean) => { try { const token = getToken(); if (!token) { - throw new Error('Authentication required'); + throw new Error("Authentication required"); } const response = await userDataApi.post( - '/api/addnewfeed', + "/api/addnewfeed", { Name: name, IsPublic: isPublic, @@ -108,10 +108,37 @@ export const addNewFeed = async (name: string, isPublic: boolean) => { ); return response.data; } catch (error: any) { - throw error.response?.data || { success: false, message: 'Network error' }; + throw error.response?.data || { success: false, message: "Network error" }; } }; +export const updateFeed = async (feedId: string, name: string, isPublic: boolean): Promise => { + try { + const token = getToken(); + if (!token) { + throw new Error("Authentication required"); + } + + const response = await userDataApi.patch( + `/api/updatefeed`, + { + feedId: feedId, + Name: name, + IsPublic: isPublic, + }, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + return response.status === 200; + } catch (error: any) { + return false; + } +}; + + export const deleteFeed = async (feedId: string) => { try { diff --git a/src/pages/DashboardPage.tsx b/src/pages/DashboardPage.tsx index 6f950e5..201facc 100644 --- a/src/pages/DashboardPage.tsx +++ b/src/pages/DashboardPage.tsx @@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import { isAuthenticated } from "@/lib/auth"; import { useFeedStore } from "@/lib/store"; -import { addNewFeed } from "@/lib/api"; +import { addNewFeed, updateFeed } from "@/lib/api"; import { formatDateTime, getTimeRangeOptions } from "@/lib/timeRanges"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; @@ -15,10 +15,11 @@ import { SelectValue, } from "@/components/ui/select"; import { Skeleton } from "@/components/ui/skeleton"; -import { Plus, RefreshCw, ScanBarcode } from "lucide-react"; +import { Plus, RefreshCw, ScanBarcode, Edit, Copy } from "lucide-react"; import { FeedChart } from "@/components/FeedChart"; import { FeedActions } from "@/components/FeedActions"; import { Alert, AlertDescription } from "@/components/ui/alert"; +import { FeedDialog } from "@/components/FeedDialog"; export function DashboardPage() { const navigate = useNavigate(); @@ -36,7 +37,6 @@ export function DashboardPage() { deleteFeed, } = useFeedStore(); - // Check if user is authenticated useEffect(() => { if (!isAuthenticated()) { toast.error("Please login to access the dashboard"); @@ -44,11 +44,9 @@ export function DashboardPage() { return; } - // Fetch feeds on component mount fetchFeeds(); }, [navigate, fetchFeeds]); - // Handle time range change const handleTimeRangeChange = (value: string) => { setTimeRangeValue(value); const selectedOption = getTimeRangeOptions().find(option => option.value === value); @@ -58,36 +56,49 @@ export function DashboardPage() { } }; - // Handle add new feed - const handleAddNewFeed = async () => { - try { - const defaultName = `Untitled Feed ${new Date().toLocaleString()}`; - const response = await addNewFeed(defaultName); + const [isDialogOpen, setDialogOpen] = useState(false); + const [dialogMode, setDialogMode] = useState<"create" | "edit">("create"); + const [editFeedData, setEditFeedData] = useState<{ id: string; name: string; isPublic: boolean } | null>(null); - if (response.success) { - toast.success("New feed created successfully"); - fetchFeeds(); - } else { - toast.error("Failed to create new feed"); + const handleAddNewFeed = () => { + setDialogMode("create"); + setEditFeedData(null); + setDialogOpen(true); + }; + + const handleDialogSubmit = async (name: string, isPublic: boolean) => { + try { + if (dialogMode === "create") { + const response = await addNewFeed(name, isPublic); + if (response.success) { + toast.success("Feed created successfully"); + fetchFeeds(); + } else { + toast.error(response.message || "Failed to create feed"); + } + } else if (dialogMode === "edit" && editFeedData) { + const success = await updateFeed(editFeedData.id, name, isPublic); + if (success) { + toast.success("Feed updated successfully"); + fetchFeeds(); + } else { + toast.error("Failed to update feed"); + fetchFeeds(); + } } - } catch (error) { - toast.error("An error occurred while creating a new feed"); - console.error(error); + } catch (error: any) { + toast.error(error.message || "An error occurred"); } }; - // Handle refresh const handleRefresh = async () => { - // First refresh the feeds list await fetchFeeds(); - // Then refresh current feed data if a feed is selected if (selectedFeed) { await refreshCurrentFeedData(); } toast.success("Data refreshed"); }; - // Handle delete feed const handleDeleteFeed = async (feedId: string) => { try { await deleteFeed(feedId); @@ -108,7 +119,6 @@ export function DashboardPage() {

- {/* Button to add a new feed */} - +
+ + +
))} @@ -206,9 +222,7 @@ export function DashboardPage() { toast.success("Feed ID copied to clipboard"); }} > - - - + @@ -219,7 +233,6 @@ export function DashboardPage() { - {/* Flex container for the select box and button */}
- {/* Button to refresh feed data */}
); -} \ No newline at end of file +}