diff --git a/components/dashboard/content.tsx b/components/dashboard/content.tsx index 57ff5a3..d0150d3 100644 --- a/components/dashboard/content.tsx +++ b/components/dashboard/content.tsx @@ -6,8 +6,9 @@ import { getGreeting } from "@/lib/utils" import { statsConfig } from "@/config/dashboard" import type { OrderStatsData } from "@/lib/types" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { ShoppingCart } from "lucide-react" -import { ArrowUpCircle, CreditCard, DollarSign, Users } from "lucide-react" +import { ShoppingCart, RefreshCcw } from "lucide-react" +import { Button } from "@/components/ui/button" +import { useToast } from "@/components/ui/use-toast" import { Skeleton } from "@/components/ui/skeleton" interface ContentProps { @@ -24,7 +25,7 @@ interface TopProduct { revenue: number; } -// Add quotes array +// Business quotes array const businessQuotes = [ { text: "Your most unhappy customers are your greatest source of learning.", author: "Bill Gates" }, { text: "The secret of getting ahead is getting started.", author: "Mark Twain" }, @@ -38,75 +39,72 @@ const businessQuotes = [ { text: "Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work.", author: "Steve Jobs" } ]; +// Function to get a random quote that's not the Mark Twain one +function getRandomQuote() { + // Filter out the Mark Twain quote for now to ensure variety + const filteredQuotes = businessQuotes.filter(quote => quote.author !== "Mark Twain"); + const randomIndex = Math.floor(Math.random() * filteredQuotes.length); + return filteredQuotes[randomIndex]; +} + export default function Content({ username, orderStats }: ContentProps) { const [greeting, setGreeting] = useState("") const [topProducts, setTopProducts] = useState([]) const [isLoading, setIsLoading] = useState(true) - const [randomQuote, setRandomQuote] = useState(() => { - const randomIndex = Math.floor(Math.random() * businessQuotes.length) - return businessQuotes[randomIndex] - }) + const [error, setError] = useState(null) + const { toast } = useToast() + + // Initialize with a random quote that's not Mark Twain + const [randomQuote, setRandomQuote] = useState(getRandomQuote()) + + const fetchTopProducts = async () => { + setIsLoading(true) + setError(null) + + try { + // Get the auth token from cookies + const authToken = document.cookie + .split("; ") + .find((row) => row.startsWith("Authorization=")) + ?.split("=")[1]; + + if (!authToken) { + throw new Error("Authentication token not found") + } + + // Use the API URL from environment variables + const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/orders/top-products`; + + const response = await fetch(apiUrl, { + headers: { + Authorization: `Bearer ${authToken}`, + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + throw new Error(`API request failed: ${response.status} ${response.statusText}`) + } + + const data = await response.json(); + setTopProducts(data); + } catch (err) { + console.error("Error fetching top products:", err); + setError(err instanceof Error ? err.message : "Failed to fetch top products") + toast({ + title: "Error loading top products", + description: "Please try refreshing the page", + variant: "destructive" + }) + } finally { + setIsLoading(false) + } + }; useEffect(() => { setGreeting(getGreeting()) - // Pick a random quote when component mounts - const randomIndex = Math.floor(Math.random() * businessQuotes.length) - setRandomQuote(businessQuotes[randomIndex]) - - // Fetch top products for the vendor - const fetchTopProducts = async () => { - try { - // Check if we're in development or production - const isDev = process.env.NODE_ENV === 'development'; - // Use the internal API URL seen in the console - const apiBaseUrl = 'https://internal-api.inboxi.ng/api'; - - console.log('Using API URL:', apiBaseUrl); - - // Get the auth token from cookies - const cookies = document.cookie.split(';'); - console.log('Cookies:', cookies); - const tokenCookie = cookies.find(cookie => cookie.trim().startsWith('Authorization=')); - let token = ''; - - if (tokenCookie) { - // Extract just the token value after "Authorization=" - token = tokenCookie.trim().substring(14); // 'Authorization='.length is 14 - - // Fix any potential malformed token (seen in your screenshot) - if (token.startsWith('ization=')) { - token = token.substring(9); // Remove the 'ization=' prefix if present - } - } - - console.log('Using token:', token); - - const headers = { - 'Authorization': `Bearer ${token}` - }; - console.log('Request headers:', headers); - - const response = await fetch(`${apiBaseUrl}/orders/top-products`, { - credentials: 'include', - headers - }); - - if (response.ok) { - const data = await response.json(); - setTopProducts(data); - } else { - const errorText = await response.text(); - console.error(`Failed to fetch top products: ${response.status} ${response.statusText}`); - console.error('Error details:', errorText); - } - } catch (error) { - console.error("Error fetching top products:", error); - } finally { - setIsLoading(false); - } - }; - + // Fetch top products fetchTopProducts(); }, []) @@ -117,7 +115,7 @@ export default function Content({ username, orderStats }: ContentProps) { {greeting}, {username}!

- "The secret of getting ahead is getting started." — Mark Twain + "{randomQuote.text}" — {randomQuote.author}

@@ -135,9 +133,22 @@ export default function Content({ username, orderStats }: ContentProps) { {/* Best Selling Products Section */}
- - Your Best Selling Products - Products with the highest sales from your store + +
+ Your Best Selling Products + Products with the highest sales from your store +
+ {error && ( + + )}
{isLoading ? ( @@ -153,6 +164,11 @@ export default function Content({ username, orderStats }: ContentProps) {
))} + ) : error ? ( +
+

Error loading products

+

{error}

+
) : topProducts.length > 0 ? (
{topProducts.map(product => ( @@ -160,7 +176,21 @@ export default function Content({ username, orderStats }: ContentProps) {
{product.image ? ( - {product.name} + {product.name} { + const target = e.currentTarget; + target.src = ""; + if (target.parentElement) { + target.parentElement.classList.add("bg-muted"); + const iconSpan = document.createElement("span"); + iconSpan.className = "h-5 w-5 text-muted-foreground"; + target.parentElement.appendChild(iconSpan); + } + }} + /> ) : ( )}