-
-
-
Loading login form...
-
+
+
+
+
Loading secure login...
);
}
-// Main page component that uses Suspense
+// Main page component
export default function LoginPage() {
return (
-
}>
-
-
+
);
}
\ No newline at end of file
diff --git a/app/auth/register/page.tsx b/app/auth/register/page.tsx
index e61c5cd..b275b97 100644
--- a/app/auth/register/page.tsx
+++ b/app/auth/register/page.tsx
@@ -1,5 +1,5 @@
"use client";
-import { fetchData } from "@/lib/api";
+
import { useState } from "react";
import { useRouter } from "next/navigation";
import Image from "next/image";
@@ -7,111 +7,159 @@ import Link from "next/link";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
+import { Loader2, ArrowRight } from "lucide-react";
+import { motion } from "framer-motion";
+import { toast } from "@/hooks/use-toast";
+
+// Matches LoginPage background
+const AuthBackground = () => (
+
+);
export default function RegisterPage() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [invitationCode, setInvitationCode] = useState("");
- const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
async function handleRegister(e: React.FormEvent) {
e.preventDefault();
- setError("");
setLoading(true);
- const res = await fetchData(
- `/api/auth/register`,
- {
+ try {
+ const res = await fetch(`/api/auth/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password, invitationCode }),
+ });
+
+ const data = await res.json();
+
+ if (res.ok) {
+ toast({
+ title: "Account Created! 🎉",
+ description: "Welcome to Ember Market. Redirecting to login...",
+ variant: "default",
+ });
+ setTimeout(() => router.push("/auth/login"), 1500);
+ } else {
+ toast({
+ title: "Registration Failed",
+ description: data.error || "Please check your details.",
+ variant: "destructive",
+ });
+ setLoading(false);
}
- );
-
- const data = await res;
-
- if (res) {
- console.log("Registered successfully:", data);
- router.push("/auth/login");
- } else {
- setError(data.error || "Registration failed");
+ } catch (error) {
+ toast({
+ title: "Error",
+ description: "Something went wrong. Please try again.",
+ variant: "destructive",
+ });
+ setLoading(false);
}
-
- setLoading(false);
}
return (
-
-
-
-
- Create an Account
-
-
- Sign up to start selling
-
-
+
+
- {error &&
{error}
}
+
+
+
+
+
Create your account
+
Start managing your store today
+
-
);
diff --git a/components/analytics/AnalyticsDashboard.tsx b/components/analytics/AnalyticsDashboard.tsx
index d8154b8..5a3d858 100644
--- a/components/analytics/AnalyticsDashboard.tsx
+++ b/components/analytics/AnalyticsDashboard.tsx
@@ -46,6 +46,8 @@ import { DateRangePicker } from "@/components/ui/date-picker";
import { DateRange } from "react-day-picker";
import { addDays, startOfDay, endOfDay } from "date-fns";
import type { DateRange as ProfitDateRange } from "@/lib/services/profit-analytics-service";
+import { MotionWrapper } from "@/components/ui/motion-wrapper";
+import { motion } from "framer-motion";
// Lazy load chart components - already handled individually below
@@ -195,7 +197,7 @@ export default function AnalyticsDashboard({
];
return (
-
+
{/* Header with Privacy Toggle */}
@@ -241,197 +243,215 @@ export default function AnalyticsDashboard({
{/* Key Metrics Cards */}
-
- {isLoading
- ? [...Array(4)].map((_, i) =>
)
- : metrics.map((metric) => (
+
+
+ {isLoading
+ ? [...Array(4)].map((_, i) => )
+ : metrics.map((metric) => (
))}
-
-
- {/* Completion Rate Card */}
-
-
-
-
- Order Completion Rate
-
-
- Percentage of orders that have been successfully completed
-
-
-
- {isLoading ? (
-
- ) : (
-
-
- {hideNumbers ? "**%" : `${data.orders.completionRate}%`}
-
-
-
- {hideNumbers
- ? "** / **"
- : `${data.orders.completed} / ${data.orders.total}`}
-
-
- )}
-
-
-
- {/* Time Period Selector */}
-
-
-
Time Period
-
- Revenue, Profit, and Orders tabs use time filtering. Products and
- Customers show all-time data.
-
-
-
- {/* Analytics Tabs */}
-
-
-
-
-
- Growth
-
-
-
- Revenue
-
-
-
- Profit
-
-
-
- Products
-
-
-
- Customers
-
-
-
- Orders
-
-
-
- Predictions
-
-
-
-
- }>
-
-
-
-
-
- }>
-
-
-
-
-
- {/* Date Range Selector for Profit Calculator */}
-
-
- Date Range
-
- Select a custom date range for profit calculations
-
-
-
-
-
- {profitDateRange?.from && profitDateRange?.to && (
-
-
- {profitDateRange.from.toLocaleDateString()} -{" "}
- {profitDateRange.to.toLocaleDateString()}
-
-
- )}
+ {/* Completion Rate Card */}
+
+
+
+
+
+ Order Completion Rate
+
+
+ Percentage of orders that have been successfully completed
+
+
+
+ {isLoading ? (
+
-
-
- }>
-
-
-
+ ) : (
+
+
+ {hideNumbers ? "**%" : `${data.orders.completionRate}%`}
+
+
+
+ {hideNumbers
+ ? "** / **"
+ : `${data.orders.completed} / ${data.orders.total}`}
+
+
+ )}
+
+
+
-
- }>
-
-
-
+ {/* Time Period Selector */}
+
+
+
Time Period
+
+ Revenue, Profit, and Orders tabs use time filtering. Products and
+ Customers show all-time data.
+
+
+
+
-
- }>
-
-
-
+ {/* Analytics Tabs */}
+
+
+
+
+
+ Growth
+
+
+
+ Revenue
+
+
+
+ Profit
+
+
+
+ Products
+
+
+
+ Customers
+
+
+
+ Orders
+
+
+
+ Predictions
+
+
-
- }>
-
-
-
+
+
+ }>
+
+
+
+
-
- }>
-
-
-
-
-
+
+
+ }>
+
+
+
+
+
+
+
+ {/* Date Range Selector for Profit Calculator */}
+
+
+ Date Range
+
+ Select a custom date range for profit calculations
+
+
+
+
+
+ {profitDateRange?.from && profitDateRange?.to && (
+
+
+ {profitDateRange.from.toLocaleDateString()} -{" "}
+ {profitDateRange.to.toLocaleDateString()}
+
+
+ )}
+
+
+
+ }>
+
+
+
+
+
+
+
+ }>
+
+
+
+
+
+
+
+ }>
+
+
+
+
+
+
+
+ }>
+
+
+
+
+
+
+
+ }>
+
+
+
+
+
+
+
);
}
diff --git a/components/analytics/MetricsCard.tsx b/components/analytics/MetricsCard.tsx
index a2c4f6b..933883a 100644
--- a/components/analytics/MetricsCard.tsx
+++ b/components/analytics/MetricsCard.tsx
@@ -3,6 +3,7 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { TrendingUp, TrendingDown, Minus } from "lucide-react";
import { LucideIcon } from "lucide-react";
+import { motion } from "framer-motion";
interface MetricsCardProps {
title: string;
@@ -13,13 +14,13 @@ interface MetricsCardProps {
trendValue: string;
}
-export default function MetricsCard({
- title,
- value,
- description,
- icon: Icon,
- trend,
- trendValue
+export default function MetricsCard({
+ title,
+ value,
+ description,
+ icon: Icon,
+ trend,
+ trendValue
}: MetricsCardProps) {
const getTrendIcon = () => {
switch (trend) {
@@ -44,23 +45,25 @@ export default function MetricsCard({
};
return (
-
-
-
- {title}
-
-
-
-
- {value}
- {description}
-
- {getTrendIcon()}
-
- {trendValue}
-
-
-
-
+
+
+
+
+ {title}
+
+
+
+
+ {value}
+ {description}
+
+ {getTrendIcon()}
+
+ {trendValue}
+
+
+
+
+
);
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/components/ui/motion-wrapper.tsx b/components/ui/motion-wrapper.tsx
index a304739..bfd0b78 100644
--- a/components/ui/motion-wrapper.tsx
+++ b/components/ui/motion-wrapper.tsx
@@ -1,15 +1,30 @@
"use client";
-import { motion } from "framer-motion";
+import { motion, HTMLMotionProps } from "framer-motion";
+import { cn } from "@/lib/utils";
+import { forwardRef } from "react";
-export function MotionWrapper({ children }: { children: React.ReactNode }) {
- return (
-
- {children}
-
- );
+interface MotionWrapperProps extends HTMLMotionProps<"div"> {
+ children: React.ReactNode;
+ className?: string;
}
+
+export const MotionWrapper = forwardRef(
+ ({ children, className, ...props }, ref) => {
+ return (
+
+ {children}
+
+ );
+ }
+);
+
+MotionWrapper.displayName = "MotionWrapper";
diff --git a/public/git-info.json b/public/git-info.json
index bffac89..5a0a401 100644
--- a/public/git-info.json
+++ b/public/git-info.json
@@ -1,4 +1,4 @@
{
- "commitHash": "624bfa5",
- "buildTime": "2026-01-12T02:42:11.944Z"
+ "commitHash": "02ba4b0",
+ "buildTime": "2026-01-12T03:57:23.436Z"
}
\ No newline at end of file