- );
- }
-
- // Show error state
- if (error) {
- return (
-
-
-
{error}
-
fetchWilayaData()}
- className="mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
- >
- Try Again
-
+
+ {/* Points information panel */}
+ {pointsSource && (
+
+
+ Source: {pointsSource === 'cache' ? 'Cached' : 'Freshly Generated'}
+
+
+ Total Points: {pointCount}
+
+
+ Normal
+ Warning
+ Alert
+
+ )}
+
+ {/* Cache control button */}
+
+
+
+
- );
- }
-
- return (
-
+
+ {/* Error message */}
+ {error && (
+
+
+
+
Failed to Load Map
+
{error}
+
+ fetchWilayaData()}
+ className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm transition-colors duration-200"
+ >
+ Try Again
+
+
+
+
+ )}
+
+ {/* Loading overlay */}
+ {loading && (
+
+
+
+
+
Loading Map Data
+
Please wait while we prepare your visualization
+
+
+
+ )}
+
);
diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx
index 9826ca8..2b77404 100644
--- a/src/components/app-sidebar.tsx
+++ b/src/components/app-sidebar.tsx
@@ -98,13 +98,13 @@ const data = {
name: "Control",
url: "#",
icon: IconEye,
- id: "Inspection",
+ id: "control",
},
{
name: "Power Draw",
url: "#",
icon: IconBoltFilled,
- id: "powerdraw",
+ id: "power",
},
{
name: "Weather Forecast",
diff --git a/src/components/chart-area-interactive.tsx b/src/components/chart-area-interactive.tsx
index 4753f83..0d64a63 100644
--- a/src/components/chart-area-interactive.tsx
+++ b/src/components/chart-area-interactive.tsx
@@ -2,7 +2,6 @@
import * as React from "react"
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
-
import { useIsMobile } from "@/hooks/use-mobile"
import {
Card,
@@ -32,100 +31,6 @@ import {
export const description = "An interactive area chart"
-const chartData = [
- { date: "2024-04-01", desktop: 222, mobile: 150 },
- { date: "2024-04-02", desktop: 97, mobile: 180 },
- { date: "2024-04-03", desktop: 167, mobile: 120 },
- { date: "2024-04-04", desktop: 242, mobile: 260 },
- { date: "2024-04-05", desktop: 373, mobile: 290 },
- { date: "2024-04-06", desktop: 301, mobile: 340 },
- { date: "2024-04-07", desktop: 245, mobile: 180 },
- { date: "2024-04-08", desktop: 409, mobile: 320 },
- { date: "2024-04-09", desktop: 59, mobile: 110 },
- { date: "2024-04-10", desktop: 261, mobile: 190 },
- { date: "2024-04-11", desktop: 327, mobile: 350 },
- { date: "2024-04-12", desktop: 292, mobile: 210 },
- { date: "2024-04-13", desktop: 342, mobile: 380 },
- { date: "2024-04-14", desktop: 137, mobile: 220 },
- { date: "2024-04-15", desktop: 120, mobile: 170 },
- { date: "2024-04-16", desktop: 138, mobile: 190 },
- { date: "2024-04-17", desktop: 446, mobile: 360 },
- { date: "2024-04-18", desktop: 364, mobile: 410 },
- { date: "2024-04-19", desktop: 243, mobile: 180 },
- { date: "2024-04-20", desktop: 89, mobile: 150 },
- { date: "2024-04-21", desktop: 137, mobile: 200 },
- { date: "2024-04-22", desktop: 224, mobile: 170 },
- { date: "2024-04-23", desktop: 138, mobile: 230 },
- { date: "2024-04-24", desktop: 387, mobile: 290 },
- { date: "2024-04-25", desktop: 215, mobile: 250 },
- { date: "2024-04-26", desktop: 75, mobile: 130 },
- { date: "2024-04-27", desktop: 383, mobile: 420 },
- { date: "2024-04-28", desktop: 122, mobile: 180 },
- { date: "2024-04-29", desktop: 315, mobile: 240 },
- { date: "2024-04-30", desktop: 454, mobile: 380 },
- { date: "2024-05-01", desktop: 165, mobile: 220 },
- { date: "2024-05-02", desktop: 293, mobile: 310 },
- { date: "2024-05-03", desktop: 247, mobile: 190 },
- { date: "2024-05-04", desktop: 385, mobile: 420 },
- { date: "2024-05-05", desktop: 481, mobile: 390 },
- { date: "2024-05-06", desktop: 498, mobile: 520 },
- { date: "2024-05-07", desktop: 388, mobile: 300 },
- { date: "2024-05-08", desktop: 149, mobile: 210 },
- { date: "2024-05-09", desktop: 227, mobile: 180 },
- { date: "2024-05-10", desktop: 293, mobile: 330 },
- { date: "2024-05-11", desktop: 335, mobile: 270 },
- { date: "2024-05-12", desktop: 197, mobile: 240 },
- { date: "2024-05-13", desktop: 197, mobile: 160 },
- { date: "2024-05-14", desktop: 448, mobile: 490 },
- { date: "2024-05-15", desktop: 473, mobile: 380 },
- { date: "2024-05-16", desktop: 338, mobile: 400 },
- { date: "2024-05-17", desktop: 499, mobile: 420 },
- { date: "2024-05-18", desktop: 315, mobile: 350 },
- { date: "2024-05-19", desktop: 235, mobile: 180 },
- { date: "2024-05-20", desktop: 177, mobile: 230 },
- { date: "2024-05-21", desktop: 82, mobile: 140 },
- { date: "2024-05-22", desktop: 81, mobile: 120 },
- { date: "2024-05-23", desktop: 252, mobile: 290 },
- { date: "2024-05-24", desktop: 294, mobile: 220 },
- { date: "2024-05-25", desktop: 201, mobile: 250 },
- { date: "2024-05-26", desktop: 213, mobile: 170 },
- { date: "2024-05-27", desktop: 420, mobile: 460 },
- { date: "2024-05-28", desktop: 233, mobile: 190 },
- { date: "2024-05-29", desktop: 78, mobile: 130 },
- { date: "2024-05-30", desktop: 340, mobile: 280 },
- { date: "2024-05-31", desktop: 178, mobile: 230 },
- { date: "2024-06-01", desktop: 178, mobile: 200 },
- { date: "2024-06-02", desktop: 470, mobile: 410 },
- { date: "2024-06-03", desktop: 103, mobile: 160 },
- { date: "2024-06-04", desktop: 439, mobile: 380 },
- { date: "2024-06-05", desktop: 88, mobile: 140 },
- { date: "2024-06-06", desktop: 294, mobile: 250 },
- { date: "2024-06-07", desktop: 323, mobile: 370 },
- { date: "2024-06-08", desktop: 385, mobile: 320 },
- { date: "2024-06-09", desktop: 438, mobile: 480 },
- { date: "2024-06-10", desktop: 155, mobile: 200 },
- { date: "2024-06-11", desktop: 92, mobile: 150 },
- { date: "2024-06-12", desktop: 492, mobile: 420 },
- { date: "2024-06-13", desktop: 81, mobile: 130 },
- { date: "2024-06-14", desktop: 426, mobile: 380 },
- { date: "2024-06-15", desktop: 307, mobile: 350 },
- { date: "2024-06-16", desktop: 371, mobile: 310 },
- { date: "2024-06-17", desktop: 475, mobile: 520 },
- { date: "2024-06-18", desktop: 107, mobile: 170 },
- { date: "2024-06-19", desktop: 341, mobile: 290 },
- { date: "2024-06-20", desktop: 408, mobile: 450 },
- { date: "2024-06-21", desktop: 169, mobile: 210 },
- { date: "2024-06-22", desktop: 317, mobile: 270 },
- { date: "2024-06-23", desktop: 480, mobile: 530 },
- { date: "2024-06-24", desktop: 132, mobile: 180 },
- { date: "2024-06-25", desktop: 141, mobile: 190 },
- { date: "2024-06-26", desktop: 434, mobile: 380 },
- { date: "2024-06-27", desktop: 448, mobile: 490 },
- { date: "2024-06-28", desktop: 149, mobile: 200 },
- { date: "2024-06-29", desktop: 103, mobile: 160 },
- { date: "2024-06-30", desktop: 446, mobile: 400 },
-]
-
const chartConfig = {
visitors: {
label: "Visitors",
@@ -140,7 +45,7 @@ const chartConfig = {
},
} satisfies ChartConfig
-export function ChartAreaInteractive() {
+export function ChartAreaInteractive({chartData, title, desc}: {chartData: any[], title: string, desc: string}) {
const isMobile = useIsMobile()
const [timeRange, setTimeRange] = React.useState("90d")
@@ -166,15 +71,16 @@ export function ChartAreaInteractive() {
return (
+
- Total Visitors
+ {title || "Chart Title"}
- Total for the last 3 months
+ {desc || "Chart Description"}
- Last 3 months
+
diff --git a/src/components/control-card.tsx b/src/components/control-card.tsx
new file mode 100644
index 0000000..9bb7057
--- /dev/null
+++ b/src/components/control-card.tsx
@@ -0,0 +1,158 @@
+import React from 'react';
+import { Card } from '@/components/ui/card';
+import { cn } from '@/lib/utils';
+import { Separator } from '@/components/ui/separator';
+// type 1 : square
+// type 2 : rectangle vertical
+// type 3 : rectangle horizontal
+export interface ControlCardProps {
+ title: string;
+ type: 1 | 2 | 3; // 1: square, 2: rectangle vertical, 3: rectangle horizontal
+ status: string;
+ image?: string;
+ className?: string;
+ children?: React.ReactNode;
+ onStatusChange?: () => void;
+}
+
+const ControlCard = ({
+ title,
+ type,
+ status,
+ image,
+ className,
+ children,
+ onStatusChange
+}: ControlCardProps) => {
+ const getStatusColor = (status: string) => {
+ switch (status.toLowerCase()) {
+ case 'active':
+ case 'on':
+ return 'primary';
+ case 'open':
+ return 'blue-700';
+ case 'disabled':
+ case 'off':
+ return 'bad';
+ default:
+ return 'neutral';
+ }
+ };
+
+ const getStatusColorClass = (status: string) => {
+ const baseColor = getStatusColor(status);
+ return `from-${baseColor} via-${baseColor}/10 via-40% to-${baseColor}/5`;
+ };
+
+ const getCardSize = () => {
+ switch (type) {
+ case 1: // Square
+ return 'w-full aspect-[9/7] xs:aspect-[9/8] sm:aspect-[9/9]';
+ case 2: // Vertical Rectangle
+ return 'w-full row-span-2';
+ case 3: // Horizontal Rectangle
+ return 'w-full col-span-2 aspect-[18/7] xs:aspect-[18/8] sm:aspect-[18/9]';
+ default:
+ return 'w-full aspect-square';
+ }
+ };
+
+ const renderCardContent = () => {
+ switch (type) {
+ case 1: // Square - Image left, text right
+ return (
+
+ {/* Left side - Image */}
+
+
+ {image && (
+
+ )}
+
+
+
+ {/* Right side - Content */}
+
+
+
{title}
+
+ {status}
+
+
+ {children}
+
+
+ );
+
+ case 2:
+ return (
+
+ {/* Top - Image */}
+
+
+ {image && (
+
+ )}
+
+
+
+ {/* Bottom - Content */}
+
+
+
{title}
+
+ {status}
+
+
+
+ {children}
+
+
+ );
+
+ case 3: // Horizontal - Header top, content bottom
+ return (
+
+ {/* Top - Header */}
+
+
+
{title}
+
+ {status}
+
+
+
+ {/* Bottom - Content */}
+
+ {children}
+
+
+ );
+ }
+ };
+
+ // for type 1 : to tr, t2 : to t, t3 : to t
+
+ return (
+
+ {renderCardContent()}
+
+ );
+};
+
+export default ControlCard;
\ No newline at end of file
diff --git a/src/components/footer/index.tsx b/src/components/footer/index.tsx
new file mode 100644
index 0000000..6363678
--- /dev/null
+++ b/src/components/footer/index.tsx
@@ -0,0 +1,84 @@
+import React from "react";
+
+const Footer = () => {
+ return (
+
+ );
+};
+
+export default Footer;
+
+const socials = [
+ {
+ Logo: (
+
+
+
+
+ ),
+ href: "https://github.com/SarathAdhi",
+ },
+ {
+ Logo: (
+
+
+
+ ),
+ href: "https://twitter.com/AdhithyaSarath",
+ },
+ {
+ Logo: (
+
+
+
+ ),
+ href: "https://www.linkedin.com/in/sarath-adhithya/",
+ },
+];
diff --git a/src/components/min-card.tsx b/src/components/min-card.tsx
new file mode 100644
index 0000000..d2c103c
--- /dev/null
+++ b/src/components/min-card.tsx
@@ -0,0 +1,39 @@
+import {
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle,
+ } from "@/components/ui/card";
+ import { Separator } from "@/components/ui/separator";
+ // tabler
+ import { TablerIcon } from "@tabler/icons-react";
+
+ interface MiniCardProps {
+ icon: TablerIcon;
+ title: string;
+ value1: string | number;
+ value2?: string | number; // Optional second value
+ iconColor?: string; // Optional icon color
+ }
+
+export default function MiniCard({
+ icon: Icon,
+ title,
+ value1,
+ value2,
+ iconColor = "text-primary", // Default icon color
+}: MiniCardProps) {
+ return (
+
+
+
+
+
+
{title}
+
{value1}
+ {value2 &&
{value2}
}
+
+
+
+ );
+ };
\ No newline at end of file
diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx
new file mode 100644
index 0000000..5b3eb7c
--- /dev/null
+++ b/src/components/navbar/index.tsx
@@ -0,0 +1,85 @@
+import { Button } from "@/components/ui/button";
+import Link from "next/link";
+import { ModeToggle } from "./mode-toggle";
+
+import { signOut } from "@/app/actions";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { createClient } from "@/utils/supabase/server";
+import { Lock, User } from "lucide-react";
+
+const Navbar = async () => {
+ const supabase = createClient();
+
+ const {
+ data: { user },
+ } = await supabase.auth.getUser();
+
+ return (
+
+ );
+};
+
+export default Navbar;
diff --git a/src/components/navbar/mode-toggle.tsx b/src/components/navbar/mode-toggle.tsx
new file mode 100644
index 0000000..f0ca4f4
--- /dev/null
+++ b/src/components/navbar/mode-toggle.tsx
@@ -0,0 +1,40 @@
+"use client";
+
+import { Moon, Sun } from "lucide-react";
+import { useTheme } from "next-themes";
+
+import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+
+export function ModeToggle() {
+ const { setTheme, theme } = useTheme();
+
+ return (
+
+
+
+
+
+ Toggle theme
+
+
+
+
+ setTheme(value)}
+ >
+ Light
+ Dark
+ System
+
+
+
+ );
+}
diff --git a/src/components/search-input.tsx b/src/components/search-input.tsx
index 5eafb48..c1985f8 100644
--- a/src/components/search-input.tsx
+++ b/src/components/search-input.tsx
@@ -15,6 +15,7 @@ import { Button } from "@/components/ui/button"; // Using Shadcn UI Button for c
interface SearchInputProps {
onSearch: (query: string) => void;
onWilayaSelect?: (wilaya: string | null) => void; // Callback for Wilaya selection
+ disabled?: boolean; // Optional prop to disable the component
}
// Algeria's 58 wilayas (provinces) - Ensure this list matches GeoJSON and population data keys
@@ -22,14 +23,14 @@ const ALGERIA_WILAYAS = [
"Adrar", "Chlef", "Laghouat", "Oum El Bouaghi", "Batna", "Béjaïa", "Biskra", "Béchar",
"Blida", "Bouira", "Tamanrasset", "Tébessa", "Tlemcen", "Tiaret", "Tizi Ouzou", "Alger",
"Djelfa", "Jijel", "Sétif", "Saïda", "Skikda", "Sidi Bel Abbès", "Annaba", "Guelma",
- "Constantine", "Médéa", "Mostaganem", "M'Sila", "Mascara", "Ouargla", "Oran", "El Bayadh",
+ "Constantine", "Médéa", "Mostaganem", "M\'Sila", "Mascara", "Ouargla", "Oran", "El Bayadh",
"Illizi", "Bordj Bou Arréridj", "Boumerdès", "El Tarf", "Tindouf", "Tissemsilt", "El Oued",
"Khenchela", "Souk Ahras", "Tipaza", "Mila", "Aïn Defla", "Naâma", "Aïn Témouchent",
"Ghardaïa", "Relizane", "Timimoun", "Bordj Badji Mokhtar", "Ouled Djellal", "Béni Abbès", // Added 2019 wilayas
- "In Salah", "In Guezzam", "Touggourt", "Djanet", "El M'ghair", "El Meniaa"
+ "In Salah", "In Guezzam", "Touggourt", "Djanet", "El M\'Ghair", "El Meniaa"
].sort(); // Sort alphabetically for better UX in the list
-const SearchInput: React.FC
= ({ onSearch, onWilayaSelect }) => {
+const SearchInput: React.FC = ({ onSearch, onWilayaSelect, disabled = false }) => {
const [inputValue, setInputValue] = useState(''); // Controls the text visible in the input field
const [commandInputValue, setCommandInputValue] = useState(''); // State for filtering within Command *if* using CommandInput
const [open, setOpen] = useState(false); // Popover open state for Wilaya mode
diff --git a/src/components/section-cards.tsx b/src/components/section-cards.tsx
index f714d25..78bc609 100644
--- a/src/components/section-cards.tsx
+++ b/src/components/section-cards.tsx
@@ -10,93 +10,59 @@ import {
CardTitle,
} from "@/components/ui/card"
-export function SectionCards() {
+export default function SectionCards({ data }: { data: any[] }) {
return (
-
-
- Total Revenue
-
- $1,250.00
-
-
-
-
- +12.5%
-
-
-
-
-
- Trending up this month
-
-
- Visitors for the last 6 months
-
-
-
-
-
- New Customers
-
- 1,234
-
-
-
-
- -20%
-
-
-
-
-
- Down 20% this period
-
-
- Acquisition needs attention
-
-
-
-
-
- Active Accounts
-
- 45,678
-
-
-
-
- +12.5%
-
-
-
-
-
- Strong user retention
-
- Engagement exceed targets
-
-
-
-
- Growth Rate
-
- 4.5%
-
-
-
-
- +4.5%
-
-
-
-
-
- Steady performance increase
-
- Meets growth projections
-
-
-
+ {data && data.map((item, index) => (
+
+
+
+ {item.name}
+
+
+ {item.value}
+
+
+
+
+ {item.trendIcon === "up" ?
+ :
+
+ }
+
+
+ {item.trend}
+
+
+
+
+
+
+
+
+ {item.description}
+
+
+ {item.footer}
+
+
+
+
+ ))
+ }
+
+
)
}
diff --git a/src/components/section-charts.tsx b/src/components/section-charts.tsx
new file mode 100644
index 0000000..ef266e4
--- /dev/null
+++ b/src/components/section-charts.tsx
@@ -0,0 +1,81 @@
+import { forwardRef, useEffect, useState } from "react"
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuLabel,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import { ChartAreaInteractive } from "@/components/chart-area-interactive"
+import { chartData, chartData2, chartData3, chartData4 } from "@/data/charData"
+
+export default function SectionCharts() {
+
+ const [selectedChart, setSelectedChart] = useState("chartData")
+ const [chart, setChart] = useState(chartData)
+ const [title, setTitle] = useState("Temperature")
+ const [description, setDescription] = useState("Temperature in going up")
+
+ useEffect(() => {
+ switch (selectedChart) {
+ case "chartData":
+ setChart(chartData)
+ setTitle("Temperature")
+ setDescription("Previous temperature")
+ break
+ case "chartData2":
+ setChart(chartData2)
+ setTitle("Humidity")
+ setDescription("Humidity is going down")
+ break
+ case "chartData3":
+ setChart(chartData3)
+ setTitle("Co2")
+ setDescription("Co2 level is going up")
+ break
+ case "chartData4":
+ setChart(chartData4)
+ setTitle("Light")
+ setDescription("Light is going down")
+ break
+ default:
+ setChart(chartData)
+ }
+ }, [selectedChart]);
+
+ return (
+
+
+
+
+
+
+ Switch Chart
+
+
+ Panel Position
+
+
+
+
+ Temperature
+ Humidity
+ Co2
+ Light
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
diff --git a/src/components/section-mini-cards.tsx b/src/components/section-mini-cards.tsx
new file mode 100644
index 0000000..673ab45
--- /dev/null
+++ b/src/components/section-mini-cards.tsx
@@ -0,0 +1,35 @@
+import { IconWindow, IconAirConditioning, IconBulbFilled, IconDoor } from "@tabler/icons-react"
+
+import MiniCard from "@/components/min-card";
+
+export default function SectionMiniCards() {
+ return (
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/tempCodeRunnerFile.tsx b/src/components/tempCodeRunnerFile.tsx
new file mode 100644
index 0000000..80c6b27
--- /dev/null
+++ b/src/components/tempCodeRunnerFile.tsx
@@ -0,0 +1 @@
+onClick
\ No newline at end of file
diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx
new file mode 100644
index 0000000..b0ff266
--- /dev/null
+++ b/src/components/theme-provider.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import * as React from "react";
+import { ThemeProvider as NextThemesProvider } from "next-themes";
+import { type ThemeProviderProps } from "next-themes/dist/types";
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return {children} ;
+}
diff --git a/src/components/ui/bento-grid.tsx b/src/components/ui/bento-grid.tsx
new file mode 100644
index 0000000..93c7d78
--- /dev/null
+++ b/src/components/ui/bento-grid.tsx
@@ -0,0 +1,82 @@
+import { cn } from "@/utils/cn";
+import { ArrowRightIcon } from "lucide-react";
+import Link from "next/link";
+import { ReactNode } from "react";
+import { Button } from "./button";
+
+const BentoGrid = ({
+ children,
+ className,
+}: {
+ children: ReactNode;
+ className?: string;
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const BentoCard = ({
+ name,
+ className,
+ background,
+ Icon,
+ description,
+ href,
+ cta,
+}: {
+ name: string;
+ className: string;
+ background: ReactNode;
+ Icon: any;
+ description: string;
+ href: string;
+ cta: string;
+}) => (
+
+
{background}
+
+
+
+
+ {name}
+
+
+
{description}
+
+
+
+
+
+
+);
+
+export { BentoCard, BentoGrid };
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index a2df8dc..5a5f657 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -14,7 +14,7 @@ const buttonVariants = cva(
destructive:
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ "border bg-background-light shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost:
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
index d05bbc6..01171a5 100644
--- a/src/components/ui/card.tsx
+++ b/src/components/ui/card.tsx
@@ -64,7 +64,7 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx
index defeb01..02fdbd9 100644
--- a/src/components/ui/checkbox.tsx
+++ b/src/components/ui/checkbox.tsx
@@ -12,7 +12,7 @@ function Checkbox({
= FieldPath
+> = {
+ name: TName;
+};
+
+const FormFieldContext = React.createContext(
+ {} as FormFieldContextValue
+);
+
+const FormField = <
+ TFieldValues extends FieldValues = FieldValues,
+ TName extends FieldPath = FieldPath
+>({
+ ...props
+}: ControllerProps) => {
+ return (
+
+
+
+ );
+};
+
+const useFormField = () => {
+ const fieldContext = React.useContext(FormFieldContext);
+ const itemContext = React.useContext(FormItemContext);
+ const { getFieldState, formState } = useFormContext();
+
+ const fieldState = getFieldState(fieldContext.name, formState);
+
+ if (!fieldContext) {
+ throw new Error("useFormField should be used within ");
+ }
+
+ const { id } = itemContext;
+
+ return {
+ id,
+ name: fieldContext.name,
+ formItemId: `${id}-form-item`,
+ formDescriptionId: `${id}-form-item-description`,
+ formMessageId: `${id}-form-item-message`,
+ ...fieldState,
+ };
+};
+
+type FormItemContextValue = {
+ id: string;
+};
+
+const FormItemContext = React.createContext(
+ {} as FormItemContextValue
+);
+
+const FormItem = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const id = React.useId();
+
+ return (
+
+
+
+ );
+});
+FormItem.displayName = "FormItem";
+
+const FormLabel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => {
+ const { error, formItemId } = useFormField();
+
+ return (
+
+ );
+});
+FormLabel.displayName = "FormLabel";
+
+const FormControl = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ ...props }, ref) => {
+ const { error, formItemId, formDescriptionId, formMessageId } =
+ useFormField();
+
+ return (
+
+ );
+});
+FormControl.displayName = "FormControl";
+
+const FormDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const { formDescriptionId } = useFormField();
+
+ return (
+
+ );
+});
+FormDescription.displayName = "FormDescription";
+
+const FormMessage = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, children, ...props }, ref) => {
+ const { error, formMessageId } = useFormField();
+ const body = error ? String(error?.message) : children;
+
+ if (!body) {
+ return null;
+ }
+
+ return (
+
+ {body}
+
+ );
+});
+FormMessage.displayName = "FormMessage";
+
+export {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+ useFormField,
+};
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index fb21238..02e84d1 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type}
data-slot="input"
className={cn(
- "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-background-light/70 border-background-dark/70 flex h-9 w-full min-w-0 rounded-md border bg-background-light/20 px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
+ "file:text-foreground placeholder:text-muted-foreground/40 selection:bg-primary selection:text-primary-foreground dark:bg-background-light/70 border border-input/70 flex h-9 w-full min-w-0 rounded-md bg-background-light/50 px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className
diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx
new file mode 100644
index 0000000..3d03cf9
--- /dev/null
+++ b/src/components/ui/input/index.tsx
@@ -0,0 +1,25 @@
+import * as React from "react";
+
+import { cn } from "@/utils/cn";
+
+export interface InputProps
+ extends React.InputHTMLAttributes {}
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+Input.displayName = "Input";
+
+export { Input };
diff --git a/src/components/ui/input/input-form.tsx b/src/components/ui/input/input-form.tsx
new file mode 100644
index 0000000..05c4ad1
--- /dev/null
+++ b/src/components/ui/input/input-form.tsx
@@ -0,0 +1,69 @@
+import * as React from "react";
+
+import { cn } from "@/utils/cn";
+import { Control, FieldValues } from "react-hook-form";
+import { Input } from ".";
+import {
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "../form";
+
+export interface InputProps
+ extends React.InputHTMLAttributes {
+ label?: string;
+ containerClassName?: string;
+ description?: string;
+ control?: Control;
+}
+
+const InputForm = React.forwardRef(
+ (
+ {
+ className,
+ containerClassName,
+ name,
+ label,
+ control,
+ description,
+ ...props
+ },
+ ref
+ ) => (
+ (
+
+ {label && (
+
+ {label}{" "}
+ {props?.required && * }
+
+ )}
+
+
+
+
+
+ {description && {description} }
+
+
+
+ )}
+ />
+ )
+);
+
+InputForm.displayName = "InputForm";
+
+export { InputForm };
diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx
index 97be6f9..bdb4aa0 100644
--- a/src/components/ui/table.tsx
+++ b/src/components/ui/table.tsx
@@ -12,7 +12,7 @@ function Table({ className, ...props }: React.ComponentProps<"table">) {
>
diff --git a/src/config/site.ts b/src/config/site.ts
new file mode 100644
index 0000000..3a41c12
--- /dev/null
+++ b/src/config/site.ts
@@ -0,0 +1,24 @@
+type SiteConfig = {
+ name: string;
+ description: string;
+ url: string;
+ ogImage: string;
+ links: {
+ twitter: string;
+ github: string;
+ };
+};
+
+const baseUrl = process.env.NEXT_PUBLIC_BASE_URL!;
+
+export const siteConfig: SiteConfig = {
+ name: "Next Level UI",
+ description:
+ "Blazing-fast, interactive app built with latest web tech (Next.js 14). Modern design (Shadcn, Tailwind CSS). Open-source & yours to explore!",
+ url: baseUrl,
+ ogImage: `${baseUrl}/open-graph.png`,
+ links: {
+ twitter: "https://twitter.com/AdhithyaSarath",
+ github: "https://github.com/SarathAdhi",
+ },
+};
diff --git a/src/data/charData.tsx b/src/data/charData.tsx
new file mode 100644
index 0000000..88ec64a
--- /dev/null
+++ b/src/data/charData.tsx
@@ -0,0 +1,364 @@
+
+export const chartData = [
+ { date: "2024-04-01", desktop: 222, mobile: 150 },
+ { date: "2024-04-02", desktop: 97, mobile: 180 },
+ { date: "2024-04-03", desktop: 167, mobile: 120 },
+ { date: "2024-04-04", desktop: 242, mobile: 260 },
+ { date: "2024-04-05", desktop: 373, mobile: 290 },
+ { date: "2024-04-06", desktop: 301, mobile: 340 },
+ { date: "2024-04-07", desktop: 245, mobile: 180 },
+ { date: "2024-04-08", desktop: 409, mobile: 320 },
+ { date: "2024-04-09", desktop: 59, mobile: 110 },
+ { date: "2024-04-10", desktop: 261, mobile: 190 },
+ { date: "2024-04-11", desktop: 327, mobile: 350 },
+ { date: "2024-04-12", desktop: 292, mobile: 210 },
+ { date: "2024-04-13", desktop: 342, mobile: 380 },
+ { date: "2024-04-14", desktop: 137, mobile: 220 },
+ { date: "2024-04-15", desktop: 120, mobile: 170 },
+ { date: "2024-04-16", desktop: 138, mobile: 190 },
+ { date: "2024-04-17", desktop: 446, mobile: 360 },
+ { date: "2024-04-18", desktop: 364, mobile: 410 },
+ { date: "2024-04-19", desktop: 243, mobile: 180 },
+ { date: "2024-04-20", desktop: 89, mobile: 150 },
+ { date: "2024-04-21", desktop: 137, mobile: 200 },
+ { date: "2024-04-22", desktop: 224, mobile: 170 },
+ { date: "2024-04-23", desktop: 138, mobile: 230 },
+ { date: "2024-04-24", desktop: 387, mobile: 290 },
+ { date: "2024-04-25", desktop: 215, mobile: 250 },
+ { date: "2024-04-26", desktop: 75, mobile: 130 },
+ { date: "2024-04-27", desktop: 383, mobile: 420 },
+ { date: "2024-04-28", desktop: 122, mobile: 180 },
+ { date: "2024-04-29", desktop: 315, mobile: 240 },
+ { date: "2024-04-30", desktop: 454, mobile: 380 },
+ { date: "2024-05-01", desktop: 165, mobile: 220 },
+ { date: "2024-05-02", desktop: 293, mobile: 310 },
+ { date: "2024-05-03", desktop: 247, mobile: 190 },
+ { date: "2024-05-04", desktop: 385, mobile: 420 },
+ { date: "2024-05-05", desktop: 481, mobile: 390 },
+ { date: "2024-05-06", desktop: 498, mobile: 520 },
+ { date: "2024-05-07", desktop: 388, mobile: 300 },
+ { date: "2024-05-08", desktop: 149, mobile: 210 },
+ { date: "2024-05-09", desktop: 227, mobile: 180 },
+ { date: "2024-05-10", desktop: 293, mobile: 330 },
+ { date: "2024-05-11", desktop: 335, mobile: 270 },
+ { date: "2024-05-12", desktop: 197, mobile: 240 },
+ { date: "2024-05-13", desktop: 197, mobile: 160 },
+ { date: "2024-05-14", desktop: 448, mobile: 490 },
+ { date: "2024-05-15", desktop: 473, mobile: 380 },
+ { date: "2024-05-16", desktop: 338, mobile: 400 },
+ { date: "2024-05-17", desktop: 499, mobile: 420 },
+ { date: "2024-05-18", desktop: 315, mobile: 350 },
+ { date: "2024-05-19", desktop: 235, mobile: 180 },
+ { date: "2024-05-20", desktop: 177, mobile: 230 },
+ { date: "2024-05-21", desktop: 82, mobile: 140 },
+ { date: "2024-05-22", desktop: 81, mobile: 120 },
+ { date: "2024-05-23", desktop: 252, mobile: 290 },
+ { date: "2024-05-24", desktop: 294, mobile: 220 },
+ { date: "2024-05-25", desktop: 201, mobile: 250 },
+ { date: "2024-05-26", desktop: 213, mobile: 170 },
+ { date: "2024-05-27", desktop: 420, mobile: 460 },
+ { date: "2024-05-28", desktop: 233, mobile: 190 },
+ { date: "2024-05-29", desktop: 78, mobile: 130 },
+ { date: "2024-05-30", desktop: 340, mobile: 280 },
+ { date: "2024-05-31", desktop: 178, mobile: 230 },
+ { date: "2024-06-01", desktop: 178, mobile: 200 },
+ { date: "2024-06-02", desktop: 470, mobile: 410 },
+ { date: "2024-06-03", desktop: 103, mobile: 160 },
+ { date: "2024-06-04", desktop: 439, mobile: 380 },
+ { date: "2024-06-05", desktop: 88, mobile: 140 },
+ { date: "2024-06-06", desktop: 294, mobile: 250 },
+ { date: "2024-06-07", desktop: 323, mobile: 370 },
+ { date: "2024-06-08", desktop: 385, mobile: 320 },
+ { date: "2024-06-09", desktop: 438, mobile: 480 },
+ { date: "2024-06-10", desktop: 155, mobile: 200 },
+ { date: "2024-06-11", desktop: 92, mobile: 150 },
+ { date: "2024-06-12", desktop: 492, mobile: 420 },
+ { date: "2024-06-13", desktop: 81, mobile: 130 },
+ { date: "2024-06-14", desktop: 426, mobile: 380 },
+ { date: "2024-06-15", desktop: 307, mobile: 350 },
+ { date: "2024-06-16", desktop: 371, mobile: 310 },
+ { date: "2024-06-17", desktop: 475, mobile: 520 },
+ { date: "2024-06-18", desktop: 107, mobile: 170 },
+ { date: "2024-06-19", desktop: 341, mobile: 290 },
+ { date: "2024-06-20", desktop: 408, mobile: 450 },
+ { date: "2024-06-21", desktop: 169, mobile: 210 },
+ { date: "2024-06-22", desktop: 317, mobile: 270 },
+ { date: "2024-06-23", desktop: 480, mobile: 530 },
+ { date: "2024-06-24", desktop: 132, mobile: 180 },
+ { date: "2024-06-25", desktop: 141, mobile: 190 },
+ { date: "2024-06-26", desktop: 434, mobile: 380 },
+ { date: "2024-06-27", desktop: 448, mobile: 490 },
+ { date: "2024-06-28", desktop: 149, mobile: 200 },
+ { date: "2024-06-29", desktop: 103, mobile: 160 },
+ { date: "2024-06-30", desktop: 446, mobile: 400 },
+]
+export const chartData2 = [
+ { date: "2024-04-01", desktop: 185, mobile: 125 },
+ { date: "2024-04-02", desktop: 82, mobile: 155 },
+ { date: "2024-04-03", desktop: 142, mobile: 100 },
+ { date: "2024-04-04", desktop: 205, mobile: 220 },
+ { date: "2024-04-05", desktop: 315, mobile: 245 },
+ { date: "2024-04-06", desktop: 255, mobile: 290 },
+ { date: "2024-04-07", desktop: 208, mobile: 155 },
+ { date: "2024-04-08", desktop: 348, mobile: 270 },
+ { date: "2024-04-09", desktop: 50, mobile: 90 },
+ { date: "2024-04-10", desktop: 222, mobile: 165 },
+ { date: "2024-04-11", desktop: 278, mobile: 295 },
+ { date: "2024-04-12", desktop: 248, mobile: 180 },
+ { date: "2024-04-13", desktop: 290, mobile: 325 },
+ { date: "2024-04-14", desktop: 116, mobile: 190 },
+ { date: "2024-04-15", desktop: 102, mobile: 145 },
+ { date: "2024-04-16", desktop: 117, mobile: 165 },
+ { date: "2024-04-17", desktop: 379, mobile: 305 },
+ { date: "2024-04-18", desktop: 309, mobile: 350 },
+ { date: "2024-04-19", desktop: 206, mobile: 155 },
+ { date: "2024-04-20", desktop: 75, mobile: 130 },
+ { date: "2024-04-21", desktop: 116, mobile: 170 },
+ { date: "2024-04-22", desktop: 190, mobile: 145 },
+ { date: "2024-04-23", desktop: 117, mobile: 195 },
+ { date: "2024-04-24", desktop: 329, mobile: 245 },
+ { date: "2024-04-25", desktop: 183, mobile: 210 },
+ { date: "2024-04-26", desktop: 64, mobile: 110 },
+ { date: "2024-04-27", desktop: 325, mobile: 355 },
+ { date: "2024-04-28", desktop: 104, mobile: 155 },
+ { date: "2024-04-29", desktop: 268, mobile: 205 },
+ { date: "2024-04-30", desktop: 386, mobile: 325 },
+ { date: "2024-05-01", desktop: 140, mobile: 190 },
+ { date: "2024-05-02", desktop: 249, mobile: 265 },
+ { date: "2024-05-03", desktop: 209, mobile: 165 },
+ { date: "2024-05-04", desktop: 327, mobile: 355 },
+ { date: "2024-05-05", desktop: 409, mobile: 330 },
+ { date: "2024-05-06", desktop: 423, mobile: 440 },
+ { date: "2024-05-07", desktop: 329, mobile: 255 },
+ { date: "2024-05-08", desktop: 127, mobile: 180 },
+ { date: "2024-05-09", desktop: 193, mobile: 155 },
+ { date: "2024-05-10", desktop: 249, mobile: 280 },
+ { date: "2024-05-11", desktop: 285, mobile: 230 },
+ { date: "2024-05-12", desktop: 167, mobile: 205 },
+ { date: "2024-05-13", desktop: 167, mobile: 135 },
+ { date: "2024-05-14", desktop: 381, mobile: 415 },
+ { date: "2024-05-15", desktop: 402, mobile: 325 },
+ { date: "2024-05-16", desktop: 287, mobile: 340 },
+ { date: "2024-05-17", desktop: 424, mobile: 355 },
+ { date: "2024-05-18", desktop: 268, mobile: 295 },
+ { date: "2024-05-19", desktop: 199, mobile: 155 },
+ { date: "2024-05-20", desktop: 150, mobile: 195 },
+ { date: "2024-05-21", desktop: 70, mobile: 120 },
+ { date: "2024-05-22", desktop: 69, mobile: 100 },
+ { date: "2024-05-23", desktop: 214, mobile: 245 },
+ { date: "2024-05-24", desktop: 249, mobile: 190 },
+ { date: "2024-05-25", desktop: 171, mobile: 210 },
+ { date: "2024-05-26", desktop: 181, mobile: 145 },
+ { date: "2024-05-27", desktop: 357, mobile: 390 },
+ { date: "2024-05-28", desktop: 198, mobile: 165 },
+ { date: "2024-05-29", desktop: 66, mobile: 110 },
+ { date: "2024-05-30", desktop: 289, mobile: 235 },
+ { date: "2024-05-31", desktop: 151, mobile: 195 },
+ { date: "2024-06-01", desktop: 151, mobile: 170 },
+ { date: "2024-06-02", desktop: 399, mobile: 350 },
+ { date: "2024-06-03", desktop: 87, mobile: 135 },
+ { date: "2024-06-04", desktop: 373, mobile: 325 },
+ { date: "2024-06-05", desktop: 75, mobile: 120 },
+ { date: "2024-06-06", desktop: 249, mobile: 210 },
+ { date: "2024-06-07", desktop: 274, mobile: 315 },
+ { date: "2024-06-08", desktop: 327, mobile: 270 },
+ { date: "2024-06-09", desktop: 372, mobile: 405 },
+ { date: "2024-06-10", desktop: 132, mobile: 170 },
+ { date: "2024-06-11", desktop: 78, mobile: 130 },
+ { date: "2024-06-12", desktop: 418, mobile: 355 },
+ { date: "2024-06-13", desktop: 69, mobile: 110 },
+ { date: "2024-06-14", desktop: 362, mobile: 325 },
+ { date: "2024-06-15", desktop: 261, mobile: 295 },
+ { date: "2024-06-16", desktop: 315, mobile: 265 },
+ { date: "2024-06-17", desktop: 404, mobile: 440 },
+ { date: "2024-06-18", desktop: 91, mobile: 145 },
+ { date: "2024-06-19", desktop: 290, mobile: 245 },
+ { date: "2024-06-20", desktop: 347, mobile: 380 },
+ { date: "2024-06-21", desktop: 144, mobile: 180 },
+ { date: "2024-06-22", desktop: 269, mobile: 230 },
+ { date: "2024-06-23", desktop: 408, mobile: 450 },
+ { date: "2024-06-24", desktop: 112, mobile: 155 },
+ { date: "2024-06-25", desktop: 119, mobile: 165 },
+ { date: "2024-06-26", desktop: 369, mobile: 325 },
+ { date: "2024-06-27", desktop: 381, mobile: 415 },
+ { date: "2024-06-28", desktop: 127, mobile: 170 },
+ { date: "2024-06-29", desktop: 87, mobile: 135 },
+ { date: "2024-06-30", desktop: 379, mobile: 340 },
+];
+export const chartData3 = [
+ { date: "2024-04-01", desktop: 250, mobile: 175 },
+ { date: "2024-04-02", desktop: 110, mobile: 200 },
+ { date: "2024-04-03", desktop: 190, mobile: 135 },
+ { date: "2024-04-04", desktop: 275, mobile: 290 },
+ { date: "2024-04-05", desktop: 420, mobile: 325 },
+ { date: "2024-04-06", desktop: 340, mobile: 380 },
+ { date: "2024-04-07", desktop: 280, mobile: 200 },
+ { date: "2024-04-08", desktop: 460, mobile: 350 },
+ { date: "2024-04-09", desktop: 65, mobile: 120 },
+ { date: "2024-04-10", desktop: 290, mobile: 215 },
+ { date: "2024-04-11", desktop: 365, mobile: 390 },
+ { date: "2024-04-12", desktop: 330, mobile: 235 },
+ { date: "2024-04-13", desktop: 380, mobile: 420 },
+ { date: "2024-04-14", desktop: 155, mobile: 245 },
+ { date: "2024-04-15", desktop: 135, mobile: 190 },
+ { date: "2024-04-16", desktop: 150, mobile: 210 },
+ { date: "2024-04-17", desktop: 500, mobile: 400 },
+ { date: "2024-04-18", desktop: 410, mobile: 450 },
+ { date: "2024-04-19", desktop: 270, mobile: 200 },
+ { date: "2024-04-20", desktop: 100, mobile: 170 },
+ { date: "2024-04-21", desktop: 155, mobile: 220 },
+ { date: "2024-04-22", desktop: 250, mobile: 190 },
+ { date: "2024-04-23", desktop: 155, mobile: 250 },
+ { date: "2024-04-24", desktop: 430, mobile: 320 },
+ { date: "2024-04-25", desktop: 240, mobile: 280 },
+ { date: "2024-04-26", desktop: 85, mobile: 150 },
+ { date: "2024-04-27", desktop: 430, mobile: 470 },
+ { date: "2024-04-28", desktop: 140, mobile: 200 },
+ { date: "2024-04-29", desktop: 350, mobile: 260 },
+ { date: "2024-04-30", desktop: 510, mobile: 420 },
+ { date: "2024-05-01", desktop: 180, mobile: 240 },
+ { date: "2024-05-02", desktop: 325, mobile: 340 },
+ { date: "2024-05-03", desktop: 275, mobile: 210 },
+ { date: "2024-05-04", desktop: 430, mobile: 470 },
+ { date: "2024-05-05", desktop: 530, mobile: 430 },
+ { date: "2024-05-06", desktop: 550, mobile: 580 },
+ { date: "2024-05-07", desktop: 430, mobile: 340 },
+ { date: "2024-05-08", desktop: 165, mobile: 230 },
+ { date: "2024-05-09", desktop: 250, mobile: 200 },
+ { date: "2024-05-10", desktop: 325, mobile: 360 },
+ { date: "2024-05-11", desktop: 370, mobile: 300 },
+ { date: "2024-05-12", desktop: 215, mobile: 260 },
+ { date: "2024-05-13", desktop: 215, mobile: 180 },
+ { date: "2024-05-14", desktop: 500, mobile: 540 },
+ { date: "2024-05-15", desktop: 520, mobile: 420 },
+ { date: "2024-05-16", desktop: 375, mobile: 440 },
+ { date: "2024-05-17", desktop: 550, mobile: 460 },
+ { date: "2024-05-18", desktop: 350, mobile: 390 },
+ { date: "2024-05-19", desktop: 260, mobile: 200 },
+ { date: "2024-05-20", desktop: 195, mobile: 250 },
+ { date: "2024-05-21", desktop: 90, mobile: 150 },
+ { date: "2024-05-22", desktop: 90, mobile: 130 },
+ { date: "2024-05-23", desktop: 280, mobile: 320 },
+ { date: "2024-05-24", desktop: 320, mobile: 240 },
+ { date: "2024-05-25", desktop: 225, mobile: 270 },
+ { date: "2024-05-26", desktop: 235, mobile: 190 },
+ { date: "2024-05-27", desktop: 460, mobile: 500 },
+ { date: "2024-05-28", desktop: 260, mobile: 210 },
+ { date: "2024-05-29", desktop: 90, mobile: 150 },
+ { date: "2024-05-30", desktop: 370, mobile: 310 },
+ { date: "2024-05-31", desktop: 195, mobile: 250 },
+ { date: "2024-06-01", desktop: 195, mobile: 220 },
+ { date: "2024-06-02", desktop: 520, mobile: 450 },
+ { date: "2024-06-03", desktop: 115, mobile: 170 },
+ { date: "2024-06-04", desktop: 490, mobile: 420 },
+ { date: "2024-06-05", desktop: 95, mobile: 150 },
+ { date: "2024-06-06", desktop: 320, mobile: 280 },
+ { date: "2024-06-07", desktop: 355, mobile: 410 },
+ { date: "2024-06-08", desktop: 430, mobile: 350 },
+ { date: "2024-06-09", desktop: 480, mobile: 520 },
+ { date: "2024-06-10", desktop: 175, mobile: 220 },
+ { date: "2024-06-11", desktop: 105, mobile: 170 },
+ { date: "2024-06-12", desktop: 540, mobile: 460 },
+ { date: "2024-06-13", desktop: 90, mobile: 150 },
+ { date: "2024-06-14", desktop: 470, mobile: 420 },
+ { date: "2024-06-15", desktop: 340, mobile: 390 },
+ { date: "2024-06-16", desktop: 410, mobile: 340 },
+ { date: "2024-06-17", desktop: 520, mobile: 570 },
+ { date: "2024-06-18", desktop: 120, mobile: 190 },
+ { date: "2024-06-19", desktop: 380, mobile: 330 },
+ { date: "2024-06-20", desktop: 450, mobile: 500 },
+ { date: "2024-06-21", desktop: 190, mobile: 240 },
+ { date: "2024-06-22", desktop: 350, mobile: 300 },
+ { date: "2024-06-23", desktop: 530, mobile: 580 },
+ { date: "2024-06-24", desktop: 145, mobile: 200 },
+ { date: "2024-06-25", desktop: 160, mobile: 210 },
+ { date: "2024-06-26", desktop: 480, mobile: 420 },
+ { date: "2024-06-27", desktop: 500, mobile: 540 },
+ { date: "2024-06-28", desktop: 165, mobile: 220 },
+ { date: "2024-06-29", desktop: 115, mobile: 170 },
+ { date: "2024-06-30", desktop: 500, mobile: 440 },
+];
+export const chartData4 = [
+ { date: "2024-04-01", desktop: 280, mobile: 190 },
+ { date: "2024-04-02", desktop: 125, mobile: 220 },
+ { date: "2024-04-03", desktop: 210, mobile: 150 },
+ { date: "2024-04-04", desktop: 300, mobile: 310 },
+ { date: "2024-04-05", desktop: 450, mobile: 350 },
+ { date: "2024-04-06", desktop: 370, mobile: 400 },
+ { date: "2024-04-07", desktop: 300, mobile: 215 },
+ { date: "2024-04-08", desktop: 500, mobile: 380 },
+ { date: "2024-04-09", desktop: 70, mobile: 135 },
+ { date: "2024-04-10", desktop: 320, mobile: 230 },
+ { date: "2024-04-11", desktop: 400, mobile: 410 },
+ { date: "2024-04-12", desktop: 360, mobile: 250 },
+ { date: "2024-04-13", desktop: 410, mobile: 450 },
+ { date: "2024-04-14", desktop: 170, mobile: 260 },
+ { date: "2024-04-15", desktop: 150, mobile: 205 },
+ { date: "2024-04-16", desktop: 165, mobile: 230 },
+ { date: "2024-04-17", desktop: 540, mobile: 440 },
+ { date: "2024-04-18", desktop: 440, mobile: 480 },
+ { date: "2024-04-19", desktop: 290, mobile: 215 },
+ { date: "2024-04-20", desktop: 115, mobile: 185 },
+ { date: "2024-04-21", desktop: 170, mobile: 240 },
+ { date: "2024-04-22", desktop: 270, mobile: 205 },
+ { date: "2024-04-23", desktop: 170, mobile: 270 },
+ { date: "2024-04-24", desktop: 470, mobile: 350 },
+ { date: "2024-04-25", desktop: 260, mobile: 300 },
+ { date: "2024-04-26", desktop: 95, mobile: 165 },
+ { date: "2024-04-27", desktop: 470, mobile: 500 },
+ { date: "2024-04-28", desktop: 155, mobile: 220 },
+ { date: "2024-04-29", desktop: 380, mobile: 280 },
+ { date: "2024-04-30", desktop: 550, mobile: 450 },
+ { date: "2024-05-01", desktop: 200, mobile: 260 },
+ { date: "2024-05-02", desktop: 350, mobile: 370 },
+ { date: "2024-05-03", desktop: 300, mobile: 230 },
+ { date: "2024-05-04", desktop: 470, mobile: 500 },
+ { date: "2024-05-05", desktop: 560, mobile: 450 },
+ { date: "2024-05-06", desktop: 590, mobile: 620 },
+ { date: "2024-05-07", desktop: 460, mobile: 370 },
+ { date: "2024-05-08", desktop: 180, mobile: 250 },
+ { date: "2024-05-09", desktop: 270, mobile: 215 },
+ { date: "2024-05-10", desktop: 350, mobile: 390 },
+ { date: "2024-05-11", desktop: 400, mobile: 330 },
+ { date: "2024-05-12", desktop: 230, mobile: 280 },
+ { date: "2024-05-13", desktop: 230, mobile: 190 },
+ { date: "2024-05-14", desktop: 540, mobile: 580 },
+ { date: "2024-05-15", desktop: 550, mobile: 450 },
+ { date: "2024-05-16", desktop: 400, mobile: 470 },
+ { date: "2024-05-17", desktop: 590, mobile: 490 },
+ { date: "2024-05-18", desktop: 380, mobile: 420 },
+ { date: "2024-05-19", desktop: 280, mobile: 215 },
+ { date: "2024-05-20", desktop: 210, mobile: 270 },
+ { date: "2024-05-21", desktop: 100, mobile: 170 },
+ { date: "2024-05-22", desktop: 100, mobile: 145 },
+ { date: "2024-05-23", desktop: 300, mobile: 340 },
+ { date: "2024-05-24", desktop: 350, mobile: 260 },
+ { date: "2024-05-25", desktop: 240, mobile: 290 },
+ { date: "2024-05-26", desktop: 250, mobile: 205 },
+ { date: "2024-05-27", desktop: 500, mobile: 540 },
+ { date: "2024-05-28", desktop: 280, mobile: 230 },
+ { date: "2024-05-29", desktop: 100, mobile: 170 },
+ { date: "2024-05-30", desktop: 400, mobile: 330 },
+ { date: "2024-05-31", desktop: 210, mobile: 270 },
+ { date: "2024-06-01", desktop: 210, mobile: 240 },
+ { date: "2024-06-02", desktop: 560, mobile: 480 },
+ { date: "2024-06-03", desktop: 125, mobile: 185 },
+ { date: "2024-06-04", desktop: 520, mobile: 450 },
+ { date: "2024-06-05", desktop: 105, mobile: 165 },
+ { date: "2024-06-06", desktop: 350, mobile: 300 },
+ { date: "2024-06-07", desktop: 380, mobile: 440 },
+ { date: "2024-06-08", desktop: 470, mobile: 380 },
+ { date: "2024-06-09", desktop: 510, mobile: 550 },
+ { date: "2024-06-10", desktop: 190, mobile: 240 },
+ { date: "2024-06-11", desktop: 115, mobile: 185 },
+ { date: "2024-06-12", desktop: 570, mobile: 490 },
+ { date: "2024-06-13", desktop: 100, mobile: 165 },
+ { date: "2024-06-14", desktop: 500, mobile: 450 },
+ { date: "2024-06-15", desktop: 370, mobile: 420 },
+ { date: "2024-06-16", desktop: 440, mobile: 370 },
+ { date: "2024-06-17", desktop: 560, mobile: 600 },
+ { date: "2024-06-18", desktop: 130, mobile: 200 },
+ { date: "2024-06-19", desktop: 410, mobile: 350 },
+ { date: "2024-06-20", desktop: 490, mobile: 530 },
+ { date: "2024-06-21", desktop: 205, mobile: 260 },
+];
diff --git a/src/data/population.json b/src/data/population.json
new file mode 100644
index 0000000..66fbe93
--- /dev/null
+++ b/src/data/population.json
@@ -0,0 +1,236 @@
+{
+ "wilayas": [
+ {
+ "name": "Adrar",
+ "population": 402197
+ },
+ {
+ "name": "Chlef",
+ "population": 1010000
+ },
+ {
+ "name": "Laghouat",
+ "population": 455602
+ },
+ {
+ "name": "Oum El Bouaghi",
+ "population": 621612
+ },
+ {
+ "name": "Batna",
+ "population": 1119970
+ },
+ {
+ "name": "Béjaïa",
+ "population": 912577
+ },
+ {
+ "name": "Biskra",
+ "population": 721356
+ },
+ {
+ "name": "Béchar",
+ "population": 270061
+ },
+ {
+ "name": "Blida",
+ "population": 1000000
+ },
+ {
+ "name": "Bouira",
+ "population": 695583
+ },
+ {
+ "name": "Tamanrasset",
+ "population": 176637
+ },
+ {
+ "name": "Tébessa",
+ "population": 648703
+ },
+ {
+ "name": "Tlemcen",
+ "population": 949135
+ },
+ {
+ "name": "Tiaret",
+ "population": 846823
+ },
+ {
+ "name": "Tizi Ouzou",
+ "population": 1118990
+ },
+ {
+ "name": "Alger",
+ "population": 2940000
+ },
+ {
+ "name": "Djelfa",
+ "population": 1192000
+ },
+ {
+ "name": "Jijel",
+ "population": 636948
+ },
+ {
+ "name": "Sétif",
+ "population": 1500000
+ },
+ {
+ "name": "Saïda",
+ "population": 330641
+ },
+ {
+ "name": "Skikda",
+ "population": 898680
+ },
+ {
+ "name": "Sidi Bel Abbès",
+ "population": 604744
+ },
+ {
+ "name": "Annaba",
+ "population": 609499
+ },
+ {
+ "name": "Guelma",
+ "population": 482430
+ },
+ {
+ "name": "Constantine",
+ "population": 938475
+ },
+ {
+ "name": "Médéa",
+ "population": 819932
+ },
+ {
+ "name": "Mostaganem",
+ "population": 737118
+ },
+ {
+ "name": "M\'Sila",
+ "population": 990591
+ },
+ {
+ "name": "Mascara",
+ "population": 784073
+ },
+ {
+ "name": "Ouargla",
+ "population": 558558
+ },
+ {
+ "name": "Oran",
+ "population": 1500000
+ },
+ {
+ "name": "El Bayadh",
+ "population": 228624
+ },
+ {
+ "name": "Illizi",
+ "population": 52276
+ },
+ {
+ "name": "Bordj Bou Arréridj",
+ "population": 628475
+ },
+ {
+ "name": "Boumerdès",
+ "population": 802083
+ },
+ {
+ "name": "El Tarf",
+ "population": 408414
+ },
+ {
+ "name": "Tindouf",
+ "population": 49045
+ },
+ {
+ "name": "Tissemsilt",
+ "population": 294476
+ },
+ {
+ "name": "El Oued",
+ "population": 647548
+ },
+ {
+ "name": "Khenchela",
+ "population": 386683
+ },
+ {
+ "name": "Souk Ahras",
+ "population": 438127
+ },
+ {
+ "name": "Tipaza",
+ "population": 591010
+ },
+ {
+ "name": "Mila",
+ "population": 766886
+ },
+ {
+ "name": "Aïn Defla",
+ "population": 766013
+ },
+ {
+ "name": "Naâma",
+ "population": 192891
+ },
+ {
+ "name": "Aïn Témouchent",
+ "population": 371239
+ },
+ {
+ "name": "Ghardaïa",
+ "population": 363598
+ },
+ {
+ "name": "Relizane",
+ "population": 726180
+ },
+ {
+ "name": "Timimoun",
+ "population": 122019
+ },
+ {
+ "name": "Bordj Badji Mokhtar",
+ "population": 16037
+ },
+ {
+ "name": "Ouled Djellal",
+ "population": 174219
+ },
+ {
+ "name": "Béni Abbès",
+ "population": 50063
+ },
+ {
+ "name": "In Salah",
+ "population": 50392
+ },
+ {
+ "name": "In Guezzam",
+ "population": 11072
+ },
+ {
+ "name": "Touggourt",
+ "population": 247221
+ },
+ {
+ "name": "Djanet",
+ "population": 17577
+ },
+ {
+ "name": "El M\'Ghair",
+ "population": 162267
+ },
+ {
+ "name": "El Meniaa",
+ "population": 57276
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..59513d7
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,12 @@
+import { updateSession } from "@/utils/supabase/middleware";
+import { type NextRequest } from "next/server";
+
+export async function middleware(request: NextRequest) {
+ return await updateSession(request);
+}
+
+export const config = {
+ matcher: [
+ "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
+ ],
+};
diff --git a/src/pages/Access.tsx b/src/pages/Access.tsx
index aeb4d99..939a8ac 100644
--- a/src/pages/Access.tsx
+++ b/src/pages/Access.tsx
@@ -54,7 +54,7 @@ import {
} from "@/components/ui/select"
// Define the User type
-export type Role = "employee" | "admin";
+export type Role = "employee" | "admin" | "manager";
export type User = {
user_id: string;
@@ -62,7 +62,7 @@ export type User = {
email: string;
name: string;
rfid_code: string;
- role: Role;
+ role: Role[]; // Changed to array of Role
created_at: Date;
updated_at: Date;
};
@@ -71,45 +71,47 @@ const generateUserId = (): string => {
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
};
-const initialData: User[] = [
- {
- user_id: generateUserId(),
- profile_image: null,
- email: "john.doe@example.com",
- name: "John Doe",
- rfid_code: "12345",
- role: "employee",
- created_at: new Date(),
- updated_at: new Date(),
- },
- {
- user_id: generateUserId(),
- profile_image: null,
- email: "jane.smith@example.com",
- name: "Jane Smith",
- rfid_code: "67890",
- role: "admin",
- created_at: new Date(),
- updated_at: new Date(),
- },
- {
- user_id: generateUserId(),
- profile_image: null,
- email: "peter.jones@example.com",
- name: "Peter Jones",
- rfid_code: "98765",
- role: "employee",
- created_at: new Date(),
- updated_at: new Date(),
- },
-];
-
-// --- Edit Dialog Component ---
-interface EditUserDialogProps {
- user: User | null;
- isOpen: boolean;
- onOpenChange: (open: boolean) => void;
- onSave: (updatedUser: User) => void;
+// function to generate number of random users data
+const generateRandomUsersData = (num: number): User[] => {
+ const users = [] as User[];
+ const roles: Role[] = ["employee", "admin", "manager"]; // Define available roles
+ for (let i = 0; i < num; i++) {
+ // Randomly determine the number of roles for the user (1 to all roles)
+ const numRoles = Math.floor(Math.random() * roles.length) + 1;
+ const userRoles: Role[] = [];
+
+ // Assign random roles to the user
+ for (let j = 0; j < numRoles; j++) {
+ const randomRole = roles[Math.floor(Math.random() * roles.length)];
+ if (!userRoles.includes(randomRole)) { // Ensure no duplicate roles
+ userRoles.push(randomRole);
+ }
+ }
+
+ const user: User = {
+ user_id: generateUserId(),
+ profile_image: Math.random() > 0.5 ? `https://randomuser.me/api/portraits/${Math.random() > 0.5 ? 'men' : 'women'}/${i % 99}.jpg` : null,
+ email: `user${i}@example.com`,
+ name: `User ${i}`,
+ rfid_code: Math.floor(Math.random() * 1000000000).toString().padStart(10, '0'),
+ role: userRoles, // Assign the array of roles
+ created_at: new Date(Date.now() - Math.floor(Math.random() * 10000000000)),
+ updated_at: new Date()
+ };
+ users.push(user);
+ }
+ return users;
+};
+
+
+const initialData: User[] = generateRandomUsersData(100); // Generate 100 random users
+
+ // --- Edit Dialog Component ---
+ interface EditUserDialogProps {
+ user: User | null;
+isOpen: boolean;
+onOpenChange: (open: boolean) => void;
+onSave: (updatedUser: User) => void;
}
function EditUserDialog({ user, isOpen, onOpenChange, onSave }: EditUserDialogProps) {
@@ -140,7 +142,7 @@ function EditUserDialog({ user, isOpen, onOpenChange, onSave }: EditUserDialogPr
}
};
- const handleRoleChange = (value: User["role"]) => {
+ const handleRoleChange = (value: Role[]) => {
if (editedUser) {
setEditedUser({
...editedUser,
@@ -180,6 +182,8 @@ function EditUserDialog({ user, isOpen, onOpenChange, onSave }: EditUserDialogPr
if (!user || !editedUser) return null;
+ const roles: Role[] = ["employee", "admin", "manager"];
+
return (
@@ -195,7 +199,7 @@ function EditUserDialog({ user, isOpen, onOpenChange, onSave }: EditUserDialogPr
@@ -262,15 +266,25 @@ function EditUserDialog({ user, isOpen, onOpenChange, onSave }: EditUserDialogPr