Initial commit for new panel

This commit is contained in:
AmirReza Jamali
2025-09-09 11:20:26 +03:30
commit 1d4ccb3575
343 changed files with 20031 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
import { DotIcon } from "@/assets/icons";
import { formatMessageTime } from "@/lib/format-message-time";
import { cn } from "@/lib/utils";
import Image from "next/image";
import Link from "next/link";
import { getChatsData } from "../fetch";
export async function ChatsCard() {
const data = await getChatsData();
return (
<div className="col-span-12 rounded-[10px] bg-white py-6 shadow-1 dark:bg-gray-dark dark:shadow-card xl:col-span-4">
<h2 className="mb-5.5 px-7.5 text-body-2xlg font-bold text-dark dark:text-white">
Chats
</h2>
<ul>
{data.map((chat, key) => (
<li key={key}>
<Link
href="/"
className="flex items-center gap-4.5 px-7.5 py-3 outline-none hover:bg-gray-2 focus-visible:bg-gray-2 dark:hover:bg-dark-2 dark:focus-visible:bg-dark-2"
>
<div className="relative shrink-0">
<Image
src={chat.profile}
width={56}
height={56}
className="size-14 rounded-full object-cover"
alt={"Avatar for " + chat.name}
/>
<span
className={cn(
"absolute bottom-0 right-0 size-3.5 rounded-full ring-2 ring-white dark:ring-dark-2",
chat.isActive ? "bg-green" : "bg-orange-light",
)}
/>
</div>
<div className="relative flex-grow">
<h3 className="font-medium text-dark dark:text-white">
{chat.name}
</h3>
<div className="flex flex-wrap items-center gap-2">
<span
className={cn(
"truncate text-sm font-medium dark:text-dark-5 xl:max-w-[8rem]",
chat.unreadCount && "text-dark-4 dark:text-dark-6",
)}
>
{chat.lastMessage.content}
</span>
<DotIcon />
<time
className="text-xs"
dateTime={chat.lastMessage.timestamp}
>
{formatMessageTime(chat.lastMessage.timestamp)}
</time>
</div>
{!!chat.unreadCount && (
<div className="pointer-events-none absolute right-0 top-1/2 aspect-square max-w-fit -translate-y-1/2 select-none rounded-full bg-primary px-2 py-0.5 text-sm font-medium text-white">
{chat.unreadCount}
</div>
)}
</div>
</Link>
</li>
))}
</ul>
</div>
);
}
@@ -0,0 +1,53 @@
import { ArrowDownIcon, ArrowUpIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import type { JSX, SVGProps } from "react";
type PropsType = {
label: string;
data: {
value: number | string;
growthRate: number;
};
Icon: (props: SVGProps<SVGSVGElement>) => JSX.Element;
};
export function OverviewCard({ label, data, Icon }: PropsType) {
const isDecreasing = data.growthRate < 0;
return (
<div className="rounded-[10px] bg-white p-6 shadow-1 dark:bg-gray-dark">
<Icon />
<div className="mt-6 flex items-end justify-between">
<dl>
<dt className="mb-1.5 text-heading-6 font-bold text-dark dark:text-white">
{data.value}
</dt>
<dd className="text-sm font-medium text-dark-6">{label}</dd>
</dl>
<dl
className={cn(
"text-sm font-medium",
isDecreasing ? "text-red" : "text-green",
)}
>
<dt className="flex items-center gap-1.5">
{data.growthRate}%
{isDecreasing ? (
<ArrowDownIcon aria-hidden />
) : (
<ArrowUpIcon aria-hidden />
)}
</dt>
<dd className="sr-only">
{label} {isDecreasing ? "Decreased" : "Increased"} by{" "}
{data.growthRate}%
</dd>
</dl>
</div>
</div>
);
}
@@ -0,0 +1,73 @@
import type { SVGProps } from "react";
type SVGPropsType = SVGProps<SVGSVGElement>;
export function Views(props: SVGPropsType) {
return (
<svg width={58} height={58} viewBox="0 0 58 58" fill="none" {...props}>
<circle cx={29} cy={29} r={29} fill="#3FD97F" />
<path
d="M26.562 29a2.437 2.437 0 114.875 0 2.437 2.437 0 01-4.875 0z"
fill="#fff"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18.166 29c0 1.776.46 2.374 1.382 3.57 1.838 2.389 4.922 5.097 9.452 5.097s7.614-2.708 9.452-5.096c.92-1.197 1.381-1.795 1.381-3.57 0-1.777-.46-2.375-1.381-3.571-1.838-2.389-4.922-5.096-9.452-5.096s-7.614 2.707-9.452 5.096c-.921 1.196-1.381 1.794-1.381 3.57zM29 24.938a4.063 4.063 0 100 8.125 4.063 4.063 0 000-8.125z"
fill="#fff"
/>
</svg>
);
}
export function Profit(props: SVGPropsType) {
return (
<svg width={58} height={58} viewBox="0 0 58 58" fill="none" {...props}>
<circle cx={29} cy={29} r={29} fill="#FF9C55" />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M29 39.833c5.983 0 10.833-4.85 10.833-10.833 0-5.983-4.85-10.834-10.833-10.834-5.983 0-10.834 4.85-10.834 10.834 0 5.983 4.85 10.833 10.834 10.833zm.812-17.333a.812.812 0 10-1.625 0v.343c-1.766.316-3.25 1.643-3.25 3.448 0 2.077 1.964 3.521 4.063 3.521 1.491 0 2.437.982 2.437 1.896 0 .915-.946 1.896-2.437 1.896-1.491 0-2.438-.981-2.438-1.896a.812.812 0 10-1.625 0c0 1.805 1.484 3.132 3.25 3.449v.343a.812.812 0 101.625 0v-.343c1.767-.317 3.25-1.644 3.25-3.449 0-2.077-1.963-3.52-4.062-3.52-1.491 0-2.438-.982-2.438-1.896 0-.915.947-1.896 2.438-1.896s2.437.98 2.437 1.895a.813.813 0 001.625 0c0-1.805-1.483-3.132-3.25-3.448V22.5z"
fill="#fff"
/>
</svg>
);
}
export function Product(props: SVGPropsType) {
return (
<svg width={58} height={58} viewBox="0 0 58 58" fill="none" {...props}>
<circle cx={29} cy={29} r={29} fill="#8155FF" />
<path
d="M35.043 20.8l-2.167-1.136c-1.902-.998-2.853-1.498-3.876-1.498-1.023 0-1.974.5-3.876 1.498L22.958 20.8c-1.922 1.008-3.051 1.6-3.752 2.394L29 28.09l9.794-4.896c-.7-.793-1.83-1.386-3.751-2.394zM39.56 24.628l-9.747 4.874v10.227c.777-.194 1.662-.658 3.063-1.393l2.167-1.137c2.33-1.223 3.496-1.835 4.143-2.934.647-1.099.647-2.467.647-5.202v-.127c0-2.05 0-3.332-.272-4.308zM28.188 39.73V29.501l-9.749-4.874c-.272.976-.272 2.258-.272 4.308v.127c0 2.735 0 4.103.647 5.202.647 1.1 1.813 1.71 4.144 2.934l2.166 1.137c1.4.735 2.286 1.2 3.064 1.393z"
fill="#fff"
/>
</svg>
);
}
export function Users(props: SVGPropsType) {
return (
<svg width={58} height={58} viewBox="0 0 58 58" fill="none" {...props}>
<circle cx={29} cy={29} r={29} fill="#18BFFF" />
<ellipse
cx={25.7511}
cy={22.4998}
rx={4.33333}
ry={4.33333}
fill="#fff"
/>
<ellipse
cx={25.7511}
cy={34.4178}
rx={7.58333}
ry={4.33333}
fill="#fff"
/>
<path
d="M38.75 34.417c0 1.795-2.206 3.25-4.898 3.25.793-.867 1.339-1.955 1.339-3.248 0-1.295-.547-2.384-1.342-3.252 2.693 0 4.9 1.455 4.9 3.25zM35.5 22.501a3.25 3.25 0 01-4.364 3.054 6.163 6.163 0 00.805-3.055c0-1.11-.293-2.152-.804-3.053A3.25 3.25 0 0135.5 22.5z"
fill="#fff"
/>
</svg>
);
}
@@ -0,0 +1,48 @@
import { compactFormat } from "@/lib/format-number";
import { getOverviewData } from "../../fetch";
import { OverviewCard } from "./card";
import * as icons from "./icons";
export async function OverviewCardsGroup() {
const { views, profit, products, users } = await getOverviewData();
return (
<div className="grid gap-4 sm:grid-cols-2 sm:gap-6 xl:grid-cols-4 2xl:gap-7.5">
<OverviewCard
label="Total Views"
data={{
...views,
value: compactFormat(views.value),
}}
Icon={icons.Views}
/>
<OverviewCard
label="Total Profit"
data={{
...profit,
value: "$" + compactFormat(profit.value),
}}
Icon={icons.Profit}
/>
<OverviewCard
label="Total Products"
data={{
...products,
value: compactFormat(products.value),
}}
Icon={icons.Product}
/>
<OverviewCard
label="Total Users"
data={{
...users,
value: compactFormat(users.value),
}}
Icon={icons.Users}
/>
</div>
);
}
@@ -0,0 +1,26 @@
import { Skeleton } from "@/components/ui/skeleton";
export function OverviewCardsSkeleton() {
return (
<div className="grid gap-4 sm:grid-cols-2 sm:gap-6 xl:grid-cols-4 2xl:gap-7.5">
{Array.from({ length: 4 }).map((_, i) => (
<div
key={i}
className="rounded-[10px] bg-white p-6 shadow-1 dark:bg-gray-dark"
>
<Skeleton className="size-12 rounded-full" />
<div className="mt-6 flex items-end justify-between">
<div>
<Skeleton className="mb-1.5 h-7 w-18" />
<Skeleton className="h-5 w-20" />
</div>
<Skeleton className="h-5 w-15" />
</div>
</div>
))}
</div>
);
}
@@ -0,0 +1,17 @@
"use client";
import dynamic from "next/dynamic";
const Map = dynamic(() => import("./map"), { ssr: false });
export function RegionLabels() {
return (
<div className="col-span-12 rounded-[10px] bg-white p-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card xl:col-span-7">
<h2 className="mb-7 text-body-2xlg font-bold text-dark dark:text-white">
Region labels
</h2>
<Map />
</div>
);
}
@@ -0,0 +1,47 @@
"use client";
import jsVectorMap from "jsvectormap";
import { useEffect } from "react";
import "@/js/us-aea-en";
export default function Map() {
useEffect(() => {
new jsVectorMap({
selector: "#mapOne",
map: "us_aea_en",
zoomButtons: true,
regionStyle: {
initial: {
fill: "#C8D0D8",
},
hover: {
fillOpacity: 1,
fill: "#3056D3",
},
},
regionLabelStyle: {
initial: {
fontWeight: "semibold",
fill: "#fff",
},
hover: {
cursor: "pointer",
},
},
labels: {
regions: {
render(code: string) {
return code.split("-")[1];
},
},
},
});
}, []);
return (
<div className="h-[422px]">
<div id="mapOne" className="mapOne map-btn" />
</div>
);
}
+91
View File
@@ -0,0 +1,91 @@
export async function getOverviewData() {
// Fake delay
await new Promise((resolve) => setTimeout(resolve, 2000));
return {
views: {
value: 3456,
growthRate: 0.43,
},
profit: {
value: 4220,
growthRate: 4.35,
},
products: {
value: 3456,
growthRate: 2.59,
},
users: {
value: 3456,
growthRate: -0.95,
},
};
}
export async function getChatsData() {
// Fake delay
await new Promise((resolve) => setTimeout(resolve, 1000));
return [
{
name: "Jacob Jones",
profile: "/images/user/user-01.png",
isActive: true,
lastMessage: {
content: "See you tomorrow at the meeting!",
type: "text",
timestamp: "2024-12-19T14:30:00Z",
isRead: false,
},
unreadCount: 3,
},
{
name: "Wilium Smith",
profile: "/images/user/user-03.png",
isActive: true,
lastMessage: {
content: "Thanks for the update",
type: "text",
timestamp: "2024-12-19T10:15:00Z",
isRead: true,
},
unreadCount: 0,
},
{
name: "Johurul Haque",
profile: "/images/user/user-04.png",
isActive: false,
lastMessage: {
content: "What's up?",
type: "text",
timestamp: "2024-12-19T10:15:00Z",
isRead: true,
},
unreadCount: 0,
},
{
name: "M. Chowdhury",
profile: "/images/user/user-05.png",
isActive: false,
lastMessage: {
content: "Where are you now?",
type: "text",
timestamp: "2024-12-19T10:15:00Z",
isRead: true,
},
unreadCount: 2,
},
{
name: "Akagami",
profile: "/images/user/user-07.png",
isActive: false,
lastMessage: {
content: "Hey, how are you?",
type: "text",
timestamp: "2024-12-19T10:15:00Z",
isRead: true,
},
unreadCount: 0,
},
];
}
+62
View File
@@ -0,0 +1,62 @@
import { PaymentsOverview } from "@/components/Charts/payments-overview";
import { UsedDevices } from "@/components/Charts/used-devices";
import { WeeksProfit } from "@/components/Charts/weeks-profit";
import { TopChannels } from "@/components/Tables/top-channels";
import { TopChannelsSkeleton } from "@/components/Tables/top-channels/skeleton";
import { createTimeFrameExtractor } from "@/utils/timeframe-extractor";
import { Suspense } from "react";
import { ChatsCard } from "./_components/chats-card";
import { OverviewCardsGroup } from "./_components/overview-cards";
import { OverviewCardsSkeleton } from "./_components/overview-cards/skeleton";
import { RegionLabels } from "./_components/region-labels";
type PropsType = {
searchParams: Promise<{
selected_time_frame?: string;
}>;
};
export default async function Home({ searchParams }: PropsType) {
const { selected_time_frame } = await searchParams;
const extractTimeFrame = createTimeFrameExtractor(selected_time_frame);
return (
<>
<Suspense fallback={<OverviewCardsSkeleton />}>
<OverviewCardsGroup />
</Suspense>
<div className="mt-4 grid grid-cols-12 gap-4 md:mt-6 md:gap-6 2xl:mt-9 2xl:gap-7.5">
<PaymentsOverview
className="col-span-12 xl:col-span-7"
key={extractTimeFrame("payments_overview")}
timeFrame={extractTimeFrame("payments_overview")?.split(":")[1]}
/>
<WeeksProfit
key={extractTimeFrame("weeks_profit")}
timeFrame={extractTimeFrame("weeks_profit")?.split(":")[1]}
className="col-span-12 xl:col-span-5"
/>
<UsedDevices
className="col-span-12 xl:col-span-5"
key={extractTimeFrame("used_devices")}
timeFrame={extractTimeFrame("used_devices")?.split(":")[1]}
/>
<RegionLabels />
<div className="col-span-12 grid xl:col-span-8">
<Suspense fallback={<TopChannelsSkeleton />}>
<TopChannels />
</Suspense>
</div>
<Suspense fallback={null}>
<ChatsCard />
</Suspense>
</div>
</>
);
}
+20
View File
@@ -0,0 +1,20 @@
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CreateAdminForm from "@/components/forms/admins/CreateAdmin";
interface IProps {}
const CreateAdminPage = ({}: IProps) => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Admins", href: "/admins" },
{ name: "Create Admin", href: "/admins/create" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CreateAdminForm />
</>
);
};
export default CreateAdminPage;
+26
View File
@@ -0,0 +1,26 @@
"use client";
import Loading from "@/app/loading";
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CreateAdminForm from "@/components/forms/admins/CreateAdmin";
import { useAdminDetails } from "@/hooks/queries";
import React, { use } from "react";
const AdminEditPage = ({ params }: { params: Promise<{ id: string }> }) => {
const { id } = use(params);
const { data: adminDetails, isLoading } = useAdminDetails(id);
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Admins", href: "/admins" },
{ name: "Edit Admin", href: `/admins/edit/${id}` },
];
if (isLoading) return <Loading />;
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CreateAdminForm editMode defaultValues={adminDetails?.data} id={id} />
</>
);
};
export default AdminEditPage;
+25
View File
@@ -0,0 +1,25 @@
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import AdminsTable from "@/components/Tables/admins";
import { AdminsSkeleton } from "@/components/Tables/admins/Skeleton";
import { Metadata } from "next";
import { Suspense } from "react";
export const metadata: Metadata = {
title: "Admins Page",
};
const AdminsPage = () => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Admins", href: "/admins" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<Suspense fallback={<AdminsSkeleton />}>
<AdminsTable />
</Suspense>
</>
);
};
export default AdminsPage;
+22
View File
@@ -0,0 +1,22 @@
import Signin from "@/components/Auth/Signin";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Sign in",
};
export default function SignIn() {
return (
<div className="flex h-svh flex-col items-center justify-center">
<div className="shadow-3xl m-auto flex w-1/2 flex-col items-center justify-center rounded-2xl bg-white dark:bg-gray-dark dark:shadow-card">
<div className="flex w-full flex-wrap items-center justify-center">
<div className="w-full xl:w-1/2">
<div className="w-full p-4 sm:p-12.5 xl:p-15">
<Signin />
</div>
</div>
</div>
</div>
</div>
);
}
+17
View File
@@ -0,0 +1,17 @@
import CalendarBox from "@/components/CalenderBox";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Calender Page",
// other metadata
};
const CalendarPage = () => {
return (
<>
<CalendarBox />
</>
);
};
export default CalendarPage;
@@ -0,0 +1 @@
/Users/amirrezajamali/Documents/Dev/tender/src/app/(companies)/companies
+35
View File
@@ -0,0 +1,35 @@
import { CampaignVisitors } from "@/components/Charts/campaign-visitors";
import { UsedDevices } from "@/components/Charts/used-devices";
import { createTimeFrameExtractor } from "@/utils/timeframe-extractor";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Basic Chart",
};
type PropsType = {
searchParams: Promise<{
selected_time_frame?: string;
}>;
};
export default async function Page(props: PropsType) {
const { selected_time_frame } = await props.searchParams;
const extractTimeFrame = createTimeFrameExtractor(selected_time_frame);
return (
<>
<div className="grid grid-cols-12 gap-4 md:gap-6 2xl:gap-7.5">
<UsedDevices
key={extractTimeFrame("used_devices")}
timeFrame={extractTimeFrame("used_devices")?.split(":")[1]}
className="col-span-12 xl:col-span-5"
/>
<div className="col-span-12 xl:col-span-5">
<CampaignVisitors />
</div>
</div>
</>
);
}
+19
View File
@@ -0,0 +1,19 @@
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CreateAdminForm from "@/components/forms/admins/CreateAdmin";
import CreateCompany from "@/components/forms/companies/CreateCompany";
const CreateCompanyPage = () => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Company", href: "/companies" },
{ name: "Create company", href: "/companies/create" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CreateCompany />
</>
);
};
export default CreateCompanyPage;
+26
View File
@@ -0,0 +1,26 @@
"use client";
import Loading from "@/app/loading";
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CreateCompany from "@/components/forms/companies/CreateCompany";
import { useCompanyDetails } from "@/hooks/queries";
import { use } from "react";
const EditCompanyPage = ({ params }: { params: Promise<{ id: string }> }) => {
const { id } = use(params);
const { isLoading, data } = useCompanyDetails(id);
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Company", href: "/companies" },
{ name: "Edit company", href: `/companies/edit/${id}` },
];
if (isLoading) return <Loading />;
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CreateCompany editMode defaultValues={data.data} id={id} />
</>
);
};
export default EditCompanyPage;
+17
View File
@@ -0,0 +1,17 @@
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CompaniesTable from "@/components/Tables/companies";
const Companies = () => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Companies", href: "/companies" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CompaniesTable />
</>
);
};
export default Companies;
+20
View File
@@ -0,0 +1,20 @@
"use client";
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CreateCustomer from "@/components/forms/customers/CreateCustomer";
const CreateCustomerPage = () => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Customers", href: "/customers" },
{ name: "Create Customer", href: "/customers/create" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CreateCustomer />
</>
);
};
export default CreateCustomerPage;
+7
View File
@@ -0,0 +1,7 @@
import { ShadowBox } from "@/src/components";
const EditCustomer = () => {
return <ShadowBox>Edit customer</ShadowBox>;
};
export default EditCustomer;
+17
View File
@@ -0,0 +1,17 @@
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import CustomersTable from "@/components/Tables/customers";
const CustomersPage = () => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Customers", href: "/customers" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<CustomersTable />
</>
);
};
export default CustomersPage;
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+133
View File
@@ -0,0 +1,133 @@
import type { Metadata } from "next";
import { GlobeIcon } from "@/assets/icons";
import DatePickerOne from "@/components/FormElements/DatePicker/DatePickerOne";
import DatePickerTwo from "@/components/FormElements/DatePicker/DatePickerTwo";
import InputGroup from "@/components/FormElements/InputGroup";
import { TextAreaGroup } from "@/components/FormElements/InputGroup/text-area";
import MultiSelect from "@/components/FormElements/MultiSelect";
import { Checkbox } from "@/components/FormElements/checkbox";
import { RadioInput } from "@/components/FormElements/radio";
import { Select } from "@/components/FormElements/select";
import { Switch } from "@/components/FormElements/switch";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
export const metadata: Metadata = {
title: "Form Elements",
};
export default function FormElementsPage() {
return (
<>
<div className="grid grid-cols-1 gap-9 sm:grid-cols-2">
<div className="flex flex-col gap-9">
<ShowcaseSection title="Input Fields" className="space-y-5.5 !p-6.5">
{/* <InputGroup
label="Default input"
placeholder="Default input text"
type="text"
name="default"
/> */}
<div>hello</div>
{/* <InputGroup
label="Active input"
placeholder="Active input text"
active
type="text"
/>
<InputGroup
label="Disabled input"
placeholder="Disabled input text"
type="text"
disabled
/> */}
</ShowcaseSection>
<ShowcaseSection
title="Toggle switch input"
className="space-y-5.5 !p-6.5"
>
<Switch />
<Switch backgroundSize="sm" />
<Switch withIcon />
<Switch background="dark" />
</ShowcaseSection>
<ShowcaseSection title="Time and date" className="space-y-5.5 !p-6.5">
<DatePickerOne />
<DatePickerTwo />
</ShowcaseSection>
<ShowcaseSection title="File upload" className="space-y-5.5 !p-6.5">
<div>hello</div>
{/* <InputGroup
type="file"
fileStyleVariant="style1"
label="Attach file"
placeholder="Attach file"
name="file2"
/>
<InputGroup
name="file"
type="file"
fileStyleVariant="style2"
label="Attach file"
placeholder="Attach file"
/> */}
</ShowcaseSection>
</div>
<div className="flex flex-col gap-9">
<ShowcaseSection title="Textarea Fields" className="space-y-6 !p-6.5">
<div>hello</div>
{/* <TextAreaGroup
label="Default textarea"
placeholder="Default textarea"
/>
<TextAreaGroup
label="Active textarea"
placeholder="Active textarea"
active
/>
<TextAreaGroup
label="Disabled textarea"
placeholder="Disabled textarea"
disabled
/> */}
</ShowcaseSection>
<ShowcaseSection title="Select input" className="space-y-5.5 !p-6.5">
{/* <Select
label="Select Country"
items={[
{ label: "United States", value: "USA" },
{ label: "United Kingdom", value: "UK" },
{ label: "Canada", value: "Canada" },
]}
defaultValue="USA"
prefixIcon={<GlobeIcon />}
/> */}
<div>hello</div>
{/* <MultiSelect id="multiSelect" /> */}
</ShowcaseSection>
<ShowcaseSection
title="Checkbox and radio"
className="space-y-5.5 !p-6.5"
>
<Checkbox label="Checkbox Text" />
<Checkbox label="Checkbox Text" withIcon="check" />
<Checkbox label="Checkbox Text" withIcon="x" />
<RadioInput label="Checkbox Text" />
<RadioInput label="Checkbox Text" variant="circle" />
</ShowcaseSection>
</div>
</div>
</>
);
}
@@ -0,0 +1,60 @@
import InputGroup from "@/components/FormElements/InputGroup";
import { TextAreaGroup } from "@/components/FormElements/InputGroup/text-area";
import { Select } from "@/components/FormElements/select";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
export function ContactForm() {
return (
<ShowcaseSection title="Contact Form" className="!p-6.5">
<form action="#">
<div className="mb-4.5 flex flex-col gap-4.5 xl:flex-row">
<InputGroup
label="First name"
type="text"
placeholder="Enter your first name"
className="w-full xl:w-1/2"
/>
<InputGroup
label="Last name"
type="text"
placeholder="Enter your last name"
className="w-full xl:w-1/2"
/>
</div>
<InputGroup
label="Email"
type="email"
placeholder="Enter your email address"
className="mb-4.5"
required
/>
<InputGroup
label="Subject"
type="text"
placeholder="Enter your subject"
className="mb-4.5"
/>
<Select
label="Subject"
placeholder="Select your subject"
className="mb-4.5"
items={[
{ label: "United States", value: "USA" },
{ label: "United Kingdom", value: "UK" },
{ label: "Canada", value: "Canada" },
]}
/>
<TextAreaGroup label="Message" placeholder="Type your message" />
<button className="mt-6 flex w-full justify-center rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90">
Send Message
</button>
</form>
</ShowcaseSection>
);
}
@@ -0,0 +1,37 @@
import { Checkbox } from "@/components/FormElements/checkbox";
import InputGroup from "@/components/FormElements/InputGroup";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
import Link from "next/link";
export function SignInForm() {
return (
<ShowcaseSection title="Sign In Form" className="!p-6.5">
<form action="#">
<InputGroup
label="Email"
type="email"
placeholder="Enter your email address"
className="mb-4.5"
/>
<InputGroup
label="Password"
type="password"
placeholder="Enter your password"
/>
<div className="mb-5.5 mt-5 flex items-center justify-between">
<Checkbox label="Remember me" minimal withBg withIcon="check" />
<Link href="#" className="text-body-sm text-primary hover:underline">
Forgot password?
</Link>
</div>
<button className="flex w-full justify-center rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90">
Sign In
</button>
</form>
</ShowcaseSection>
);
}
@@ -0,0 +1,42 @@
import InputGroup from "@/components/FormElements/InputGroup";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
export function SignUpForm() {
return (
<ShowcaseSection title="Sign Up Form" className="!p-6.5">
<form action="#">
<InputGroup
label="Name"
type="text"
placeholder="Enter full name"
className="mb-4.5"
/>
<InputGroup
label="Email"
type="email"
placeholder="Enter email address"
className="mb-4.5"
/>
<InputGroup
label="Password"
type="password"
placeholder="Enter password"
className="mb-4.5"
/>
<InputGroup
label="Re-type Password"
type="password"
placeholder="Re-type password"
className="mb-5.5"
/>
<button className="flex w-full justify-center rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90">
Sign Up
</button>
</form>
</ShowcaseSection>
);
}
+26
View File
@@ -0,0 +1,26 @@
import type { Metadata } from "next";
import { ContactForm } from "./_components/contact-form";
import { SignInForm } from "./_components/sign-in-form";
import { SignUpForm } from "./_components/sign-up-form";
export const metadata: Metadata = {
title: "Form Layout",
};
export default function Page() {
return (
<>
<div className="grid grid-cols-1 gap-9 sm:grid-cols-2">
<div className="flex flex-col gap-9">
<ContactForm />
</div>
<div className="flex flex-col gap-9">
<SignInForm />
<SignUpForm />
</div>
</div>
</>
);
}
+36
View File
@@ -0,0 +1,36 @@
import "@/css/satoshi.css";
import "@/css/style.css";
import { ConditionalLayout } from "@/components/Layouts/conditional-layout";
import "flatpickr/dist/flatpickr.min.css";
import "jsvectormap/dist/jsvectormap.css";
import type { Metadata } from "next";
import NextTopLoader from "nextjs-toploader";
import type { PropsWithChildren } from "react";
import { Providers } from "./providers";
export const metadata: Metadata = {
title: {
template: "%s | NextAdmin - Next.js Dashboard Kit",
default: "NextAdmin - Next.js Dashboard Kit",
},
description:
"Next.js admin dashboard toolkit with 200+ templates, UI components, and integrations for fast dashboard development.",
icons: {
icon: "/images/main-logo.svg",
},
};
export default function RootLayout({ children }: PropsWithChildren) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>
<NextTopLoader color="#5750F1" showSpinner={false} />
<ConditionalLayout>{children}</ConditionalLayout>
</Providers>
</body>
</html>
);
}
+14
View File
@@ -0,0 +1,14 @@
import { cn } from "../lib/utils";
interface IProps {
className?: string | null;
}
const Loading = ({ className = "w-svw h-svh" }: IProps) => {
return (
<div className={cn("flex items-center justify-center", className)}>
<span className="loading loading-dots loading-xl"></span>
</div>
);
};
export default Loading;
@@ -0,0 +1,91 @@
import {
CallIcon,
EmailIcon,
PencilSquareIcon,
UserIcon,
} from "@/assets/icons";
import InputGroup from "@/components/FormElements/InputGroup";
import { TextAreaGroup } from "@/components/FormElements/InputGroup/text-area";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
export function PersonalInfoForm() {
return (
<ShowcaseSection title="Personal Information" className="!p-7">
<form>
<div className="mb-5.5 flex flex-col gap-5.5 sm:flex-row">
<InputGroup
className="w-full sm:w-1/2"
type="text"
name="fullName"
label="Full Name"
placeholder="David Jhon"
defaultValue="David Jhon"
icon={<UserIcon />}
iconPosition="left"
height="sm"
/>
<InputGroup
className="w-full sm:w-1/2"
type="text"
name="phoneNumber"
label="Phone Number"
placeholder="+990 3343 7865"
defaultValue={"+990 3343 7865"}
icon={<CallIcon />}
iconPosition="left"
height="sm"
/>
</div>
<InputGroup
className="mb-5.5"
type="email"
name="email"
label="Email Address"
placeholder="devidjond45@gmail.com"
defaultValue="devidjond45@gmail.com"
icon={<EmailIcon />}
iconPosition="left"
height="sm"
/>
<InputGroup
className="mb-5.5"
type="text"
name="username"
label="Username"
placeholder="devidjhon24"
defaultValue="devidjhon24"
icon={<UserIcon />}
iconPosition="left"
height="sm"
/>
<TextAreaGroup
className="mb-5.5"
label="BIO"
placeholder="Write your bio here"
icon={<PencilSquareIcon />}
defaultValue="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam lacinia turpis tortor, consequat efficitur mi congue a. Curabitur cursus, ipsum ut lobortis sodales, enim arcu pellentesque lectus ac suscipit diam sem a felis. Cras sapien ex, blandit eu dui et suscipit gravida nunc. Sed sed est quis dui."
/>
<div className="flex justify-end gap-3">
<button
className="rounded-lg border border-stroke px-6 py-[7px] font-medium text-dark hover:shadow-1 dark:border-dark-3 dark:text-white"
type="button"
>
Cancel
</button>
<button
className="rounded-lg bg-primary px-6 py-[7px] font-medium text-gray-2 hover:bg-opacity-90"
type="submit"
>
Save
</button>
</div>
</form>
</ShowcaseSection>
);
}
@@ -0,0 +1,79 @@
import { UploadIcon } from "@/assets/icons";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
import Image from "next/image";
export function UploadPhotoForm() {
return (
<ShowcaseSection title="Your Photo" className="!p-7">
<form>
<div className="mb-4 flex items-center gap-3">
<Image
src="/images/user/user-03.png"
width={55}
height={55}
alt="User"
className="size-14 rounded-full object-cover"
quality={90}
/>
<div>
<span className="mb-1.5 font-medium text-dark dark:text-white">
Edit your photo
</span>
<span className="flex gap-3">
<button type="button" className="text-body-sm hover:text-red">
Delete
</button>
<button className="text-body-sm hover:text-primary">
Update
</button>
</span>
</div>
</div>
<div className="relative mb-5.5 block w-full rounded-xl border border-dashed border-gray-4 bg-gray-2 hover:border-primary dark:border-dark-3 dark:bg-dark-2 dark:hover:border-primary">
<input
type="file"
name="profilePhoto"
id="profilePhoto"
accept="image/png, image/jpg, image/jpeg"
hidden
/>
<label
htmlFor="profilePhoto"
className="flex cursor-pointer flex-col items-center justify-center p-4 sm:py-7.5"
>
<div className="flex size-13.5 items-center justify-center rounded-full border border-stroke bg-white dark:border-dark-3 dark:bg-gray-dark">
<UploadIcon />
</div>
<p className="mt-2.5 text-body-sm font-medium">
<span className="text-primary">Click to upload</span> or drag and
drop
</p>
<p className="mt-1 text-body-xs">
SVG, PNG, JPG or GIF (max, 800 X 800px)
</p>
</label>
</div>
<div className="flex justify-end gap-3">
<button
className="flex justify-center rounded-lg border border-stroke px-6 py-[7px] font-medium text-dark hover:shadow-1 dark:border-dark-3 dark:text-white"
type="button"
>
Cancel
</button>
<button
className="flex items-center justify-center rounded-lg bg-primary px-6 py-[7px] font-medium text-gray-2 hover:bg-opacity-90"
type="submit"
>
Save
</button>
</div>
</form>
</ShowcaseSection>
);
}
+22
View File
@@ -0,0 +1,22 @@
import type { Metadata } from "next";
import { PersonalInfoForm } from "./_components/personal-info";
import { UploadPhotoForm } from "./_components/upload-photo";
export const metadata: Metadata = {
title: "Settings Page",
};
export default function SettingsPage() {
return (
<div className="mx-auto w-full max-w-[1080px]">
<div className="grid grid-cols-5 gap-8">
<div className="col-span-5 xl:col-span-3">
<PersonalInfoForm />
</div>
<div className="col-span-5 xl:col-span-2">
<UploadPhotoForm />
</div>
</div>
</div>
);
}
+134
View File
@@ -0,0 +1,134 @@
import React from "react";
export type PropsType = React.SVGProps<SVGSVGElement>;
export function CameraIcon(props: PropsType) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.69882 3.365C5.89894 2.38259 6.77316 1.6875 7.77475 1.6875H10.2252C11.2268 1.6875 12.1011 2.38259 12.3012 3.36499C12.3474 3.59178 12.5528 3.75814 12.7665 3.75814H12.7788L12.7911 3.75868C13.8437 3.80471 14.6521 3.93387 15.3271 4.37668C15.7524 4.65568 16.1182 5.01463 16.4033 5.43348C16.7579 5.9546 16.9143 6.55271 16.9893 7.27609C17.0625 7.98284 17.0625 8.86875 17.0625 9.99079V10.0547C17.0625 11.1767 17.0625 12.0626 16.9893 12.7694C16.9143 13.4927 16.7579 14.0909 16.4033 14.612C16.1182 15.0308 15.7524 15.3898 15.3271 15.6688C14.7995 16.0149 14.1947 16.1675 13.461 16.2408C12.7428 16.3125 11.8418 16.3125 10.6976 16.3125H7.30242C6.15824 16.3125 5.25725 16.3125 4.53897 16.2408C3.80534 16.1675 3.20049 16.0149 2.67289 15.6688C2.24761 15.3898 1.88179 15.0308 1.59674 14.612C1.24209 14.0909 1.08567 13.4927 1.01072 12.7694C0.937488 12.0626 0.937494 11.1767 0.9375 10.0547V9.9908C0.937494 8.86875 0.937488 7.98284 1.01072 7.27609C1.08567 6.55271 1.24209 5.9546 1.59674 5.43348C1.88179 5.01463 2.24761 4.65568 2.67289 4.37668C3.34787 3.93387 4.15635 3.80471 5.20892 3.75868L5.2212 3.75814H5.2335C5.44716 3.75814 5.65262 3.59179 5.69882 3.365ZM7.77475 2.8125C7.29392 2.8125 6.89179 3.14475 6.80118 3.58955C6.65443 4.30994 6.01575 4.8764 5.24725 4.88308C4.23579 4.92802 3.69402 5.05227 3.28998 5.31733C2.98732 5.51589 2.72814 5.77058 2.52679 6.06643C2.31968 6.37076 2.19522 6.75994 2.12973 7.39203C2.06321 8.03405 2.0625 8.8617 2.0625 10.0227C2.0625 11.1838 2.06321 12.0114 2.12973 12.6534C2.19522 13.2855 2.31968 13.6747 2.5268 13.979C2.72814 14.2749 2.98732 14.5296 3.28998 14.7281C3.60313 14.9336 4.00383 15.0567 4.65078 15.1213C5.30662 15.1868 6.15145 15.1875 7.33333 15.1875H10.6667C11.8486 15.1875 12.6934 15.1868 13.3492 15.1213C13.9962 15.0567 14.3969 14.9336 14.71 14.7281C15.0127 14.5296 15.2719 14.2749 15.4732 13.979C15.6803 13.6747 15.8048 13.2855 15.8703 12.6534C15.9368 12.0114 15.9375 11.1838 15.9375 10.0227C15.9375 8.8617 15.9368 8.03405 15.8703 7.39203C15.8048 6.75994 15.6803 6.37076 15.4732 6.06643C15.2719 5.77058 15.0127 5.51589 14.71 5.31733C14.306 5.05227 13.7642 4.92802 12.7528 4.88308C11.9843 4.8764 11.3456 4.30994 11.1988 3.58955C11.1082 3.14475 10.7061 2.8125 10.2252 2.8125H7.77475ZM9 8.0625C8.06802 8.0625 7.3125 8.81802 7.3125 9.75C7.3125 10.682 8.06802 11.4375 9 11.4375C9.93198 11.4375 10.6875 10.682 10.6875 9.75C10.6875 8.81802 9.93198 8.0625 9 8.0625ZM6.1875 9.75C6.1875 8.1967 7.4467 6.9375 9 6.9375C10.5533 6.9375 11.8125 8.1967 11.8125 9.75C11.8125 11.3033 10.5533 12.5625 9 12.5625C7.4467 12.5625 6.1875 11.3033 6.1875 9.75ZM12.9375 7.5C12.9375 7.18934 13.1893 6.9375 13.5 6.9375H14.25C14.5607 6.9375 14.8125 7.18934 14.8125 7.5C14.8125 7.81066 14.5607 8.0625 14.25 8.0625H13.5C13.1893 8.0625 12.9375 7.81066 12.9375 7.5Z"
/>
</svg>
);
}
export function FacebookIcon(props: PropsType) {
return (
<svg
width="22"
height="22"
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_1676_1804)">
<path d="M12.8337 12.3752H15.1253L16.042 8.7085H12.8337V6.87516C12.8337 5.931 12.8337 5.04183 14.667 5.04183H16.042V1.96183C15.7432 1.92241 14.6147 1.8335 13.4231 1.8335C10.9343 1.8335 9.16699 3.35241 9.16699 6.14183V8.7085H6.41699V12.3752H9.16699V20.1668H12.8337V12.3752Z" />
</g>
<defs>
<clipPath id="clip0_1676_1804">
<rect width="22" height="22" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function XIcon(props: PropsType) {
return (
<svg
className="fill-current"
width="22"
height="22"
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M13.6894 18.5L9.90566 13.1069L5.16898 18.5H3.16504L9.01663 11.8394L3.16504 3.5H8.31001L11.8761 8.58297L16.3443 3.5H18.3482L12.7681 9.85216L18.8343 18.5H13.6894ZM15.921 16.9795H14.5719L6.03435 5.02047H7.38366L10.803 9.809L11.3943 10.6399L15.921 16.9795Z"
/>
</svg>
);
}
export function LinkedInIcon(props: PropsType) {
return (
<svg
width="23"
height="22"
viewBox="0 0 23 22"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_1676_1812)">
<path d="M6.69596 4.58327C6.69572 5.0695 6.50233 5.53572 6.15834 5.87937C5.81436 6.22301 5.34794 6.41593 4.86171 6.41569C4.37548 6.41545 3.90926 6.22206 3.56562 5.87807C3.22197 5.53408 3.02905 5.06767 3.0293 4.58144C3.02954 4.09521 3.22293 3.62899 3.56692 3.28535C3.9109 2.9417 4.37732 2.74878 4.86355 2.74902C5.34978 2.74927 5.816 2.94265 6.15964 3.28664C6.50329 3.63063 6.69621 4.09704 6.69596 4.58327ZM6.75096 7.77327H3.0843V19.2499H6.75096V7.77327ZM12.5443 7.77327H8.89596V19.2499H12.5076V13.2274C12.5076 9.87244 16.8801 9.56077 16.8801 13.2274V19.2499H20.501V11.9808C20.501 6.32494 14.0293 6.53577 12.5076 9.31327L12.5443 7.77327Z" />
</g>
<defs>
<clipPath id="clip0_1676_1812">
<rect
width="22"
height="22"
fill="white"
transform="translate(0.333984)"
/>
</clipPath>
</defs>
</svg>
);
}
export function DribbleIcon(props: PropsType) {
return (
<svg
width="22"
height="22"
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_1676_1816)">
<path d="M18.3229 10.6078C18.2478 9.16492 17.7459 7.7768 16.881 6.61941C16.6175 6.90324 16.3358 7.16964 16.0377 7.41691C15.1219 8.17761 14.0985 8.79851 13.0008 9.25942C13.1538 9.58025 13.2941 9.891 13.4178 10.1843V10.1871C13.4528 10.269 13.4864 10.3516 13.5187 10.4346C14.9065 10.2787 16.3695 10.3356 17.7876 10.5272C17.9764 10.5528 18.1543 10.5803 18.3229 10.6078ZM9.72001 3.77866C10.6133 5.03741 11.4371 6.34408 12.1877 7.69283C13.3088 7.251 14.2355 6.69366 14.9817 6.07308C15.2407 5.85962 15.4845 5.62836 15.7113 5.381C14.3922 4.27157 12.7233 3.66438 10.9997 3.66683C10.5707 3.66654 10.1425 3.70365 9.72001 3.77775V3.77866ZM3.89826 9.16408C4.52272 9.14832 5.14643 9.11072 5.76826 9.05133C7.27126 8.9169 8.76143 8.66496 10.2251 8.29783C9.46015 6.96886 8.63427 5.6759 7.75009 4.42308C6.80567 4.89094 5.97291 5.55646 5.30832 6.37447C4.64372 7.19248 4.16283 8.14387 3.89826 9.16408ZM5.30076 15.6156C5.65643 15.0958 6.12393 14.511 6.74451 13.8748C8.07734 12.509 9.65034 11.4457 11.4708 10.859L11.5277 10.8425C11.3764 10.5088 11.2343 10.2109 11.0913 9.93042C9.40834 10.4208 7.63551 10.727 5.86909 10.8856C5.00743 10.9635 4.23468 10.9974 3.66634 11.0029C3.66472 12.6828 4.24228 14.3119 5.30168 15.6156H5.30076ZM13.7543 17.7973C13.4008 16.0146 12.9004 14.2642 12.2583 12.564C10.4231 13.2304 8.96101 14.2048 7.83076 15.3672C7.37463 15.8277 6.96984 16.3364 6.62351 16.8843C7.88742 17.8273 9.42271 18.3358 10.9997 18.3335C11.9438 18.3349 12.8792 18.1534 13.7543 17.7991V17.7973ZM15.4712 16.8118C16.9023 15.7116 17.8773 14.1221 18.2093 12.3477C17.8976 12.2697 17.5025 12.1918 17.068 12.1313C16.102 11.9922 15.1217 11.982 14.153 12.1011C14.6985 13.64 15.1389 15.2142 15.4712 16.8128V16.8118ZM10.9997 20.1668C5.93693 20.1668 1.83301 16.0629 1.83301 11.0002C1.83301 5.93741 5.93693 1.8335 10.9997 1.8335C16.0624 1.8335 20.1663 5.93741 20.1663 11.0002C20.1663 16.0629 16.0624 20.1668 10.9997 20.1668Z" />
</g>
<defs>
<clipPath id="clip0_1676_1816">
<rect width="22" height="22" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function GitHubIcon(props: PropsType) {
return (
<svg
width="23"
height="22"
viewBox="0 0 23 22"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_1676_1820)">
<path d="M11.6657 1.8335C6.60111 1.8335 2.49902 5.93558 2.49902 11.0002C2.49799 12.9245 3.10294 14.8003 4.22806 16.3614C5.35318 17.9226 6.94133 19.0898 8.76719 19.6975C9.22553 19.7772 9.39694 19.5022 9.39694 19.2612C9.39694 19.0439 9.38503 18.3225 9.38503 17.5543C7.08236 17.9787 6.48653 16.9933 6.30319 16.4772C6.19961 16.2132 5.75319 15.4002 5.36361 15.182C5.04278 15.0106 4.58444 14.5862 5.35169 14.5752C6.07403 14.5632 6.58919 15.2397 6.76153 15.5147C7.58653 16.9007 8.90469 16.5112 9.43086 16.271C9.51153 15.6752 9.75169 15.2746 10.0157 15.0454C7.97611 14.8162 5.84486 14.0252 5.84486 10.5189C5.84486 9.52158 6.19961 8.6975 6.78444 8.05491C6.69278 7.82575 6.37194 6.88616 6.87611 5.62575C6.87611 5.62575 7.64336 5.38558 9.39694 6.56625C10.1432 6.35914 10.9142 6.25489 11.6886 6.25641C12.4678 6.25641 13.2469 6.35908 13.9803 6.56533C15.7329 5.37366 16.5011 5.62666 16.5011 5.62666C17.0053 6.88708 16.6844 7.82666 16.5928 8.05583C17.1767 8.6975 17.5324 9.51058 17.5324 10.5189C17.5324 14.0371 15.3901 14.8162 13.3505 15.0454C13.6824 15.3314 13.9693 15.8814 13.9693 16.7412C13.9693 17.9668 13.9574 18.9522 13.9574 19.2621C13.9574 19.5022 14.1297 19.7882 14.588 19.6966C16.4076 19.0822 17.9888 17.9127 19.1089 16.3527C20.2291 14.7927 20.8318 12.9207 20.8324 11.0002C20.8324 5.93558 16.7303 1.8335 11.6657 1.8335Z" />
</g>
<defs>
<clipPath id="clip0_1676_1820">
<rect
width="22"
height="22"
fill="white"
transform="translate(0.666016)"
/>
</clipPath>
</defs>
</svg>
);
}
@@ -0,0 +1,59 @@
import Link from "next/link";
import {
DribbleIcon,
FacebookIcon,
GitHubIcon,
LinkedInIcon,
XIcon,
} from "./icons";
const ACCOUNTS = [
{
platform: "Facebook",
url: "#",
Icon: FacebookIcon,
},
{
platform: "X",
url: "#",
Icon: XIcon,
},
{
platform: "LinkedIn",
url: "#",
Icon: LinkedInIcon,
},
{
platform: "Dribble",
url: "#",
Icon: DribbleIcon,
},
{
platform: "GitHub",
url: "#",
Icon: GitHubIcon,
},
];
export function SocialAccounts() {
return (
<div className="mt-4.5">
<h4 className="mb-3.5 font-medium text-dark dark:text-white">
Follow me on
</h4>
<div className="flex items-center justify-center gap-3.5">
{ACCOUNTS.map(({ Icon, ...item }) => (
<Link
key={item.platform}
href={item.url}
className="hover:text-primary"
>
<span className="sr-only">View {item.platform} Account</span>
<Icon />
</Link>
))}
</div>
</div>
);
}
+11
View File
@@ -0,0 +1,11 @@
import type { PropsWithChildren } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Profile Page",
};
export default function Layout({ children }: PropsWithChildren) {
return children;
}
+151
View File
@@ -0,0 +1,151 @@
"use client";
import Image from "next/image";
import { useState } from "react";
import { CameraIcon } from "./_components/icons";
import { SocialAccounts } from "./_components/social-accounts";
export default function Page() {
const [data, setData] = useState({
name: "Danish Heilium",
profilePhoto: "/images/user/user-03.png",
coverPhoto: "/images/cover/cover-01.png",
});
const handleChange = (e: any) => {
if (e.target.name === "profilePhoto") {
const file = e.target?.files[0];
setData({
...data,
profilePhoto: file && URL.createObjectURL(file),
});
} else if (e.target.name === "coverPhoto") {
const file = e.target?.files[0];
setData({
...data,
coverPhoto: file && URL.createObjectURL(file),
});
} else {
setData({
...data,
[e.target.name]: e.target.value,
});
}
};
return (
<div className="mx-auto w-full max-w-[970px]">
<div className="overflow-hidden rounded-[10px] bg-white shadow-1 dark:bg-gray-dark dark:shadow-card">
<div className="relative z-20 h-35 md:h-65">
<Image
src={data?.coverPhoto}
alt="profile cover"
className="h-full w-full rounded-tl-[10px] rounded-tr-[10px] object-cover object-center"
width={970}
height={260}
style={{
width: "auto",
height: "auto",
}}
/>
<div className="absolute bottom-1 right-1 z-10 xsm:bottom-4 xsm:right-4">
<label
htmlFor="cover"
className="flex cursor-pointer items-center justify-center gap-2 rounded-lg bg-primary px-[15px] py-[5px] text-body-sm font-medium text-white hover:bg-opacity-90"
>
<input
type="file"
name="coverPhoto"
id="coverPhoto"
className="sr-only"
onChange={handleChange}
accept="image/png, image/jpg, image/jpeg"
/>
<CameraIcon />
<span>Edit</span>
</label>
</div>
</div>
<div className="px-4 pb-6 text-center lg:pb-8 xl:pb-11.5">
<div className="relative z-30 mx-auto -mt-22 h-30 w-full max-w-30 rounded-full bg-white/20 p-1 backdrop-blur sm:h-44 sm:max-w-[176px] sm:p-3">
<div className="relative drop-shadow-2">
{data?.profilePhoto && (
<>
<Image
src={data?.profilePhoto}
width={160}
height={160}
className="overflow-hidden rounded-full"
alt="profile"
/>
<label
htmlFor="profilePhoto"
className="absolute bottom-0 right-0 flex size-8.5 cursor-pointer items-center justify-center rounded-full bg-primary text-white hover:bg-opacity-90 sm:bottom-2 sm:right-2"
>
<CameraIcon />
<input
type="file"
name="profilePhoto"
id="profilePhoto"
className="sr-only"
onChange={handleChange}
accept="image/png, image/jpg, image/jpeg"
/>
</label>
</>
)}
</div>
</div>
<div className="mt-4">
<h3 className="mb-1 text-heading-6 font-bold text-dark dark:text-white">
{data?.name}
</h3>
<p className="font-medium">Ui/Ux Designer</p>
<div className="mx-auto mb-5.5 mt-5 grid max-w-[370px] grid-cols-3 rounded-[5px] border border-stroke py-[9px] shadow-1 dark:border-dark-3 dark:bg-dark-2 dark:shadow-card">
<div className="flex flex-col items-center justify-center gap-1 border-r border-stroke px-4 dark:border-dark-3 xsm:flex-row">
<span className="font-medium text-dark dark:text-white">
259
</span>
<span className="text-body-sm">Posts</span>
</div>
<div className="flex flex-col items-center justify-center gap-1 border-r border-stroke px-4 dark:border-dark-3 xsm:flex-row">
<span className="font-medium text-dark dark:text-white">
129K
</span>
<span className="text-body-sm">Followers</span>
</div>
<div className="flex flex-col items-center justify-center gap-1 px-4 xsm:flex-row">
<span className="font-medium text-dark dark:text-white">
2K
</span>
<span className="text-body-sm-sm">Following</span>
</div>
</div>
<div className="mx-auto max-w-[720px]">
<h4 className="font-medium text-dark dark:text-white">
About Me
</h4>
<p className="mt-4">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Pellentesque posuere fermentum urna, eu condimentum mauris
tempus ut. Donec fermentum blandit aliquet. Etiam dictum dapibus
ultricies. Sed vel aliquet libero. Nunc a augue fermentum,
pharetra ligula sed, aliquam lacus.
</p>
</div>
<SocialAccounts />
</div>
</div>
</div>
</div>
);
}
+40
View File
@@ -0,0 +1,40 @@
"use client";
import { SidebarProvider } from "@/components/Layouts/sidebar/sidebar-context";
import { UserProvider } from "@/contexts";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ThemeProvider } from "next-themes";
import { ToastContainer, Zoom } from "react-toastify";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider defaultTheme="light" attribute="class">
<UserProvider>
<SidebarProvider>
<QueryClientProvider client={queryClient}>
<ToastContainer
position="top-right"
autoClose={2500}
theme={"colored"}
transition={Zoom}
hideProgressBar
newestOnTop
closeOnClick
pauseOnFocusLoss
draggable
pauseOnHover
/>
{children}
</QueryClientProvider>
</SidebarProvider>
</UserProvider>
</ThemeProvider>
);
}
+32
View File
@@ -0,0 +1,32 @@
import { InvoiceTable } from "@/components/Tables/invoice-table";
import { TopChannels } from "@/components/Tables/top-channels";
import { TopChannelsSkeleton } from "@/components/Tables/top-channels/skeleton";
import { TopProducts } from "@/components/Tables/top-products";
import { TopProductsSkeleton } from "@/components/Tables/top-products/skeleton";
import { Metadata } from "next";
import { Suspense } from "react";
export const metadata: Metadata = {
title: "Tables",
};
const TablesPage = () => {
return (
<>
<div className="space-y-10">
<Suspense fallback={<TopChannelsSkeleton />}>
<TopChannels />
</Suspense>
<Suspense fallback={<TopProductsSkeleton />}>
<TopProducts />
</Suspense>
<InvoiceTable />
</div>
</>
);
};
export default TablesPage;
+17
View File
@@ -0,0 +1,17 @@
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import TendersTable from "@/components/Tables/tenders";
const TendersPage = () => {
const breadcrumbItems = [
{ name: "Dashboard", href: "/" },
{ name: "Tenders", href: "/tenders" },
];
return (
<>
<Breadcrumb items={breadcrumbItems} />
<TendersTable />
</>
);
};
export default TendersPage;
+36
View File
@@ -0,0 +1,36 @@
import { Alert } from "@/components/ui-elements/alert";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Alerts",
// other metadata
};
export default function Page() {
return (
<>
{/* <Breadcrumb pageName="Alerts" /> */}
<div className="space-y-7.5 rounded-[10px] bg-white p-4 shadow-1 dark:bg-gray-dark dark:shadow-card md:p-6 xl:p-9">
<Alert
variant="warning"
title="Attention Needed"
description="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when"
/>
<Alert
variant="success"
title="Message Sent Successfully"
description="Lorem Ipsum is simply dummy text of the printing and typesetting industry."
/>
<Alert
variant="error"
title="There were 1 errors with your submission"
description="Lorem Ipsum is simply dummy text of the printing"
/>
</div>
</>
);
}
+133
View File
@@ -0,0 +1,133 @@
import { MessageOutlineIcon } from "@/assets/icons";
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
import { Button } from "@/components/ui-elements/button";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Buttons",
};
export default function Page() {
return (
<>
{/* <Breadcrumb pageName="Buttons" /> */}
<div className="space-y-10">
<ShowcaseSection title="Normal Button">
<div className="mb-7.5 flex flex-wrap gap-5 xl:gap-20">
<Button label="Button" variant="primary" />
<Button label="Button" variant="primary" shape="rounded" />
<Button label="Button" variant="primary" shape="full" />
<Button label="Button" variant="outlinePrimary" shape="rounded" />
</div>
<div className="mb-7.5 flex flex-wrap gap-5 xl:gap-20">
<Button label="Button" variant="green" />
<Button label="Button" variant="green" shape="rounded" />
<Button label="Button" variant="green" shape="full" />
<Button label="Button" variant="outlineGreen" shape="rounded" />
</div>
<div className="flex flex-wrap gap-5 xl:gap-20">
<Button label="Button" variant="dark" />
<Button label="Button" variant="dark" shape="rounded" />
<Button label="Button" variant="dark" shape="full" />
<Button label="Button" variant="outlineDark" shape="rounded" />
</div>
</ShowcaseSection>
<ShowcaseSection title="Button With Icon">
<div className="mb-7.5 flex flex-wrap gap-5 xl:gap-7.5">
<Button
label="Button With Icon"
variant="primary"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="green"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="dark"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="outlinePrimary"
size="small"
icon={<MessageOutlineIcon />}
/>
</div>
<div className="mb-7.5 flex flex-wrap gap-5 xl:gap-7.5">
<Button
label="Button With Icon"
variant="primary"
shape="rounded"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="green"
shape="rounded"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="dark"
shape="rounded"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="outlinePrimary"
shape="rounded"
size="small"
icon={<MessageOutlineIcon />}
/>
</div>
<div className="flex flex-wrap gap-5 xl:gap-7.5">
<Button
label="Button With Icon"
variant="primary"
shape="full"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="green"
shape="full"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="dark"
shape="full"
size="small"
icon={<MessageOutlineIcon />}
/>
<Button
label="Button With Icon"
variant="outlinePrimary"
shape="full"
size="small"
icon={<MessageOutlineIcon />}
/>
</div>
</ShowcaseSection>
</div>
</>
);
}
+444
View File
@@ -0,0 +1,444 @@
import type { IconProps } from "@/types/icon-props";
export function SearchIcon(props: IconProps) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_1699_11536)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.625 2.0625C5.00063 2.0625 2.0625 5.00063 2.0625 8.625C2.0625 12.2494 5.00063 15.1875 8.625 15.1875C12.2494 15.1875 15.1875 12.2494 15.1875 8.625C15.1875 5.00063 12.2494 2.0625 8.625 2.0625ZM0.9375 8.625C0.9375 4.37931 4.37931 0.9375 8.625 0.9375C12.8707 0.9375 16.3125 4.37931 16.3125 8.625C16.3125 10.5454 15.6083 12.3013 14.4441 13.6487L16.8977 16.1023C17.1174 16.3219 17.1174 16.6781 16.8977 16.8977C16.6781 17.1174 16.3219 17.1174 16.1023 16.8977L13.6487 14.4441C12.3013 15.6083 10.5454 16.3125 8.625 16.3125C4.37931 16.3125 0.9375 12.8707 0.9375 8.625Z"
/>
</g>
<defs>
<clipPath id="clip0_1699_11536">
<rect width="18" height="18" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function CurrencyIcon(props: IconProps) {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path d="M9.18 2.5v1.79q-1.1.25-1.9.96t-1.07 1.68l1.54.62q.32-1 .93-1.52t1.62-.52q.85 0 1.44.38t.59 1.06q0 .73-.46 1.16t-2.22 1.14q-1.79.56-2.46 1.35T6.1 12.2q0 1.35.88 2.1t1.79.86v1.75h1.67v-1.75q1.04-.17 1.72-.76T12.9 13l-1.54-.67q-.25.67-.71 1t-1.25.33q-.92 0-1.39-.41T7.58 12.2q0-.69.62-1.08t2.17-.83q1.44-.42 2.18-1.32T13.29 7.5q0-1.48-.88-2.25t-2.17-.96V2.5H9.18z" />
</svg>
);
}
export function MoneyIcon(props: IconProps) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height="20px"
viewBox="0 -960 960 960"
width="20px"
{...props}
>
<path d="M220-60 80-200l140-140 57 56-44 44h494l-43-44 56-56 140 140L740-60l-57-56 44-44H233l43 44-56 56Zm260-460q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35ZM200-400q-33 0-56.5-23.5T120-480v-320q0-33 23.5-56.5T200-880h560q33 0 56.5 23.5T840-800v320q0 33-23.5 56.5T760-400H200Zm80-80h400q0-33 23.5-56.5T760-560v-160q-33 0-56.5-23.5T680-800H280q0 33-23.5 56.5T200-720v160q33 0 56.5 23.5T280-480Zm-80 0v-320 320Z" />
</svg>
);
}
export function CloseIcon(props: IconProps) {
return (
<svg
width={25}
height={24}
viewBox="0 0 25 24"
fill="currentColor"
{...props}
>
<path d="M12.998 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95 1.414-1.414 4.95 4.95z" />
</svg>
);
}
export function ArrowLeftIcon(props: IconProps) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<path
d="M15.7492 8.38125H3.73984L8.52109 3.51562C8.77422 3.2625 8.77422 2.86875 8.52109 2.61562C8.26797 2.3625 7.87422 2.3625 7.62109 2.61562L1.79922 8.52187C1.54609 8.775 1.54609 9.16875 1.79922 9.42188L7.62109 15.3281C7.73359 15.4406 7.90234 15.525 8.07109 15.525C8.23984 15.525 8.38047 15.4687 8.52109 15.3562C8.77422 15.1031 8.77422 14.7094 8.52109 14.4563L3.76797 9.64687H15.7492C16.0867 9.64687 16.368 9.36562 16.368 9.02812C16.368 8.6625 16.0867 8.38125 15.7492 8.38125Z"
fill=""
/>
</svg>
);
}
export function ChevronUpIcon(props: IconProps) {
return (
<svg
width={22}
height={22}
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.551 7.728a.687.687 0 01.895 0l6.417 5.5a.687.687 0 11-.895 1.044l-5.97-5.117-5.969 5.117a.687.687 0 01-.894-1.044l6.416-5.5z"
/>
</svg>
);
}
export function ArrowUpIcon(props: IconProps) {
return (
<svg
width={10}
height={10}
viewBox="0 0 10 10"
fill="currentColor"
{...props}
>
<path d="M4.357 2.393L.91 5.745 0 4.861 5 0l5 4.861-.909.884-3.448-3.353V10H4.357V2.393z" />
</svg>
);
}
export function ArrowDownIcon(props: IconProps) {
return (
<svg
width={10}
height={10}
viewBox="0 0 10 10"
fill="currentColor"
{...props}
>
<path d="M5.643 7.607L9.09 4.255l.909.884L5 10 0 5.139l.909-.884 3.448 3.353V0h1.286v7.607z" />
</svg>
);
}
export function DotIcon(props: IconProps) {
return (
<svg width={2} height={3} viewBox="0 0 2 3" fill="currentColor" {...props}>
<circle cx={1} cy={1.5} r={1} fill="#637381" />
</svg>
);
}
export function TrendingUpIcon(props: IconProps) {
return (
<svg
width="14"
height="15"
viewBox="0 0 14 15"
fill="currentColor"
{...props}
>
<path
d="M13.0158 5.24707H9.4939C9.2314 5.24707 9.01265 5.46582 9.01265 5.72832C9.01265 5.99082 9.2314 6.20957 9.4939 6.20957H11.6595L8.85953 8.09082C8.75015 8.17832 8.59703 8.17832 8.46578 8.09082L5.57828 6.1877C5.1189 5.88145 4.55015 5.88145 4.09078 6.1877L0.722027 8.44082C0.503277 8.59395 0.437652 8.9002 0.590777 9.11895C0.678277 9.2502 0.831402 9.3377 1.0064 9.3377C1.0939 9.3377 1.20328 9.31582 1.2689 9.2502L4.65953 6.99707C4.7689 6.90957 4.92203 6.90957 5.05328 6.99707L7.94078 8.92207C8.40015 9.22832 8.9689 9.22832 9.42828 8.92207L12.5127 6.84395V9.27207C12.5127 9.53457 12.7314 9.75332 12.9939 9.75332C13.2564 9.75332 13.4752 9.53457 13.4752 9.27207V5.72832C13.5189 5.46582 13.2783 5.24707 13.0158 5.24707Z"
fill=""
/>
</svg>
);
}
export function CheckIcon(props: IconProps) {
return (
<svg
width="11"
height="8"
viewBox="0 0 11 8"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.2355 0.812752L10.2452 0.824547C10.4585 1.08224 10.4617 1.48728 10.1855 1.74621L4.85633 7.09869C4.66442 7.29617 4.41535 7.4001 4.14693 7.4001C3.89823 7.4001 3.63296 7.29979 3.43735 7.09851L0.788615 4.43129C0.536589 4.1703 0.536617 3.758 0.788643 3.49701C1.04747 3.22897 1.4675 3.22816 1.72731 3.49457L4.16182 5.94608L9.28643 0.799032C9.54626 0.532887 9.96609 0.533789 10.2248 0.801737L10.2355 0.812752Z"
fill=""
/>
</svg>
);
}
export function XIcon(props: IconProps) {
return (
<svg
width="11"
height="11"
viewBox="0 0 11 11"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_803_2686)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.23529 2.29669C0.942402 2.00379 0.942402 1.52892 1.23529 1.23603C1.52819 0.943134 2.00306 0.943134 2.29596 1.23603L5.37433 4.3144L8.45261 1.23612C8.7455 0.943225 9.22038 0.943225 9.51327 1.23612C9.80616 1.52901 9.80616 2.00389 9.51327 2.29678L6.43499 5.37506L9.51327 8.45334C9.80616 8.74624 9.80616 9.22111 9.51327 9.514C9.22038 9.8069 8.7455 9.8069 8.45261 9.514L5.37433 6.43572L2.29596 9.51409C2.00306 9.80699 1.52819 9.80699 1.23529 9.51409C0.942402 9.2212 0.942402 8.74633 1.23529 8.45343L4.31367 5.37506L1.23529 2.29669Z"
/>
</g>
<defs>
<clipPath id="clip0_803_2686">
<rect width="10.75" height="10.75" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function GlobeIcon(props: IconProps) {
return (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" {...props}>
<g clipPath="url(#clip0_1680_14985)">
<path
d="M9.99935 18.3334C5.39697 18.3334 1.66602 14.6024 1.66602 10.0001C1.66602 5.39771 5.39697 1.66675 9.99935 1.66675C14.6017 1.66675 18.3327 5.39771 18.3327 10.0001C18.3327 14.6024 14.6017 18.3334 9.99935 18.3334ZM8.09103 16.3896C7.28887 14.6883 6.79712 12.8119 6.68877 10.8334H3.38426C3.71435 13.4805 5.59634 15.6457 8.09103 16.3896ZM8.35827 10.8334C8.4836 12.8657 9.06418 14.7748 9.99935 16.4601C10.9345 14.7748 11.5151 12.8657 11.6404 10.8334H8.35827ZM16.6144 10.8334H13.3099C13.2016 12.8119 12.7098 14.6883 11.9077 16.3896C14.4023 15.6457 16.2844 13.4805 16.6144 10.8334ZM3.38426 9.16675H6.68877C6.79712 7.18822 7.28887 5.31181 8.09103 3.61055C5.59634 4.35452 3.71435 6.51966 3.38426 9.16675ZM8.35827 9.16675H11.6404C11.5151 7.13443 10.9345 5.22529 9.99935 3.54007C9.06418 5.22529 8.4836 7.13443 8.35827 9.16675ZM11.9077 3.61055C12.7098 5.31181 13.2016 7.18822 13.3099 9.16675H16.6144C16.2844 6.51966 14.4023 4.35452 11.9077 3.61055Z"
fill="#6B7280"
/>
</g>
<defs>
<clipPath id="clip0_1680_14985">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function TrashIcon(props: IconProps) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.73202 1.68751H10.2681C10.4304 1.68741 10.5718 1.68732 10.7053 1.70864C11.2328 1.79287 11.6892 2.12186 11.9359 2.59563C11.9984 2.71555 12.043 2.84971 12.0942 3.00371L12.1779 3.25488C12.1921 3.2974 12.1962 3.30943 12.1996 3.31891C12.3309 3.682 12.6715 3.92745 13.0575 3.93723C13.0676 3.93748 13.08 3.93753 13.1251 3.93753H15.3751C15.6857 3.93753 15.9376 4.18937 15.9376 4.50003C15.9376 4.81069 15.6857 5.06253 15.3751 5.06253H2.625C2.31434 5.06253 2.0625 4.81069 2.0625 4.50003C2.0625 4.18937 2.31434 3.93753 2.625 3.93753H4.87506C4.9201 3.93753 4.93253 3.93749 4.94267 3.93723C5.32866 3.92745 5.66918 3.68202 5.80052 3.31893C5.80397 3.30938 5.80794 3.29761 5.82218 3.25488L5.90589 3.00372C5.95711 2.84973 6.00174 2.71555 6.06419 2.59563C6.3109 2.12186 6.76735 1.79287 7.29482 1.70864C7.42834 1.68732 7.56973 1.68741 7.73202 1.68751ZM6.75611 3.93753C6.79475 3.86176 6.82898 3.78303 6.85843 3.70161C6.86737 3.67689 6.87615 3.65057 6.88742 3.61675L6.96227 3.39219C7.03065 3.18706 7.04639 3.14522 7.06201 3.11523C7.14424 2.95731 7.29639 2.84764 7.47222 2.81957C7.50561 2.81423 7.55027 2.81253 7.76651 2.81253H10.2336C10.4499 2.81253 10.4945 2.81423 10.5279 2.81957C10.7037 2.84764 10.8559 2.95731 10.9381 3.11523C10.9537 3.14522 10.9695 3.18705 11.0379 3.39219L11.1127 3.61662L11.1417 3.70163C11.1712 3.78304 11.2054 3.86177 11.244 3.93753H6.75611Z"
fill=""
/>
<path
d="M4.43632 6.33761C4.41565 6.02764 4.14762 5.79311 3.83765 5.81377C3.52767 5.83444 3.29314 6.10247 3.31381 6.41245L3.6614 11.6262C3.72552 12.5883 3.77731 13.3654 3.89879 13.9752C4.02509 14.6092 4.23991 15.1387 4.6836 15.5538C5.1273 15.9689 5.66996 16.1481 6.31095 16.2319C6.92747 16.3126 7.70628 16.3125 8.67045 16.3125H9.32963C10.2938 16.3125 11.0727 16.3126 11.6892 16.2319C12.3302 16.1481 12.8728 15.9689 13.3165 15.5538C13.7602 15.1387 13.975 14.6092 14.1013 13.9752C14.2228 13.3654 14.2746 12.5883 14.3387 11.6263L14.6863 6.41245C14.707 6.10247 14.4725 5.83444 14.1625 5.81377C13.8525 5.79311 13.5845 6.02764 13.5638 6.33761L13.2189 11.5119C13.1515 12.5228 13.1034 13.2262 12.998 13.7554C12.8958 14.2688 12.753 14.5405 12.5479 14.7323C12.3429 14.9242 12.0623 15.0485 11.5433 15.1164C11.0082 15.1864 10.3032 15.1875 9.29007 15.1875H8.71005C7.69692 15.1875 6.99192 15.1864 6.45686 15.1164C5.93786 15.0485 5.65724 14.9242 5.45218 14.7323C5.24712 14.5405 5.10438 14.2687 5.00211 13.7554C4.89669 13.2262 4.84867 12.5228 4.78127 11.5119L4.43632 6.33761Z"
fill=""
/>
<path
d="M7.0691 7.69032C7.37822 7.65941 7.65387 7.88494 7.68478 8.19406L8.05978 11.9441C8.09069 12.2532 7.86516 12.5288 7.55604 12.5597C7.24692 12.5906 6.97127 12.3651 6.94036 12.056L6.56536 8.306C6.53445 7.99688 6.75998 7.72123 7.0691 7.69032Z"
fill=""
/>
<path
d="M10.931 7.69032C11.2402 7.72123 11.4657 7.99688 11.4348 8.306L11.0598 12.056C11.0289 12.3651 10.7532 12.5906 10.4441 12.5597C10.135 12.5288 9.90945 12.2532 9.94036 11.9441L10.3154 8.19406C10.3463 7.88494 10.6219 7.65941 10.931 7.69032Z"
fill=""
/>
</svg>
);
}
export function MessageOutlineIcon(props: IconProps) {
return (
<svg
width="22"
height="22"
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.9987 2.521C6.31578 2.521 2.51953 6.31725 2.51953 11.0002C2.51953 12.3578 2.8381 13.6391 3.40393 14.7751C3.63103 15.231 3.71848 15.7762 3.57519 16.3118L3.02922 18.3523C2.92895 18.7271 3.2718 19.0699 3.64657 18.9696L5.6871 18.4237C6.22262 18.2804 6.76783 18.3678 7.22378 18.5949C8.3598 19.1608 9.64106 19.4793 10.9987 19.4793C15.6816 19.4793 19.4779 15.6831 19.4779 11.0002C19.4779 6.31725 15.6816 2.521 10.9987 2.521ZM1.14453 11.0002C1.14453 5.55786 5.55639 1.146 10.9987 1.146C16.441 1.146 20.8529 5.55786 20.8529 11.0002C20.8529 16.4425 16.441 20.8543 10.9987 20.8543C9.42358 20.8543 7.93293 20.4843 6.61075 19.8257C6.41345 19.7274 6.21199 19.7066 6.0425 19.7519L4.00197 20.2979C2.60512 20.6717 1.3272 19.3937 1.70094 17.9969L2.24692 15.9564C2.29227 15.7869 2.27142 15.5854 2.17315 15.3881C1.5146 14.0659 1.14453 12.5753 1.14453 11.0002ZM14.2348 8.68069C14.5033 8.94918 14.5033 9.38448 14.2348 9.65296L10.5682 13.3196C10.3035 13.5843 9.87588 13.5886 9.60592 13.3294L7.77258 11.5694C7.49867 11.3065 7.48979 10.8713 7.75274 10.5974C8.0157 10.3235 8.45091 10.3146 8.72481 10.5775L10.0722 11.871L13.2626 8.68069C13.531 8.41221 13.9663 8.41221 14.2348 8.68069Z"
fill=""
/>
</svg>
);
}
export function EmailIcon(props: IconProps) {
return (
<svg
width="22"
height="22"
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.11756 2.979H12.8877C14.5723 2.97899 15.9066 2.97898 16.9509 3.11938C18.0256 3.26387 18.8955 3.56831 19.5815 4.25431C20.2675 4.94031 20.5719 5.81018 20.7164 6.8849C20.8568 7.92918 20.8568 9.26351 20.8568 10.9481V11.0515C20.8568 12.7362 20.8568 14.0705 20.7164 15.1148C20.5719 16.1895 20.2675 17.0594 19.5815 17.7454C18.8955 18.4314 18.0256 18.7358 16.9509 18.8803C15.9066 19.0207 14.5723 19.0207 12.8876 19.0207H9.11756C7.43295 19.0207 6.09861 19.0207 5.05433 18.8803C3.97961 18.7358 3.10974 18.4314 2.42374 17.7454C1.73774 17.0594 1.4333 16.1895 1.28881 15.1148C1.14841 14.0705 1.14842 12.7362 1.14844 11.0516V10.9481C1.14842 9.26351 1.14841 7.92918 1.28881 6.8849C1.4333 5.81018 1.73774 4.94031 2.42374 4.25431C3.10974 3.56831 3.97961 3.26387 5.05433 3.11938C6.09861 2.97898 7.43294 2.97899 9.11756 2.979ZM5.23755 4.48212C4.3153 4.60611 3.78396 4.83864 3.39602 5.22658C3.00807 5.61452 2.77554 6.14587 2.65155 7.06812C2.5249 8.01014 2.52344 9.25192 2.52344 10.9998C2.52344 12.7478 2.5249 13.9895 2.65155 14.9316C2.77554 15.8538 3.00807 16.3852 3.39602 16.7731C3.78396 17.161 4.3153 17.3936 5.23755 17.5176C6.17957 17.6442 7.42135 17.6457 9.16927 17.6457H12.8359C14.5839 17.6457 15.8256 17.6442 16.7677 17.5176C17.6899 17.3936 18.2213 17.161 18.6092 16.7731C18.9971 16.3852 19.2297 15.8538 19.3537 14.9316C19.4803 13.9895 19.4818 12.7478 19.4818 10.9998C19.4818 9.25192 19.4803 8.01014 19.3537 7.06812C19.2297 6.14587 18.9971 5.61452 18.6092 5.22658C18.2213 4.83864 17.6899 4.60611 16.7677 4.48212C15.8256 4.35546 14.5839 4.354 12.8359 4.354H9.16927C7.42135 4.354 6.17958 4.35546 5.23755 4.48212ZM4.97445 6.89304C5.21753 6.60135 5.65104 6.56194 5.94273 6.80502L7.92172 8.45418C8.77693 9.16685 9.37069 9.66005 9.87197 9.98246C10.3572 10.2945 10.6863 10.3993 11.0026 10.3993C11.3189 10.3993 11.648 10.2945 12.1332 9.98246C12.6345 9.66005 13.2283 9.16685 14.0835 8.45417L16.0625 6.80502C16.3542 6.56194 16.7877 6.60135 17.0308 6.89304C17.2738 7.18473 17.2344 7.61825 16.9427 7.86132L14.9293 9.5392C14.1168 10.2163 13.4582 10.7651 12.877 11.1389C12.2716 11.5283 11.6819 11.7743 11.0026 11.7743C10.3233 11.7743 9.73364 11.5283 9.12818 11.1389C8.54696 10.7651 7.88843 10.2163 7.07594 9.5392L5.06248 7.86132C4.77079 7.61825 4.73138 7.18473 4.97445 6.89304Z"
fill=""
/>
</svg>
);
}
export function PasswordIcon(props: IconProps) {
return (
<svg
width="22"
height="22"
viewBox="0 0 22 22"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.48177 14.6668C8.48177 13.2746 9.61039 12.146 11.0026 12.146C12.3948 12.146 13.5234 13.2746 13.5234 14.6668C13.5234 16.059 12.3948 17.1877 11.0026 17.1877C9.61039 17.1877 8.48177 16.059 8.48177 14.6668ZM11.0026 13.521C10.3698 13.521 9.85677 14.034 9.85677 14.6668C9.85677 15.2997 10.3698 15.8127 11.0026 15.8127C11.6354 15.8127 12.1484 15.2997 12.1484 14.6668C12.1484 14.034 11.6354 13.521 11.0026 13.521Z"
fill=""
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.19011 7.3335C6.19011 4.67563 8.34474 2.521 11.0026 2.521C13.2441 2.521 15.1293 4.05405 15.6635 6.12986C15.7582 6.49757 16.133 6.71894 16.5007 6.6243C16.8684 6.52965 17.0898 6.15484 16.9951 5.78713C16.3083 3.11857 13.8867 1.146 11.0026 1.146C7.58534 1.146 4.81511 3.91623 4.81511 7.3335V8.5277C4.60718 8.54232 4.4112 8.56135 4.22683 8.58614C3.40173 8.69707 2.70702 8.93439 2.15526 9.48615C1.6035 10.0379 1.36618 10.7326 1.25525 11.5577C1.1484 12.3524 1.14842 13.3629 1.14844 14.6165V14.7171C1.14842 15.9708 1.1484 16.9812 1.25525 17.7759C1.36618 18.601 1.6035 19.2958 2.15526 19.8475C2.70702 20.3993 3.40173 20.6366 4.22683 20.7475C5.02155 20.8544 6.03202 20.8543 7.28564 20.8543H14.7196C15.9732 20.8543 16.9837 20.8544 17.7784 20.7475C18.6035 20.6366 19.2982 20.3993 19.85 19.8475C20.4017 19.2958 20.639 18.601 20.75 17.7759C20.8568 16.9812 20.8568 15.9708 20.8568 14.7171V14.6165C20.8568 13.3629 20.8568 12.3524 20.75 11.5577C20.639 10.7326 20.4017 10.0379 19.85 9.48615C19.2982 8.93439 18.6035 8.69707 17.7784 8.58614C16.9837 8.47929 15.9732 8.47931 14.7196 8.47933H7.28564C6.89741 8.47932 6.53251 8.47932 6.19011 8.48249V7.3335ZM4.41005 9.94888C3.73742 10.0393 3.38123 10.2047 3.12753 10.4584C2.87383 10.7121 2.70842 11.0683 2.61799 11.7409C2.5249 12.4333 2.52344 13.351 2.52344 14.6668C2.52344 15.9826 2.5249 16.9003 2.61799 17.5927C2.70842 18.2653 2.87383 18.6215 3.12753 18.8752C3.38123 19.1289 3.73742 19.2943 4.41005 19.3848C5.10245 19.4779 6.02014 19.4793 7.33594 19.4793H14.6693C15.9851 19.4793 16.9028 19.4779 17.5952 19.3848C18.2678 19.2943 18.624 19.1289 18.8777 18.8752C19.1314 18.6215 19.2968 18.2653 19.3872 17.5927C19.4803 16.9003 19.4818 15.9826 19.4818 14.6668C19.4818 13.351 19.4803 12.4333 19.3872 11.7409C19.2968 11.0683 19.1314 10.7121 18.8777 10.4584C18.624 10.2047 18.2678 10.0393 17.5952 9.94888C16.9028 9.85579 15.9851 9.85433 14.6693 9.85433H7.33594C6.02014 9.85433 5.10245 9.85579 4.41005 9.94888Z"
fill=""
/>
</svg>
);
}
export function GoogleIcon(props: IconProps) {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_1715_17244)">
<path
d="M19.999 10.2216C20.0111 9.53416 19.9387 8.84776 19.7834 8.17725H10.2031V11.8883H15.8266C15.7201 12.539 15.4804 13.1618 15.1219 13.7194C14.7634 14.2769 14.2935 14.7577 13.7405 15.1327L13.7209 15.257L16.7502 17.5567L16.96 17.5772C18.8873 15.8328 19.9986 13.266 19.9986 10.2216"
fill="#4285F4"
/>
<path
d="M10.2016 19.9998C12.9566 19.9998 15.2695 19.1109 16.959 17.5775L13.739 15.133C12.8774 15.722 11.7209 16.1332 10.2016 16.1332C8.91122 16.1258 7.656 15.7203 6.61401 14.9744C5.57201 14.2285 4.79616 13.1799 4.39653 11.9775L4.27694 11.9875L1.12711 14.3764L1.08594 14.4886C1.93427 16.1455 3.23617 17.5384 4.84606 18.5117C6.45596 19.485 8.31039 20.0002 10.202 19.9998"
fill="#34A853"
/>
<path
d="M4.39899 11.9777C4.1758 11.3411 4.06063 10.673 4.05807 9.99996C4.06218 9.32799 4.1731 8.66075 4.38684 8.02225L4.38115 7.88968L1.19269 5.4624L1.0884 5.51101C0.372763 6.90343 0 8.4408 0 9.99987C0 11.5589 0.372763 13.0963 1.0884 14.4887L4.39899 11.9777Z"
fill="#FBBC05"
/>
<path
d="M10.202 3.86687C11.6641 3.84462 13.0783 4.37827 14.1476 5.35583L17.0274 2.60021C15.1804 0.902092 12.7344 -0.0296414 10.202 0.000207357C8.31041 -0.000233694 6.456 0.514977 4.8461 1.48823C3.23621 2.46148 1.93429 3.85441 1.08594 5.51125L4.38555 8.02249C4.78912 6.8203 5.56754 5.77255 6.61107 5.02699C7.6546 4.28143 8.9106 3.87565 10.202 3.86687Z"
fill="#EB4335"
/>
</g>
<defs>
<clipPath id="clip0_1715_17244">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function UserIcon(props: IconProps) {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.99881 1.0415C7.81268 1.0415 6.04048 2.81371 6.04048 4.99984C6.04048 7.18596 7.81268 8.95817 9.99881 8.95817C12.1849 8.95817 13.9571 7.18596 13.9571 4.99984C13.9571 2.81371 12.1849 1.0415 9.99881 1.0415ZM7.29048 4.99984C7.29048 3.50407 8.50304 2.2915 9.99881 2.2915C11.4946 2.2915 12.7071 3.50407 12.7071 4.99984C12.7071 6.49561 11.4946 7.70817 9.99881 7.70817C8.50304 7.70817 7.29048 6.49561 7.29048 4.99984Z"
fill=""
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.99881 10.2082C8.07085 10.2082 6.29458 10.6464 4.97835 11.3868C3.68171 12.1161 2.70714 13.2216 2.70714 14.5832L2.70709 14.6681C2.70615 15.6363 2.70496 16.8515 3.77082 17.7195C4.29538 18.1466 5.02921 18.4504 6.02065 18.6511C7.01486 18.8523 8.31066 18.9582 9.99881 18.9582C11.687 18.9582 12.9828 18.8523 13.977 18.6511C14.9684 18.4504 15.7022 18.1466 16.2268 17.7195C17.2927 16.8515 17.2915 15.6363 17.2905 14.6681L17.2905 14.5832C17.2905 13.2216 16.3159 12.1161 15.0193 11.3868C13.703 10.6464 11.9268 10.2082 9.99881 10.2082ZM3.95714 14.5832C3.95714 13.8737 4.47496 13.1041 5.59118 12.4763C6.68781 11.8594 8.24487 11.4582 9.99881 11.4582C11.7527 11.4582 13.3098 11.8594 14.4064 12.4763C15.5227 13.1041 16.0405 13.8737 16.0405 14.5832C16.0405 15.673 16.0069 16.2865 15.4375 16.7502C15.1287 17.0016 14.6125 17.2471 13.729 17.4259C12.8482 17.6042 11.644 17.7082 9.99881 17.7082C8.35362 17.7082 7.14943 17.6042 6.26864 17.4259C5.38508 17.2471 4.86891 17.0016 4.56013 16.7502C3.99074 16.2865 3.95714 15.673 3.95714 14.5832Z"
fill=""
/>
</svg>
);
}
export function CallIcon(props: IconProps) {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.77789 1.70226C5.79233 0.693575 7.46264 0.873121 8.31207 2.00777L9.36289 3.41144C10.0541 4.33468 9.99306 5.62502 9.17264 6.44079L8.97367 6.63863C8.96498 6.66387 8.9439 6.74322 8.96729 6.89401C9.01998 7.23359 9.30354 7.95393 10.494 9.1376C11.684 10.3209 12.4094 10.6041 12.7538 10.657C12.9099 10.6809 12.9915 10.6586 13.0168 10.6498L13.3568 10.3117C14.0862 9.58651 15.2069 9.45095 16.1099 9.94183L17.702 10.8073C19.0653 11.5484 19.4097 13.4015 18.2928 14.5121L17.109 15.6892C16.736 16.06 16.2344 16.3693 15.6223 16.4264C14.1148 16.5669 10.5996 16.3876 6.90615 12.7151C3.45788 9.28642 2.79616 6.29643 2.71244 4.82323L3.33643 4.78777L2.71244 4.82323C2.67011 4.07831 3.02212 3.44806 3.46989 3.00283L4.77789 1.70226ZM7.31141 2.75689C6.88922 2.19294 6.10232 2.1481 5.65925 2.58866L4.35125 3.88923C4.07632 4.1626 3.94404 4.46388 3.96043 4.75231C4.02695 5.92281 4.56136 8.62088 7.78751 11.8287C11.1721 15.194 14.298 15.2944 15.5062 15.1818C15.7531 15.1587 15.9986 15.0305 16.2276 14.8028L17.4114 13.6257C17.8926 13.1472 17.7865 12.276 17.105 11.9055L15.5129 11.0401C15.0733 10.8011 14.5582 10.8799 14.2382 11.1981L13.8586 11.5755L13.418 11.1323C13.8586 11.5755 13.858 11.5761 13.8574 11.5767L13.8562 11.5779L13.8537 11.5804L13.8483 11.5856L13.8361 11.5969C13.8273 11.6049 13.8173 11.6137 13.806 11.6231C13.7833 11.6418 13.7555 11.663 13.7222 11.6853C13.6555 11.73 13.5674 11.7786 13.4567 11.8199C13.231 11.904 12.9333 11.9491 12.5643 11.8925C11.842 11.7817 10.8851 11.2893 9.61261 10.024C8.34054 8.75915 7.84394 7.80671 7.73207 7.08564C7.67487 6.71693 7.72049 6.41918 7.8056 6.1933C7.84731 6.0826 7.89646 5.99458 7.94157 5.928C7.96407 5.8948 7.98548 5.86704 8.00437 5.84449C8.01382 5.83322 8.02265 5.82323 8.03068 5.81451L8.04212 5.80235L8.04737 5.79697L8.04986 5.79445L8.05107 5.79323C8.05167 5.79264 8.05227 5.79204 8.49295 6.23524L8.05227 5.79204L8.29128 5.55439C8.64845 5.19925 8.69847 4.60971 8.36223 4.16056L7.31141 2.75689Z"
fill=""
/>
</svg>
);
}
export function PencilSquareIcon(props: IconProps) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_2575_3985)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.95697 0.9375L10.125 0.9375C10.4357 0.9375 10.6875 1.18934 10.6875 1.5C10.6875 1.81066 10.4357 2.0625 10.125 2.0625H9C7.21633 2.0625 5.93517 2.06369 4.96018 2.19478C4.00138 2.32369 3.42334 2.56886 2.9961 2.9961C2.56886 3.42334 2.32369 4.00138 2.19478 4.96018C2.06369 5.93517 2.0625 7.21633 2.0625 9C2.0625 10.7837 2.06369 12.0648 2.19478 13.0398C2.32369 13.9986 2.56886 14.5767 2.9961 15.0039C3.42334 15.4311 4.00138 15.6763 4.96018 15.8052C5.93517 15.9363 7.21633 15.9375 9 15.9375C10.7837 15.9375 12.0648 15.9363 13.0398 15.8052C13.9986 15.6763 14.5767 15.4311 15.0039 15.0039C15.4311 14.5767 15.6763 13.9986 15.8052 13.0398C15.9363 12.0648 15.9375 10.7837 15.9375 9V7.875C15.9375 7.56434 16.1893 7.3125 16.5 7.3125C16.8107 7.3125 17.0625 7.56434 17.0625 7.875V9.04303C17.0625 10.7743 17.0625 12.1311 16.9202 13.1897C16.7745 14.2733 16.4705 15.1283 15.7994 15.7994C15.1283 16.4705 14.2733 16.7745 13.1897 16.9202C12.1311 17.0625 10.7743 17.0625 9.04303 17.0625H8.95697C7.22567 17.0625 5.8689 17.0625 4.81028 16.9202C3.72673 16.7745 2.87171 16.4705 2.2006 15.7994C1.5295 15.1283 1.22549 14.2733 1.07981 13.1897C0.937483 12.1311 0.937491 10.7743 0.9375 9.04303V8.95697C0.937491 7.22567 0.937483 5.86889 1.07981 4.81028C1.22549 3.72673 1.5295 2.87171 2.2006 2.2006C2.87171 1.5295 3.72673 1.22549 4.81028 1.07981C5.86889 0.937483 7.22567 0.937491 8.95697 0.9375ZM12.5779 1.70694C13.6038 0.681022 15.2671 0.681022 16.2931 1.70694C17.319 2.73285 17.319 4.39619 16.2931 5.4221L11.307 10.4082C11.0285 10.6867 10.8541 10.8611 10.6594 11.013C10.4302 11.1918 10.1821 11.3451 9.91961 11.4702C9.69676 11.5764 9.46271 11.6544 9.08909 11.7789L6.9107 12.505C6.50851 12.6391 6.0651 12.5344 5.76533 12.2347C5.46556 11.9349 5.36089 11.4915 5.49495 11.0893L6.22108 8.91092C6.34559 8.53729 6.42359 8.30324 6.5298 8.08039C6.65489 7.81791 6.80821 7.56984 6.98703 7.34056C7.13887 7.1459 7.31333 6.97147 7.59183 6.693L12.5779 1.70694ZM15.4976 2.50243C14.911 1.91586 13.96 1.91586 13.3734 2.50243L13.0909 2.7849C13.108 2.85679 13.1318 2.94245 13.1649 3.038C13.2724 3.34779 13.4758 3.75579 13.86 4.13999C14.2442 4.5242 14.6522 4.7276 14.962 4.83508C15.0575 4.86823 15.1432 4.89205 15.2151 4.90907L15.4976 4.62661C16.0841 4.04003 16.0841 3.08901 15.4976 2.50243ZM14.3289 5.79532C13.9419 5.6289 13.4911 5.36209 13.0645 4.93549C12.6379 4.50889 12.3711 4.05812 12.2047 3.67114L8.41313 7.46269C8.10075 7.77508 7.97823 7.89897 7.87411 8.03246C7.74553 8.19731 7.6353 8.37567 7.54536 8.56439C7.47252 8.71722 7.41651 8.8822 7.2768 9.30131L6.95288 10.2731L7.72693 11.0471L8.69869 10.7232C9.1178 10.5835 9.28278 10.5275 9.43561 10.4546C9.62433 10.3647 9.80269 10.2545 9.96754 10.1259C10.101 10.0218 10.2249 9.89926 10.5373 9.58687L14.3289 5.79532Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_2575_3985">
<rect width="18" height="18" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function UploadIcon(props: IconProps) {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_2298_23087)">
<path
d="M18.75 13.7501C18.375 13.7501 18.0313 14.0626 18.0313 14.4688V17.2501C18.0313 17.5313 17.8125 17.7501 17.5313 17.7501H2.46875C2.1875 17.7501 1.96875 17.5313 1.96875 17.2501V14.4688C1.96875 14.0626 1.625 13.7501 1.25 13.7501C0.875 13.7501 0.53125 14.0626 0.53125 14.4688V17.2501C0.53125 18.3126 1.375 19.1563 2.4375 19.1563H17.5313C18.5938 19.1563 19.4375 18.3126 19.4375 17.2501V14.4688C19.4688 14.0626 19.125 13.7501 18.75 13.7501Z"
fill=""
/>
<path
d="M5.96875 6.46881L9.3125 3.21881V14.0313C9.3125 14.4063 9.625 14.7501 10.0312 14.7501C10.4062 14.7501 10.75 14.4376 10.75 14.0313V3.21881L14.0937 6.46881C14.2187 6.59381 14.4063 6.65631 14.5938 6.65631C14.7813 6.65631 14.9688 6.59381 15.0938 6.43756C15.375 6.15631 15.3438 5.71881 15.0938 5.43756L10.5 1.06256C10.2187 0.812561 9.78125 0.812561 9.53125 1.06256L4.96875 5.46881C4.6875 5.75006 4.6875 6.18756 4.96875 6.46881C5.25 6.71881 5.6875 6.75006 5.96875 6.46881Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_2298_23087">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
);
}
+13
View File
@@ -0,0 +1,13 @@
<svg width="174" height="30" viewBox="0 0 174 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.2" d="M30 15C30 23.2843 23.2843 30 15 30C6.71573 30 0 23.2843 0 15C0 6.71573 6.71573 0 15 0C23.2843 0 30 6.71573 30 15ZM5.82206 15C5.82206 20.0688 9.93116 24.1779 15 24.1779C20.0688 24.1779 24.1779 20.0688 24.1779 15C24.1779 9.93116 20.0688 5.82206 15 5.82206C9.93116 5.82206 5.82206 9.93116 5.82206 15Z" fill="#D1D5DB"/>
<path d="M26.0711 10.1447C27.5434 9.49895 29.2914 10.1686 29.641 11.7379C30.151 14.0271 30.1201 16.418 29.5323 18.7164C28.7025 21.9611 26.8107 24.8348 24.1583 26.8796C21.5059 28.9245 18.2454 30.0228 14.8964 29.9996C11.5473 29.9765 8.30233 28.8332 5.67841 26.7519C3.0545 24.6707 1.20259 21.7711 0.417721 18.5152C-0.367143 15.2594 -0.0398089 11.8345 1.34757 8.78624C2.73496 5.73799 5.10257 3.24172 8.07323 1.69514C10.1775 0.59962 12.4986 0.0252566 14.8438 0.000814452C16.4515 -0.0159403 17.5014 1.53369 17.2078 3.11436V3.11436C16.9142 4.69504 15.3716 5.68973 13.7782 5.90376C12.7321 6.04427 11.7109 6.36512 10.7618 6.85925C8.94413 7.80555 7.49547 9.33292 6.64659 11.198C5.7977 13.0631 5.59741 15.1587 6.07764 17.1508C6.55787 19.143 7.69099 20.9171 9.29647 22.1906C10.9019 23.464 12.8874 24.1636 14.9366 24.1777C16.9857 24.1919 18.9807 23.5199 20.6036 22.2687C22.2265 21.0176 23.3841 19.2593 23.8918 17.2739C24.1569 16.2373 24.2369 15.1698 24.1356 14.1192C23.9813 12.5189 24.5987 10.7904 26.0711 10.1447V10.1447Z" fill="#5750F1"/>
<path d="M48.3289 24.6565H45V5.34346H48.3554L57.4174 19.0291V5.34346H60.7464V24.6565H57.4174L48.3289 10.9709V24.6565Z" fill="white"/>
<path d="M69.8563 25C65.9726 25 63.2513 22.1731 63.2513 18.1308C63.2513 14.0357 65.9197 11.2087 69.7507 11.2087C73.6608 11.2087 76.1443 13.8243 76.1443 17.893V18.8705L66.316 18.897C66.5538 21.1955 67.7692 22.358 69.9092 22.358C71.6793 22.358 72.8418 21.6711 73.2117 20.4293H76.1972C75.6423 23.2827 73.2645 25 69.8563 25ZM69.7771 13.8507C67.8748 13.8507 66.7124 14.8811 66.3953 16.8362H72.9475C72.9475 15.0396 71.7057 13.8507 69.7771 13.8507Z" fill="white"/>
<path d="M79.8743 24.6565H76.2019L80.6933 18.2629L76.2019 11.605H79.9536L82.8333 16.0436L85.6075 11.605H89.227L84.7884 18.21L89.0949 24.6565H85.3961L82.622 20.3501L79.8743 24.6565Z" fill="white"/>
<path d="M95.0578 24.6565H91.8345V14.2999H89.0604L90.7873 11.605H91.8345V8.32893H95.0578V11.605H97.5941V14.2999H95.0578V24.6565Z" fill="white"/>
<path d="M102.795 24.6565H99.2809L106.256 5.34346H109.717L116.692 24.6565H113.125L111.566 20.1915H104.354L102.795 24.6565ZM107.55 11.103L105.357 17.3382H110.589L108.369 11.103C108.211 10.6011 108.026 10.0198 107.973 9.62351C107.894 9.9934 107.735 10.5746 107.55 11.103Z" fill="white"/>
<path d="M122.615 25C118.837 25 116.486 22.2259 116.486 18.1836C116.486 14.1149 118.864 11.2087 122.8 11.2087C124.623 11.2087 126.235 11.9749 127.054 13.2695V5H130.251V24.6565H127.292L127.08 22.6222C126.288 24.1281 124.597 25 122.615 25ZM123.329 22.041C125.574 22.041 127.027 20.4293 127.027 18.0779C127.027 15.7266 125.574 14.0885 123.329 14.0885C121.083 14.0885 119.709 15.753 119.709 18.0779C119.709 20.4029 121.083 22.041 123.329 22.041Z" fill="white"/>
<path d="M136.04 24.6565H132.817V11.605H135.776L136.04 13.1374C136.701 12.0542 138.022 11.2087 139.898 11.2087C141.879 11.2087 143.253 12.1863 143.94 13.6922C144.6 12.1863 146.133 11.2087 148.114 11.2087C151.285 11.2087 153.028 13.111 153.028 16.1229V24.6565H149.832V16.9683C149.832 15.0925 148.828 14.1149 147.295 14.1149C145.736 14.1149 144.548 15.1189 144.548 17.2589V24.6565H141.324V16.9419C141.324 15.1189 140.347 14.1413 138.814 14.1413C137.282 14.1413 136.04 15.1453 136.04 17.2589V24.6565Z" fill="white"/>
<path d="M157.012 8.98943C155.902 8.98943 155.03 8.11757 155.03 7.03435C155.03 5.95112 155.902 5.10568 157.012 5.10568C158.068 5.10568 158.94 5.95112 158.94 7.03435C158.94 8.11757 158.068 8.98943 157.012 8.98943ZM155.4 24.6565V11.605H158.623V24.6565H155.4Z" fill="white"/>
<path d="M164.384 24.6565H161.161V11.605H164.146L164.41 13.2959C165.23 11.9749 166.815 11.2087 168.585 11.2087C171.861 11.2087 173.552 13.2431 173.552 16.6248V24.6565H170.329V17.391C170.329 15.1982 169.245 14.1413 167.581 14.1413C165.599 14.1413 164.384 15.5152 164.384 17.6288V24.6565Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="24" cy="24" r="24" fill="#3162C9"/>
<path d="M25.789 35.9982V25.0532H29.3269L29.8566 20.7878H25.789V18.0644C25.789 16.8295 26.1192 15.9878 27.8248 15.9878L30 15.9868V12.1718C29.6236 12.12 28.3325 12.0039 26.8304 12.0039C23.6942 12.0039 21.5471 13.9916 21.5471 17.6422V20.7879H18V25.0533H21.547V35.9983L25.789 35.9982Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 449 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="24" cy="24" r="24" fill="#212529"/>
<path d="M24 12.675C17.625 12.675 12.375 17.85 12.375 24.3C12.375 29.4 15.7125 33.75 20.3625 35.325C20.9625 35.4375 21.15 35.0625 21.15 34.8C21.15 34.5375 21.15 33.7875 21.1125 32.775C17.8875 33.525 17.2125 31.2 17.2125 31.2C16.6875 29.8875 15.9 29.5125 15.9 29.5125C14.85 28.7625 15.9375 28.7625 15.9375 28.7625C17.1 28.8 17.7375 29.9625 17.7375 29.9625C18.75 31.7625 20.475 31.2375 21.1125 30.9C21.225 30.15 21.525 29.625 21.8625 29.325C19.3125 29.0625 16.575 28.05 16.575 23.625C16.575 22.35 17.0625 21.3375 17.775 20.55C17.6625 20.2875 17.25 19.0875 17.8875 17.475C17.8875 17.475 18.9 17.175 21.1125 18.675C22.05 18.4125 23.025 18.2625 24.0375 18.2625C25.05 18.2625 26.0625 18.375 26.9625 18.675C29.175 17.2125 30.15 17.475 30.15 17.475C30.7875 19.05 30.4125 20.2875 30.2625 20.55C31.0125 21.3375 31.4625 22.3875 31.4625 23.625C31.4625 28.05 28.725 29.0625 26.175 29.325C26.5875 29.7 26.9625 30.45 26.9625 31.5C26.9625 33.075 26.925 34.3125 26.925 34.6875C26.925 34.9875 27.15 35.325 27.7125 35.2125C32.2875 33.675 35.625 29.3625 35.625 24.225C35.5875 17.85 30.375 12.675 24 12.675Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="24" cy="24" r="24" fill="#EEF0F2"/>
<path d="M36.0002 24.2662C36.0147 23.4413 35.9278 22.6176 35.7414 21.813H24.2451V26.2662H30.9933C30.8655 27.0471 30.5778 27.7945 30.1476 28.4636C29.7174 29.1326 29.1536 29.7095 28.49 30.1595L28.4665 30.3087L32.1016 33.0683L32.3533 33.093C34.6661 30.9996 35.9997 27.9195 35.9997 24.2662" fill="#4285F4"/>
<path d="M24.2449 36C27.5509 36 30.3264 34.9333 32.3539 33.0933L28.4898 30.1598C27.4559 30.8667 26.0681 31.36 24.2449 31.36C22.6965 31.3512 21.1902 30.8646 19.9398 29.9695C18.6894 29.0744 17.7584 27.8162 17.2789 26.3733L17.1354 26.3853L13.3556 29.2519L13.3062 29.3865C14.3241 31.3748 15.8864 33.0464 17.8183 34.2143C19.7502 35.3822 21.9755 36.0005 24.2454 36" fill="#34A853"/>
<path d="M17.2788 26.3733C17.011 25.6094 16.8728 24.8077 16.8697 24C16.8746 23.1936 17.0077 22.393 17.2642 21.6267L17.2574 21.4677L13.4312 18.5549L13.3061 18.6133C12.4473 20.2842 12 22.129 12 23.9999C12 25.8708 12.4473 27.7156 13.3061 29.3865L17.2788 26.3733Z" fill="#FBBC05"/>
<path d="M24.2449 16.6399C25.9995 16.6132 27.6964 17.2535 28.9796 18.4266L32.4355 15.1199C30.219 13.0821 27.2838 11.964 24.2449 11.9999C21.975 11.9993 19.7497 12.6176 17.8179 13.7855C15.886 14.9534 14.3237 16.6249 13.3057 18.6131L17.2652 21.6266C17.7495 20.184 18.6836 18.9267 19.9358 18.032C21.1881 17.1373 22.6953 16.6504 24.2449 16.6399Z" fill="#EB4335"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+7
View File
@@ -0,0 +1,7 @@
export { default as dark } from './dark.svg';
export { default as facebook } from './facebook.svg';
export { default as github } from './github.svg';
export { default as google } from './google.svg';
export { default as main } from './main.svg';
export { default as vimeo } from './vimeo.svg';
export { default as x } from './x.svg';
+13
View File
@@ -0,0 +1,13 @@
<svg width="174" height="30" viewBox="0 0 174 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M30 15C30 23.2843 23.2843 30 15 30C6.71573 30 0 23.2843 0 15C0 6.71573 6.71573 0 15 0C23.2843 0 30 6.71573 30 15ZM5.82206 15C5.82206 20.0688 9.93116 24.1779 15 24.1779C20.0688 24.1779 24.1779 20.0688 24.1779 15C24.1779 9.93116 20.0688 5.82206 15 5.82206C9.93116 5.82206 5.82206 9.93116 5.82206 15Z" fill="#E5E7EB"/>
<path d="M26.0711 10.1447C27.5434 9.49895 29.2914 10.1686 29.641 11.7379C30.151 14.0271 30.1201 16.418 29.5323 18.7164C28.7025 21.9611 26.8107 24.8348 24.1583 26.8796C21.5059 28.9245 18.2454 30.0228 14.8964 29.9996C11.5473 29.9765 8.30233 28.8332 5.67841 26.7519C3.0545 24.6707 1.20259 21.7711 0.417721 18.5152C-0.367143 15.2594 -0.0398089 11.8345 1.34757 8.78624C2.73496 5.73799 5.10257 3.24172 8.07323 1.69514C10.1775 0.59962 12.4986 0.0252566 14.8438 0.000814452C16.4515 -0.0159403 17.5014 1.53369 17.2078 3.11436C16.9142 4.69504 15.3716 5.68973 13.7782 5.90376C12.7321 6.04427 11.7109 6.36512 10.7618 6.85925C8.94413 7.80555 7.49547 9.33292 6.64659 11.198C5.7977 13.0631 5.59741 15.1587 6.07764 17.1508C6.55787 19.143 7.69099 20.9171 9.29647 22.1906C10.9019 23.464 12.8874 24.1636 14.9366 24.1777C16.9857 24.1919 18.9807 23.5199 20.6036 22.2687C22.2265 21.0176 23.3841 19.2593 23.8918 17.2739C24.1569 16.2373 24.2369 15.1698 24.1356 14.1192C23.9813 12.5189 24.5987 10.7904 26.0711 10.1447Z" fill="#5750F1"/>
<path d="M48.3289 24.6565H45V5.34346H48.3554L57.4174 19.0291V5.34346H60.7464V24.6565H57.4174L48.3289 10.9709V24.6565Z" fill="#111928"/>
<path d="M69.8563 25C65.9726 25 63.2513 22.1731 63.2513 18.1308C63.2513 14.0357 65.9197 11.2087 69.7507 11.2087C73.6608 11.2087 76.1443 13.8243 76.1443 17.893V18.8705L66.316 18.897C66.5538 21.1955 67.7692 22.358 69.9092 22.358C71.6793 22.358 72.8418 21.6711 73.2117 20.4293H76.1972C75.6423 23.2827 73.2645 25 69.8563 25ZM69.7771 13.8507C67.8748 13.8507 66.7124 14.8811 66.3953 16.8362H72.9475C72.9475 15.0396 71.7057 13.8507 69.7771 13.8507Z" fill="#111928"/>
<path d="M79.8743 24.6565H76.2019L80.6933 18.2629L76.2019 11.605H79.9536L82.8333 16.0436L85.6075 11.605H89.227L84.7884 18.21L89.0949 24.6565H85.3961L82.622 20.3501L79.8743 24.6565Z" fill="#111928"/>
<path d="M95.0578 24.6565H91.8345V14.2999H89.0604L90.7873 11.605H91.8345V8.32893H95.0578V11.605H97.5941V14.2999H95.0578V24.6565Z" fill="#111928"/>
<path d="M102.795 24.6565H99.2809L106.256 5.34346H109.717L116.692 24.6565H113.125L111.566 20.1915H104.354L102.795 24.6565ZM107.55 11.103L105.357 17.3382H110.589L108.369 11.103C108.211 10.6011 108.026 10.0198 107.973 9.62351C107.894 9.9934 107.735 10.5746 107.55 11.103Z" fill="#111928"/>
<path d="M122.615 25C118.837 25 116.486 22.2259 116.486 18.1836C116.486 14.1149 118.864 11.2087 122.8 11.2087C124.623 11.2087 126.235 11.9749 127.054 13.2695V5H130.251V24.6565H127.292L127.08 22.6222C126.288 24.1281 124.597 25 122.615 25ZM123.329 22.041C125.574 22.041 127.027 20.4293 127.027 18.0779C127.027 15.7266 125.574 14.0885 123.329 14.0885C121.083 14.0885 119.709 15.753 119.709 18.0779C119.709 20.4029 121.083 22.041 123.329 22.041Z" fill="#111928"/>
<path d="M136.04 24.6565H132.817V11.605H135.776L136.04 13.1374C136.701 12.0542 138.022 11.2087 139.898 11.2087C141.879 11.2087 143.253 12.1863 143.94 13.6922C144.6 12.1863 146.133 11.2087 148.114 11.2087C151.285 11.2087 153.028 13.111 153.028 16.1229V24.6565H149.832V16.9683C149.832 15.0925 148.828 14.1149 147.295 14.1149C145.736 14.1149 144.548 15.1189 144.548 17.2589V24.6565H141.324V16.9419C141.324 15.1189 140.347 14.1413 138.814 14.1413C137.282 14.1413 136.04 15.1453 136.04 17.2589V24.6565Z" fill="#111928"/>
<path d="M157.012 8.98943C155.902 8.98943 155.03 8.11757 155.03 7.03435C155.03 5.95112 155.902 5.10568 157.012 5.10568C158.068 5.10568 158.94 5.95112 158.94 7.03435C158.94 8.11757 158.068 8.98943 157.012 8.98943ZM155.4 24.6565V11.605H158.623V24.6565H155.4Z" fill="#111928"/>
<path d="M164.384 24.6565H161.161V11.605H164.146L164.41 13.2959C165.23 11.9749 166.815 11.2087 168.585 11.2087C171.861 11.2087 173.552 13.2431 173.552 16.6248V24.6565H170.329V17.391C170.329 15.1982 169.245 14.1413 167.581 14.1413C165.599 14.1413 164.384 15.5152 164.384 17.6288V24.6565Z" fill="#111928"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="24" cy="24" r="24" fill="#4DC1FF"/>
<path d="M35.625 18.6002C35.5125 20.8877 33.9375 24.0002 30.8625 27.9377C27.7125 32.0627 25.0125 34.1252 22.8375 34.1252C21.525 34.1252 20.3625 32.9252 19.3875 30.3752C18.75 28.1252 18.1875 25.8002 17.5125 23.4752C16.8375 21.0002 16.0875 19.7252 15.225 19.7252C15.075 19.7252 14.4375 20.1002 13.3875 20.8502L12.375 19.3502C13.5375 18.3377 14.6625 17.3252 15.825 16.2752C17.3625 14.9627 18.45 14.2502 19.275 14.2127C21.075 14.0627 22.1625 15.3377 22.6125 17.9252C23.025 20.7752 23.3625 22.5752 23.55 23.2502C24.075 25.6127 24.675 26.7752 25.2375 26.7752C25.725 26.7752 26.4375 26.0252 27.45 24.4877C28.4625 22.9502 28.9125 21.7502 29.025 20.9627C29.175 19.6502 28.6125 18.9377 27.45 18.9377C26.925 18.9377 26.325 19.0502 25.7625 19.3502C26.8875 15.6002 29.025 13.7627 32.25 13.8377C34.6125 13.9502 35.7375 15.5252 35.625 18.6002Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 996 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="24" cy="24" r="24" fill="black"/>
<path d="M29.7236 15.0625H32.7559L26.1312 22.6342L33.9247 32.9375H27.8224L23.0429 26.6886L17.5741 32.9375H14.5399L21.6257 24.8387L14.1494 15.0625H20.4066L24.7268 20.7743L29.7236 15.0625ZM28.6593 31.1225H30.3396L19.4936 16.7822H17.6905L28.6593 31.1225Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 417 B

@@ -0,0 +1,10 @@
import { GoogleIcon } from "@/assets/icons";
export default function GoogleSigninButton({ text }: { text: string }) {
return (
<button className="flex w-full items-center justify-center gap-3.5 rounded-lg border border-stroke bg-gray-2 p-[15px] font-medium hover:bg-opacity-50 dark:border-dark-3 dark:bg-dark-2 dark:hover:bg-opacity-50">
<GoogleIcon />
{text} with Google
</button>
);
}
+13
View File
@@ -0,0 +1,13 @@
import Link from "next/link";
import GoogleSigninButton from "../GoogleSigninButton";
import SigninWithPassword from "../SigninWithPassword";
export default function Signin() {
return (
<>
<div>
<SigninWithPassword />
</div>
</>
);
}
@@ -0,0 +1,63 @@
"use client";
import { PasswordIcon, UserIcon } from "@/assets/icons";
import InputGroup from "../FormElements/InputGroup";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { ILoginCredentials } from "@/lib/api";
import { useLoginQuery } from "@/hooks/queries";
export default function SigninWithPassword() {
const { handleSubmit, control, reset } = useForm<ILoginCredentials>();
const { mutate, isPending } = useLoginQuery();
const onSubmit: SubmitHandler<ILoginCredentials> = (data) => {
mutate(data);
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="username"
control={control}
render={({ field: username }) => (
<InputGroup
type="username"
handleChange={(value) => username.onChange(value)}
label="Username"
className="mb-4 [&_input]:py-[15px]"
placeholder="Enter your Username"
name="username"
icon={<UserIcon />}
/>
)}
/>
<Controller
name="password"
control={control}
render={({ field: password }) => (
<InputGroup
type="password"
handleChange={(value) => password.onChange(value)}
label="Password"
className="mb-5 [&_input]:py-[15px]"
placeholder="Enter your password"
name="password"
icon={<PasswordIcon />}
/>
)}
/>
<div className="mb-4.5">
<button
type="submit"
className="flex w-full cursor-pointer items-center justify-center gap-2 rounded-lg bg-primary p-4 font-medium text-white transition hover:bg-opacity-90"
>
Sign In
{/* {loading && (
<span className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-white border-t-transparent dark:border-primary dark:border-t-transparent" />
)} */}
</button>
</div>
</form>
);
}
+48
View File
@@ -0,0 +1,48 @@
import Link from "next/link";
interface BreadcrumbItem {
name: string;
href: string;
}
interface BreadcrumbProps {
items: BreadcrumbItem[];
}
const Breadcrumb = ({ items }: BreadcrumbProps) => {
const currentPage = items[items.length - 1];
return (
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<h2 className="text-[26px] font-bold leading-[30px] text-dark dark:text-white">
{currentPage.name}
</h2>
<nav>
<ol className="flex items-center gap-2">
{items.map((item, index) => {
const isLast = index === items.length - 1;
return isLast ? (
<li key={index} className="font-medium text-primary">
{item.name}
</li>
) : (
<li key={index} className="flex items-center gap-2">
<Link
href={item.href}
className="font-medium hover:text-primary"
>
{item.name}
</Link>
<span className="text-dark dark:text-white">/</span>
</li>
);
})}
</ol>
</nav>
</div>
);
};
export default Breadcrumb;
+237
View File
@@ -0,0 +1,237 @@
const CalendarBox = () => {
return (
<>
<div className="w-full max-w-full rounded-[10px] bg-white shadow-1 dark:bg-gray-dark dark:shadow-card">
<table className="w-full">
<thead>
<tr className="grid grid-cols-7 rounded-t-[10px] bg-primary text-white">
<th className="flex h-15 items-center justify-center rounded-tl-[10px] p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Sunday </span>
<span className="block lg:hidden"> Sun </span>
</th>
<th className="flex h-15 items-center justify-center p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Monday </span>
<span className="block lg:hidden"> Mon </span>
</th>
<th className="flex h-15 items-center justify-center p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Tuesday </span>
<span className="block lg:hidden"> Tue </span>
</th>
<th className="flex h-15 items-center justify-center p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Wednesday </span>
<span className="block lg:hidden"> Wed </span>
</th>
<th className="flex h-15 items-center justify-center p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Thursday </span>
<span className="block lg:hidden"> Thur </span>
</th>
<th className="flex h-15 items-center justify-center p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Friday </span>
<span className="block lg:hidden"> Fri </span>
</th>
<th className="flex h-15 items-center justify-center rounded-tr-[10px] p-1 text-body-xs font-medium sm:text-base xl:p-5">
<span className="hidden lg:block"> Saturday </span>
<span className="block lg:hidden"> Sat </span>
</th>
</tr>
</thead>
<tbody>
{/* <!-- Line 1 --> */}
<tr className="grid grid-cols-7">
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">1</span>
<div className="group h-16 w-full flex-grow cursor-pointer py-1 md:h-30">
<span className="group-hover:text-primary md:hidden">
More
</span>
<div className="event invisible absolute left-2 z-99 mb-1 flex w-[200%] flex-col rounded-r-[5px] border-l-[3px] border-primary bg-gray-2 px-3 py-1 text-left opacity-0 group-hover:visible group-hover:opacity-100 dark:bg-dark-2 md:visible md:w-[190%] md:opacity-100">
<span className="event-name font-medium text-dark dark:text-white">
Redesign Website
</span>
<span className="time text-sm">1 Dec - 2 Dec</span>
</div>
</div>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">2</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">3</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">4</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">5</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">6</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">7</span>
</td>
</tr>
{/* <!-- Line 1 --> */}
{/* <!-- Line 2 --> */}
<tr className="grid grid-cols-7">
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">8</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">9</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
10
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
11
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
12
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
13
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
14
</span>
</td>
</tr>
{/* <!-- Line 2 --> */}
{/* <!-- Line 3 --> */}
<tr className="grid grid-cols-7">
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
15
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
16
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
17
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
18
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
19
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
20
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
21
</span>
</td>
</tr>
{/* <!-- Line 3 --> */}
{/* <!-- Line 4 --> */}
<tr className="grid grid-cols-7">
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
22
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
23
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
24
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
25
</span>
<div className="group h-16 w-full flex-grow cursor-pointer py-1 md:h-30">
<span className="group-hover:text-primary md:hidden">
More
</span>
<div className="event invisible absolute left-2 z-99 mb-1 flex w-[300%] flex-col rounded-r-[5px] border-l-[3px] border-primary bg-gray-2 px-3 py-1 text-left opacity-0 group-hover:visible group-hover:opacity-100 dark:bg-dark-2 md:visible md:w-[290%] md:opacity-100">
<span className="event-name font-medium text-dark dark:text-white">
App Design
</span>
<span className="time text-sm">25 Dec - 27 Dec</span>
</div>
</div>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
26
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
27
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
28
</span>
</td>
</tr>
{/* <!-- Line 4 --> */}
{/* <!-- Line 5 --> */}
<tr className="grid grid-cols-7">
<td className="ease relative h-20 cursor-pointer rounded-bl-[10px] border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
29
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
30
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">
31
</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">1</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">2</span>
</td>
<td className="ease relative h-20 cursor-pointer border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">3</span>
</td>
<td className="ease relative h-20 cursor-pointer rounded-br-[10px] border border-stroke p-2 transition duration-500 hover:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-2 md:h-25 md:p-6 xl:h-31">
<span className="font-medium text-dark dark:text-white">4</span>
</td>
</tr>
{/* <!-- Line 5 --> */}
</tbody>
</table>
</div>
</>
);
};
export default CalendarBox;
@@ -0,0 +1,90 @@
"use client";
import type { ApexOptions } from "apexcharts";
import dynamic from "next/dynamic";
type PropsType = {
data: {
x: string;
y: number;
}[];
};
const Chart = dynamic(() => import("react-apexcharts"), {
ssr: false,
});
export function CampaignVisitorsChart({ data }: PropsType) {
const options: ApexOptions = {
colors: ["#5750F1"],
chart: {
fontFamily: "Satoshi, sans-serif",
type: "bar",
height: 200,
toolbar: {
show: false,
},
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: "40%",
borderRadius: 3,
},
},
dataLabels: {
enabled: false,
},
stroke: {
show: true,
width: 4,
colors: ["transparent"],
},
xaxis: {
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
legend: {
show: true,
position: "top",
horizontalAlign: "left",
fontFamily: "Satoshi",
},
grid: {
strokeDashArray: 7,
yaxis: {
lines: {
show: true,
},
},
},
fill: {
opacity: 1,
},
tooltip: {
x: {
show: false,
},
},
};
return (
<div className="-ml-3.5 px-6 pb-1 pt-7.5">
<Chart
options={options}
series={[
{
name: "Visitors",
data,
},
]}
type="bar"
height={230}
/>
</div>
);
}
@@ -0,0 +1,49 @@
import { TrendingUpIcon } from "@/assets/icons";
import { compactFormat } from "@/lib/format-number";
import { cn } from "@/lib/utils";
import { getCampaignVisitorsData } from "@/services/charts.services";
import { CampaignVisitorsChart } from "./chart";
export async function CampaignVisitors({ className }: { className?: string }) {
const data = await getCampaignVisitorsData();
return (
<div
className={cn(
"rounded-[10px] bg-white shadow-1 dark:bg-gray-dark dark:shadow-card",
className,
)}
>
<div className="border-b border-stroke px-6 py-5.5 dark:border-dark-3">
<div className="flex justify-between">
<h2 className="mb-1.5 text-2xl font-bold text-dark dark:text-white">
Campaign Visitors
</h2>
<div className="mb-0.5 text-2xl font-bold text-dark dark:text-white">
{compactFormat(data.total_visitors)}
</div>
</div>
<div className="flex justify-between">
<div className="text-sm font-medium">Last Campaign Performance</div>
<div
className={cn(
"flex items-center gap-1.5",
data.performance > 0 ? "text-green" : "text-red",
)}
>
<TrendingUpIcon
className={`${data.performance > 0 ? "-rotate-6" : "scale-y-[-1]"}`}
/>
<span className="text-sm font-medium">{data.performance}%</span>
</div>
</div>
</div>
<CampaignVisitorsChart data={data.chart} />
</div>
);
}
@@ -0,0 +1,107 @@
"use client";
import { useIsMobile } from "@/hooks/use-mobile";
import type { ApexOptions } from "apexcharts";
import dynamic from "next/dynamic";
type PropsType = {
data: {
received: { x: unknown; y: number }[];
due: { x: unknown; y: number }[];
};
};
const Chart = dynamic(() => import("react-apexcharts"), {
ssr: false,
});
export function PaymentsOverviewChart({ data }: PropsType) {
const isMobile = useIsMobile();
const options: ApexOptions = {
legend: {
show: false,
},
colors: ["#5750F1", "#0ABEF9"],
chart: {
height: 310,
type: "area",
toolbar: {
show: false,
},
fontFamily: "inherit",
},
fill: {
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
},
},
responsive: [
{
breakpoint: 1024,
options: {
chart: {
height: 300,
},
},
},
{
breakpoint: 1366,
options: {
chart: {
height: 320,
},
},
},
],
stroke: {
curve: "smooth",
width: isMobile ? 2 : 3,
},
grid: {
strokeDashArray: 5,
yaxis: {
lines: {
show: true,
},
},
},
dataLabels: {
enabled: false,
},
tooltip: {
marker: {
show: true,
},
},
xaxis: {
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
};
return (
<div className="-ml-4 -mr-5 h-[310px]">
<Chart
options={options}
series={[
{
name: "Received",
data: data.received,
},
{
name: "Due",
data: data.due,
},
]}
type="area"
height={310}
/>
</div>
);
}
@@ -0,0 +1,52 @@
import { PeriodPicker } from "@/components/period-picker";
import { standardFormat } from "@/lib/format-number";
import { cn } from "@/lib/utils";
import { getPaymentsOverviewData } from "@/services/charts.services";
import { PaymentsOverviewChart } from "./chart";
type PropsType = {
timeFrame?: string;
className?: string;
};
export async function PaymentsOverview({
timeFrame = "monthly",
className,
}: PropsType) {
const data = await getPaymentsOverviewData(timeFrame);
return (
<div
className={cn(
"grid gap-2 rounded-[10px] bg-white px-7.5 pb-6 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card",
className,
)}
>
<div className="flex flex-wrap items-center justify-between gap-4">
<h2 className="text-body-2xlg font-bold text-dark dark:text-white">
Payments Overview
</h2>
<PeriodPicker defaultValue={timeFrame} sectionKey="payments_overview" />
</div>
<PaymentsOverviewChart data={data} />
<dl className="grid divide-stroke text-center dark:divide-dark-3 sm:grid-cols-2 sm:divide-x [&>div]:flex [&>div]:flex-col-reverse [&>div]:gap-1">
<div className="dark:border-dark-3 max-sm:mb-3 max-sm:border-b max-sm:pb-3">
<dt className="text-xl font-bold text-dark dark:text-white">
${standardFormat(data.received.reduce((acc, { y }) => acc + y, 0))}
</dt>
<dd className="font-medium dark:text-dark-6">Received Amount</dd>
</div>
<div>
<dt className="text-xl font-bold text-dark dark:text-white">
${standardFormat(data.due.reduce((acc, { y }) => acc + y, 0))}
</dt>
<dd className="font-medium dark:text-dark-6">Due Amount</dd>
</div>
</dl>
</div>
);
}
@@ -0,0 +1,97 @@
"use client";
import { compactFormat } from "@/lib/format-number";
import type { ApexOptions } from "apexcharts";
import dynamic from "next/dynamic";
type PropsType = {
data: { name: string; amount: number }[];
};
const Chart = dynamic(() => import("react-apexcharts"), {
ssr: false,
});
export function DonutChart({ data }: PropsType) {
const chartOptions: ApexOptions = {
chart: {
type: "donut",
fontFamily: "inherit",
},
colors: ["#5750F1", "#5475E5", "#8099EC", "#ADBCF2"],
labels: data.map((item) => item.name),
legend: {
show: true,
position: "bottom",
itemMargin: {
horizontal: 10,
vertical: 5,
},
formatter: (legendName, opts) => {
const { seriesPercent } = opts.w.globals;
return `${legendName}: ${seriesPercent[opts.seriesIndex]}%`;
},
},
plotOptions: {
pie: {
donut: {
size: "80%",
background: "transparent",
labels: {
show: true,
total: {
show: true,
showAlways: true,
label: "Visitors",
fontSize: "16px",
fontWeight: "400",
},
value: {
show: true,
fontSize: "28px",
fontWeight: "bold",
formatter: (val) => compactFormat(+val),
},
},
},
},
},
dataLabels: {
enabled: false,
},
responsive: [
{
breakpoint: 2600,
options: {
chart: {
width: 415,
},
},
},
{
breakpoint: 640,
options: {
chart: {
width: "100%",
},
},
},
{
breakpoint: 370,
options: {
chart: {
width: 260,
},
},
},
],
};
return (
<Chart
options={chartOptions}
series={data.map((item) => item.amount)}
type="donut"
/>
);
}
@@ -0,0 +1,37 @@
import { PeriodPicker } from "@/components/period-picker";
import { cn } from "@/lib/utils";
import { getDevicesUsedData } from "@/services/charts.services";
import { DonutChart } from "./chart";
type PropsType = {
timeFrame?: string;
className?: string;
};
export async function UsedDevices({
timeFrame = "monthly",
className,
}: PropsType) {
const data = await getDevicesUsedData(timeFrame);
return (
<div
className={cn(
"grid grid-cols-1 grid-rows-[auto_1fr] gap-9 rounded-[10px] bg-white p-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card",
className,
)}
>
<div className="flex flex-wrap items-center justify-between gap-4">
<h2 className="text-body-2xlg font-bold text-dark dark:text-white">
Used Devices
</h2>
<PeriodPicker defaultValue={timeFrame} sectionKey="used_devices" />
</div>
<div className="grid place-items-center">
<DonutChart data={data} />
</div>
</div>
);
}
@@ -0,0 +1,113 @@
"use client";
import type { ApexOptions } from "apexcharts";
import dynamic from "next/dynamic";
type PropsType = {
data: {
sales: { x: string; y: number }[];
revenue: { x: string; y: number }[];
};
};
const Chart = dynamic(() => import("react-apexcharts"), {
ssr: false,
});
export function WeeksProfitChart({ data }: PropsType) {
const options: ApexOptions = {
colors: ["#5750F1", "#0ABEF9"],
chart: {
type: "bar",
stacked: true,
toolbar: {
show: false,
},
zoom: {
enabled: false,
},
},
responsive: [
{
breakpoint: 1536,
options: {
plotOptions: {
bar: {
borderRadius: 3,
columnWidth: "25%",
},
},
},
},
],
plotOptions: {
bar: {
horizontal: false,
borderRadius: 3,
columnWidth: "25%",
borderRadiusApplication: "end",
borderRadiusWhenStacked: "last",
},
},
dataLabels: {
enabled: false,
},
grid: {
strokeDashArray: 5,
xaxis: {
lines: {
show: false,
},
},
yaxis: {
lines: {
show: true,
},
},
},
xaxis: {
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
legend: {
position: "top",
horizontalAlign: "left",
fontFamily: "inherit",
fontWeight: 500,
fontSize: "14px",
markers: {
size: 9,
shape: "circle",
},
},
fill: {
opacity: 1,
},
};
return (
<div className="-ml-3.5 mt-3">
<Chart
options={options}
series={[
{
name: "Sales",
data: data.sales,
},
{
name: "Revenue",
data: data.revenue,
},
]}
type="bar"
height={370}
/>
</div>
);
}
@@ -0,0 +1,36 @@
import { PeriodPicker } from "@/components/period-picker";
import { cn } from "@/lib/utils";
import { getWeeksProfitData } from "@/services/charts.services";
import { WeeksProfitChart } from "./chart";
type PropsType = {
timeFrame?: string;
className?: string;
};
export async function WeeksProfit({ className, timeFrame }: PropsType) {
const data = await getWeeksProfitData(timeFrame);
return (
<div
className={cn(
"rounded-[10px] bg-white px-7.5 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card",
className,
)}
>
<div className="flex flex-wrap items-center justify-between gap-4">
<h2 className="text-body-2xlg font-bold text-dark dark:text-white">
Profit {timeFrame || "this week"}
</h2>
<PeriodPicker
items={["this week", "last week"]}
defaultValue={timeFrame || "this week"}
sectionKey="weeks_profit"
/>
</div>
<WeeksProfitChart data={data} />
</div>
);
}
@@ -0,0 +1,35 @@
import { useState } from "react";
const CheckboxFive = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelFive"
className="flex cursor-pointer select-none items-center text-body-sm font-medium text-dark dark:text-white"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelFive"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`box mr-2 flex h-5 w-5 items-center justify-center rounded-full border border-primary ${
isChecked && "!border-4"
}`}
>
<span className="h-2.5 w-2.5 rounded-full bg-white dark:bg-transparent"></span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxFive;
@@ -0,0 +1,43 @@
import { useState } from "react";
const CheckboxFour = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelFour"
className="flex cursor-pointer select-none items-center text-body-sm font-medium text-dark dark:text-white"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelFour"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`mr-2 flex h-5 w-5 items-center justify-center rounded-full border ${
isChecked
? "border-primary bg-gray-2 dark:bg-dark-2"
: "border-dark-5 dark:border-dark-6"
}`}
>
<span
className={`h-2.5 w-2.5 rounded-full bg-transparent ${
isChecked && "!bg-primary"
}`}
>
{" "}
</span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxFour;
@@ -0,0 +1,39 @@
import { useState } from "react";
const CheckboxOne = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelOne"
className="flex cursor-pointer select-none items-center text-body-sm font-medium"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelOne"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`mr-2 flex h-5 w-5 items-center justify-center rounded border ${
isChecked
? "border-primary bg-gray-2 dark:bg-transparent"
: "border-dark-5 dark:border-dark-6"
}`}
>
<span
className={`h-2.5 w-2.5 rounded-sm ${isChecked && "bg-primary"}`}
></span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxOne;
@@ -0,0 +1,64 @@
import { useState } from "react";
const CheckboxThree = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelThree"
className="flex cursor-pointer select-none items-center text-body-sm font-medium"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelThree"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`box mr-2 flex h-5 w-5 items-center justify-center rounded border ${
isChecked
? "border-primary bg-gray-2 dark:bg-transparent"
: "border-dark-5 dark:border-dark-6"
}`}
>
<span
className={`text-primary opacity-0 ${
isChecked && "!opacity-100"
}`}
>
<svg
className="fill-current"
width="11"
height="11"
viewBox="0 0 11 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_803_2686)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.23529 2.29669C0.942402 2.00379 0.942402 1.52892 1.23529 1.23603C1.52819 0.943134 2.00306 0.943134 2.29596 1.23603L5.37433 4.3144L8.45261 1.23612C8.7455 0.943225 9.22038 0.943225 9.51327 1.23612C9.80616 1.52901 9.80616 2.00389 9.51327 2.29678L6.43499 5.37506L9.51327 8.45334C9.80616 8.74624 9.80616 9.22111 9.51327 9.514C9.22038 9.8069 8.7455 9.8069 8.45261 9.514L5.37433 6.43572L2.29596 9.51409C2.00306 9.80699 1.52819 9.80699 1.23529 9.51409C0.942402 9.2212 0.942402 8.74633 1.23529 8.45343L4.31367 5.37506L1.23529 2.29669Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_803_2686">
<rect width="10.75" height="10.75" fill="white" />
</clipPath>
</defs>
</svg>
</span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxThree;
@@ -0,0 +1,52 @@
import { useState } from "react";
const CheckboxTwo = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelTwo"
className="flex cursor-pointer select-none items-center text-body-sm font-medium"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelTwo"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`mr-2 flex h-5 w-5 items-center justify-center rounded border ${
isChecked
? "border-primary bg-gray-2 dark:bg-transparent"
: "border border-dark-5 dark:border-dark-6"
}`}
>
<span className={`opacity-0 ${isChecked && "!opacity-100"}`}>
<svg
width="11"
height="8"
viewBox="0 0 11 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.0915 0.951972L10.0867 0.946075L10.0813 0.940568C9.90076 0.753564 9.61034 0.753146 9.42927 0.939309L4.16201 6.22962L1.58507 3.63469C1.40401 3.44841 1.11351 3.44879 0.932892 3.63584C0.755703 3.81933 0.755703 4.10875 0.932892 4.29224L0.932878 4.29225L0.934851 4.29424L3.58046 6.95832C3.73676 7.11955 3.94983 7.2 4.1473 7.2C4.36196 7.2 4.55963 7.11773 4.71406 6.9584L10.0468 1.60234C10.2436 1.4199 10.2421 1.1339 10.0915 0.951972ZM4.2327 6.30081L4.2317 6.2998C4.23206 6.30015 4.23237 6.30049 4.23269 6.30082L4.2327 6.30081Z"
fill="#5750F1"
stroke="#5750F1"
strokeWidth="0.4"
/>
</svg>
</span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxTwo;
@@ -0,0 +1,38 @@
"use client";
import { Calendar } from "@/components/Layouts/sidebar/icons";
import flatpickr from "flatpickr";
import { useEffect } from "react";
const DatePickerOne = () => {
useEffect(() => {
// Init flatpickr
flatpickr(".form-datepicker", {
mode: "single",
static: true,
monthSelectorType: "static",
dateFormat: "M j, Y",
});
}, []);
return (
<div>
<label className="mb-3 block text-body-sm font-medium text-dark dark:text-white">
Date picker
</label>
<div className="relative">
<input
className="form-datepicker w-full rounded-[7px] border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary"
placeholder="mm/dd/yyyy"
data-class="flatpickr-right"
/>
<div className="pointer-events-none absolute inset-0 left-auto right-5 flex items-center">
<Calendar className="size-5 text-[#9CA3AF]" />
</div>
</div>
</div>
);
};
export default DatePickerOne;
@@ -0,0 +1,38 @@
"use client";
import { ChevronUpIcon } from "@/assets/icons";
import flatpickr from "flatpickr";
import { useEffect } from "react";
const DatePickerTwo = () => {
useEffect(() => {
// Init flatpickr
flatpickr(".form-datepicker", {
mode: "single",
static: true,
monthSelectorType: "static",
dateFormat: "M j, Y",
});
}, []);
return (
<div>
<label className="mb-3 block text-body-sm font-medium text-dark dark:text-white">
Select date
</label>
<div className="relative">
<input
className="form-datepicker w-full rounded-[7px] border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary"
placeholder="mm/dd/yyyy"
data-class="flatpickr-right"
/>
<div className="pointer-events-none absolute inset-0 left-auto right-5 flex items-center text-dark-4 dark:text-dark-6">
<ChevronUpIcon className="rotate-180" />
</div>
</div>
</div>
);
};
export default DatePickerTwo;
@@ -0,0 +1,122 @@
import { cn } from "@/lib/utils";
import { type HTMLInputTypeAttribute, useId } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegister,
type UseFormRegisterReturn,
} from "react-hook-form";
type InputGroupProps<T extends FieldValues> = {
name: Path<T>;
label: string;
type: HTMLInputTypeAttribute;
placeholder: string;
className?: string;
fileStyleVariant?: "style1" | "style2";
required?: boolean;
disabled?: boolean;
active?: boolean;
handleChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
value?: string;
icon?: React.ReactNode;
iconPosition?: "left" | "right";
height?: "sm" | "default";
defaultValue?: string;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
} & Partial<UseFormRegisterReturn>;
const InputGroup = <T extends FieldValues>({
className,
label,
type,
placeholder,
required,
disabled,
active,
handleChange,
icon,
name,
register,
errors,
onChange,
onBlur,
ref,
...props
}: InputGroupProps<T>): React.ReactElement => {
const id = useId();
const error = errors && errors[name];
return (
<div className={className}>
<label
htmlFor={id}
className="text-body-sm font-medium text-dark dark:text-white"
>
{label}
{required && <span className="text-red ml-1 select-none">*</span>}
</label>
<div
className={cn(
"relative mt-3 [&_svg]:absolute [&_svg]:top-1/2 [&_svg]:-translate-y-1/2",
props.iconPosition === "left"
? "[&_svg]:left-4.5"
: "[&_svg]:right-4.5",
)}
>
<input
id={id}
type={type}
placeholder={placeholder}
name={name}
ref={ref}
onChange={(e) => {
onChange?.(e);
handleChange?.(e);
}}
onBlur={onBlur}
{...(!onChange &&
props.value !== undefined && { value: props.value })}
{...(!onChange &&
props.defaultValue !== undefined && {
defaultValue: props.defaultValue,
})}
className={cn(
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent outline-none transition focus:border-primary disabled:cursor-default disabled:bg-gray-2 data-[active=true]:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary dark:disabled:bg-dark dark:data-[active=true]:border-primary",
// Add error styles conditionally
error && "border-red focus:border-red dark:border-red",
type === "file"
? getFileStyles(props.fileStyleVariant!)
: "px-5.5 py-3 text-dark placeholder:text-dark-6 dark:text-white",
props.iconPosition === "left" && "pl-12.5",
props.height === "sm" && "py-2.5",
)}
disabled={disabled}
data-active={active}
/>
{icon}
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
};
export default InputGroup;
function getFileStyles(variant: "style1" | "style2") {
switch (variant) {
case "style1":
return `file:mr-5 file:border-collapse file:cursor-pointer file:border-0 file:border-r file:border-solid file:border-stroke file:bg-[#E2E8F0] file:px-6.5 file:py-[13px] file:text-body-sm file:font-medium file:text-dark-5 file:hover:bg-primary file:hover:bg-opacity-10 dark:file:border-dark-3 dark:file:bg-white/30 dark:file:text-white`;
default:
return `file:mr-4 file:rounded file:border-[0.5px] file:border-stroke file:bg-stroke file:px-2.5 file:py-1 file:text-body-xs file:font-medium file:text-dark-5 file:focus:border-primary dark:file:border-dark-3 dark:file:bg-white/30 dark:file:text-white px-3 py-[9px]`;
}
}
@@ -0,0 +1,89 @@
import { cn } from "@/lib/utils";
import { useId } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegister,
type UseFormRegisterReturn,
} from "react-hook-form";
type PropsType<T extends FieldValues> = {
name: Path<T>;
label: string;
placeholder: string;
required?: boolean;
disabled?: boolean;
active?: boolean;
className?: string;
icon?: React.ReactNode;
defaultValue?: string;
handleChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
} & Partial<UseFormRegisterReturn>;
export function TextAreaGroup<T extends FieldValues>({
name,
label,
placeholder,
required,
disabled,
active,
className,
icon,
defaultValue,
handleChange,
register,
errors,
onChange,
onBlur,
ref,
...props
}: PropsType<T>) {
const id = useId();
const error = errors && errors[name];
return (
<div className={cn(className)}>
<label
htmlFor={id}
className="mb-3 block text-body-sm font-medium text-dark dark:text-white"
>
{label}
{required && <span className="text-red ml-1 select-none">*</span>}
</label>
<div className="relative mt-3 [&_svg]:pointer-events-none [&_svg]:absolute [&_svg]:left-5.5 [&_svg]:top-5.5">
<textarea
id={id}
name={name}
ref={ref}
rows={6}
placeholder={placeholder}
defaultValue={defaultValue}
onChange={(e) => {
onChange?.(e);
handleChange?.(e);
}}
onBlur={onBlur}
className={cn(
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5.5 py-3 text-dark outline-none transition focus:border-primary disabled:cursor-default disabled:bg-gray-2 data-[active=true]:border-primary dark:border-dark-3 dark:bg-dark-2 dark:text-white dark:focus:border-primary dark:disabled:bg-dark dark:data-[active=true]:border-primary",
error && "border-red focus:border-red dark:border-red",
icon && "py-5 pl-13 pr-5",
)}
required={required}
disabled={disabled}
data-active={active}
/>
{icon}
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
}
+241
View File
@@ -0,0 +1,241 @@
"use client";
import React, { useEffect, useRef, useState, useId } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegisterReturn,
} from "react-hook-form";
interface Option {
value: string;
text: string;
selected: boolean;
}
type MultiSelectProps<T extends FieldValues> = {
label: string;
items: { value: string; text: string }[];
errors?: FieldErrors<T>;
required?: boolean;
placeholder?: string;
className?: string;
} & UseFormRegisterReturn<Path<T>>;
function MultiSelect<T extends FieldValues>({
name,
label,
items,
errors,
required,
placeholder = "Select an option",
className,
onChange,
onBlur,
ref,
}: MultiSelectProps<T>) {
const id = useId();
const error = errors && errors[name];
const [options, setOptions] = useState<Option[]>([]);
const [selected, setSelected] = useState<number[]>([]);
const [show, setShow] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const trigger = useRef<HTMLDivElement | null>(null);
useEffect(() => {
setOptions(
items.map((item) => ({
...item,
selected: false,
})),
);
}, [items]);
const open = () => {
setShow(true);
};
const isOpen = () => {
return show === true;
};
const combinedRef = (el: HTMLDivElement) => {
trigger.current = el;
if (typeof ref === "function") {
ref(el);
}
};
const handleSelect = (index: number) => {
const newOptions = [...options];
let newSelected = [...selected];
if (!newOptions[index].selected) {
newOptions[index].selected = true;
newSelected.push(index);
} else {
newOptions[index].selected = false;
newSelected = newSelected.filter((i) => i !== index);
}
setOptions(newOptions);
setSelected(newSelected);
const selectedValues = newSelected.map((i) => options[i].value);
onChange?.({ target: { name, value: selectedValues } });
};
const remove = (index: number, event: React.MouseEvent) => {
event.stopPropagation();
const newOptions = [...options];
const newSelected = selected.filter((i) => i !== index);
newOptions[index].selected = false;
setOptions(newOptions);
setSelected(newSelected);
const selectedValues = newSelected.map((i) => options[i].value);
onChange?.({ target: { name, value: selectedValues } });
};
useEffect(() => {
const clickHandler = ({ target }: MouseEvent) => {
if (!dropdownRef.current) return;
if (
!show ||
dropdownRef.current.contains(target as Node) ||
trigger.current?.contains(target as Node)
)
return;
setShow(false);
};
document.addEventListener("click", clickHandler);
return () => document.removeEventListener("click", clickHandler);
}, [show]);
return (
<div className={`relative z-50 ${className}`}>
<label
htmlFor={id}
className="mb-3 block text-body-sm font-medium text-dark dark:text-white"
>
{label}
</label>
<div className="relative">
<div
ref={combinedRef}
onClick={open}
onBlur={onBlur}
tabIndex={0}
className={`flex min-h-[46px] w-full cursor-pointer items-center rounded-[7px] border-[1.5px] bg-transparent py-2 pl-3 pr-3 outline-none transition focus:border-primary active:border-primary dark:bg-dark-2 ${
error
? "border-red focus:border-red dark:border-red"
: "border-stroke dark:border-dark-3"
}`}
>
<div className="flex flex-auto flex-wrap gap-2">
{selected.map((index) => (
<div
key={index}
className="flex items-center justify-center rounded-[5px] border-[.5px] border-stroke bg-gray-2 px-2.5 py-1 text-body-sm font-medium dark:border-dark-3 dark:bg-dark"
>
<div className="max-w-full flex-initial">
{options[index]?.text}
</div>
<div className="flex flex-auto flex-row-reverse">
<div
onClick={(e) => remove(index, e)}
className="hover:text-red cursor-pointer pl-2"
>
<svg
className="fill-current"
role="button"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.35355 3.35355C9.54882 3.15829 9.54882 2.84171 9.35355 2.64645C9.15829 2.45118 8.84171 2.45118 8.64645 2.64645L6 5.29289L3.35355 2.64645C3.15829 2.45118 2.84171 2.45118 2.64645 2.64645C2.45118 2.84171 2.45118 3.15829 2.64645 3.35355L5.29289 6L2.64645 8.64645C2.45118 8.84171 2.45118 9.15829 2.64645 9.35355C2.84171 9.54882 3.15829 9.54882 3.35355 9.35355L6 6.70711L8.64645 9.35355C8.84171 9.54882 9.15829 9.54882 9.35355 9.35355C9.54882 9.15829 9.54882 8.84171 9.35355 8.64645L6.70711 6L9.35355 3.35355Z"
fill="currentColor"
/>
</svg>
</div>
</div>
</div>
))}
{selected.length === 0 && (
<div className="flex-1">
<span className="h-full w-full bg-transparent p-1 px-2 text-dark-5 outline-none dark:text-dark-6">
{placeholder}
</span>
</div>
)}
</div>
<div className="flex items-center py-1 pl-1 pr-1">
<button
type="button"
className="cursor-pointer text-dark-4 outline-none focus:outline-none dark:text-dark-6"
>
<svg
className={`fill-current transition-transform duration-200 ${
isOpen() ? "rotate-180" : ""
}`}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.69149 7.09327C3.91613 6.83119 4.31069 6.80084 4.57277 7.02548L9.99936 11.6768L15.4259 7.02548C15.688 6.80084 16.0826 6.83119 16.3072 7.09327C16.5319 7.35535 16.5015 7.74991 16.2394 7.97455L10.4061 12.9745C10.172 13.1752 9.82667 13.1752 9.59261 12.9745L3.75928 7.97455C3.4972 7.74991 3.46685 7.35535 3.69149 7.09327Z"
fill="currentColor"
/>
</svg>
</button>
</div>
</div>
<div
className={`max-h-select absolute left-0 top-full z-40 w-full overflow-y-auto rounded bg-white shadow-1 dark:bg-dark-2 dark:shadow-card ${
isOpen() ? "" : "hidden"
}`}
ref={dropdownRef}
>
<div className="flex w-full flex-col">
{options.map((option, index) => (
<div key={index}>
<div
className="w-full cursor-pointer rounded-t border-b border-stroke hover:bg-primary/5 dark:border-dark-3"
onClick={() => handleSelect(index)}
>
<div
className={`relative flex w-full items-center border-l-2 p-2 pl-2 ${
option.selected ? "border-primary" : "border-transparent"
}`}
>
<div className="flex w-full items-center">
<div className="mx-2 leading-6">{option.text}</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
}
export default MultiSelect;
@@ -0,0 +1,33 @@
import { useState } from "react";
const SwitcherFour = () => {
const [enabled, setEnabled] = useState<boolean>(false);
return (
<div>
<label
htmlFor="toggle4"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
type="checkbox"
id="toggle4"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="block h-8 w-14 rounded-full bg-[#212B36] dark:bg-primary"></div>
<div
className={`absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white transition ${
enabled && "!right-1 !translate-x-full"
}`}
></div>
</div>
</label>
</div>
);
};
export default SwitcherFour;
@@ -0,0 +1,33 @@
import { useState } from "react";
const SwitcherOne = () => {
const [enabled, setEnabled] = useState<boolean>(false);
return (
<div>
<label
htmlFor="toggle1"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
type="checkbox"
id="toggle1"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="block h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]"></div>
<div
className={`absolute left-1 top-1 h-6 w-6 rounded-full bg-white shadow-switch-1 transition ${
enabled && "!right-1 !translate-x-full !bg-primary dark:!bg-white"
}`}
></div>
</div>
</label>
</div>
);
};
export default SwitcherOne;
@@ -0,0 +1,75 @@
import { useState } from "react";
const SwitcherThree = () => {
const [enabled, setEnabled] = useState(false);
return (
<div>
<label
htmlFor="toggle3"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
type="checkbox"
id="toggle3"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="block h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]"></div>
<div
className={`dot absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white shadow-switch-1 transition ${
enabled && "!right-1 !translate-x-full !bg-primary dark:!bg-white"
}`}
>
<span className={`hidden ${enabled && "!block"}`}>
<svg
className="fill-white dark:fill-dark"
width="11"
height="8"
viewBox="0 0 11 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.2355 0.812752L10.2452 0.824547C10.4585 1.08224 10.4617 1.48728 10.1855 1.74621L4.85633 7.09869C4.66442 7.29617 4.41535 7.4001 4.14693 7.4001C3.89823 7.4001 3.63296 7.29979 3.43735 7.09851L0.788615 4.43129C0.536589 4.1703 0.536617 3.758 0.788643 3.49701C1.04747 3.22897 1.4675 3.22816 1.72731 3.49457L4.16182 5.94608L9.28643 0.799032C9.54626 0.532887 9.96609 0.533789 10.2248 0.801737L10.2355 0.812752Z"
fill=""
/>
</svg>
</span>
<span className={`${enabled && "hidden"}`}>
<svg
className="fill-current"
width="11"
height="11"
viewBox="0 0 11 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_803_2686)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.23529 2.29669C0.942402 2.00379 0.942402 1.52892 1.23529 1.23603C1.52819 0.943134 2.00306 0.943134 2.29596 1.23603L5.37433 4.3144L8.45261 1.23612C8.7455 0.943225 9.22038 0.943225 9.51327 1.23612C9.80616 1.52901 9.80616 2.00389 9.51327 2.29678L6.43499 5.37506L9.51327 8.45334C9.80616 8.74624 9.80616 9.22111 9.51327 9.514C9.22038 9.8069 8.7455 9.8069 8.45261 9.514L5.37433 6.43572L2.29596 9.51409C2.00306 9.80699 1.52819 9.80699 1.23529 9.51409C0.942402 9.2212 0.942402 8.74633 1.23529 8.45343L4.31367 5.37506L1.23529 2.29669Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_803_2686">
<rect width="10.75" height="10.75" fill="white" />
</clipPath>
</defs>
</svg>
</span>
</div>
</div>
</label>
</div>
);
};
export default SwitcherThree;
@@ -0,0 +1,33 @@
import { useState } from "react";
const SwitcherTwo = () => {
const [enabled, setEnabled] = useState(false);
return (
<div>
<label
htmlFor="toggle2"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
id="toggle2"
type="checkbox"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="h-5 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]"></div>
<div
className={`dot shadow-switch-2 absolute -top-1 left-0 h-7 w-7 rounded-full bg-white transition ${
enabled && "!right-0 !translate-x-full !bg-primary dark:!bg-white"
}`}
></div>
</div>
</label>
</div>
);
};
export default SwitcherTwo;
+69
View File
@@ -0,0 +1,69 @@
import { CheckIcon, XIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { useId } from "react";
type PropsType = {
withIcon?: "check" | "x";
withBg?: boolean;
label: string;
name?: string;
minimal?: boolean;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
radius?: "default" | "md";
};
export function Checkbox({
withIcon,
label,
name,
withBg,
minimal,
onChange,
radius,
}: PropsType) {
const id = useId();
return (
<div>
<label
htmlFor={id}
className={cn(
"flex cursor-pointer select-none items-center",
!minimal && "text-body-sm font-medium",
)}
>
<div className="relative">
<input
type="checkbox"
onChange={onChange}
name={name}
id={id}
className="peer sr-only"
/>
<div
className={cn(
"mr-2 flex size-5 items-center justify-center rounded border border-dark-5 peer-checked:border-primary dark:border-dark-6 peer-checked:[&>*]:block",
withBg
? "peer-checked:bg-primary [&>*]:text-white"
: "peer-checked:bg-gray-2 dark:peer-checked:bg-transparent",
minimal && "mr-3 border-stroke dark:border-dark-3",
radius === "md" && "rounded-md",
)}
>
{!withIcon && (
<span className="hidden size-2.5 rounded-sm bg-primary" />
)}
{withIcon === "check" && (
<CheckIcon className="hidden text-primary" />
)}
{withIcon === "x" && <XIcon className="hidden text-primary" />}
</div>
</div>
<span>{label}</span>
</label>
</div>
);
}
+58
View File
@@ -0,0 +1,58 @@
import { cn } from "@/lib/utils";
import { useId } from "react";
type PropsType = {
variant?: "dot" | "circle";
label: string;
name?: string;
value?: string;
minimal?: boolean;
};
export function RadioInput({
label,
variant = "dot",
name,
value,
minimal,
}: PropsType) {
const id = useId();
return (
<div>
<label
htmlFor={id}
className="flex cursor-pointer select-none items-center text-body-sm font-medium text-dark dark:text-white"
>
<div className="relative">
<input
type="radio"
name={name}
id={id}
className="peer sr-only"
value={value}
/>
<div
className={cn(
"mr-2 flex size-5 items-center justify-center rounded-full border peer-checked:[&>*]:block",
{
"border-primary peer-checked:border-6": variant === "circle",
"border-dark-5 peer-checked:border-primary peer-checked:bg-gray-2 dark:border-dark-6 dark:peer-checked:bg-dark-2":
variant === "dot",
},
minimal && "border-stroke dark:border-dark-3",
)}
>
<span
className={cn(
"hidden size-2.5 rounded-full bg-primary",
variant === "circle" && "bg-transparent",
)}
/>
</div>
</div>
<span>{label}</span>
</label>
</div>
);
}
+105
View File
@@ -0,0 +1,105 @@
"use client";
import { ChevronUpIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { useId, useState } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegister,
type UseFormRegisterReturn,
} from "react-hook-form";
type PropsType<T extends FieldValues> = {
name: Path<T>;
label: string;
items: { value: string; label: string }[];
prefixIcon?: React.ReactNode;
className?: string;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
required?: boolean;
} & (
| { placeholder?: string; defaultValue: string }
| { placeholder: string; defaultValue?: string }
) &
Partial<UseFormRegisterReturn>;
export function Select<T extends FieldValues>({
items,
label,
defaultValue,
placeholder,
prefixIcon,
className,
name,
register,
errors,
required,
onChange,
onBlur,
ref,
...props
}: PropsType<T>) {
const id = useId();
const [isOptionSelected, setIsOptionSelected] = useState(!!defaultValue);
const error = errors && errors[name];
return (
<div className={cn("space-y-3", className)}>
<label
htmlFor={id}
className="block text-body-sm font-medium text-dark dark:text-white"
>
{label}
{required && <span className="text-red ml-1 select-none">*</span>}
</label>
<div className="relative">
{prefixIcon && (
<div className="absolute left-4 top-1/2 -translate-y-1/2">
{prefixIcon}
</div>
)}
<select
id={id}
name={name}
ref={ref}
defaultValue={defaultValue || ""}
onChange={(e) => {
setIsOptionSelected(!!e.target.value);
onChange?.(e);
}}
onBlur={onBlur}
className={cn(
"w-full appearance-none rounded-lg border border-stroke bg-transparent px-5.5 py-3 outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary [&>option]:text-dark-5 dark:[&>option]:text-dark-6",
isOptionSelected && "text-dark dark:text-white",
error && "border-red focus:border-red dark:border-red",
prefixIcon && "pl-11.5",
)}
>
{placeholder && (
<option value="" disabled hidden>
{placeholder}
</option>
)}
{items.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</select>
<ChevronUpIcon className="pointer-events-none absolute right-4 top-1/2 -translate-y-1/2 rotate-180" />
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
}
+54
View File
@@ -0,0 +1,54 @@
import { CheckIcon, XIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { useId } from "react";
type PropsType = {
withIcon?: boolean;
background?: "dark" | "light";
backgroundSize?: "sm" | "default";
name?: string;
};
export function Switch({
background,
withIcon,
backgroundSize,
name,
}: PropsType) {
const id = useId();
return (
<label
htmlFor={id}
className="flex max-w-fit cursor-pointer select-none items-center"
>
<div className="relative">
<input type="checkbox" name={name} id={id} className="peer sr-only" />
<div
className={cn("h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]", {
"h-5": backgroundSize === "sm",
"bg-[#212B36] dark:bg-primary": background === "dark",
})}
/>
<div
className={cn(
"absolute left-1 top-1 flex size-6 items-center justify-center rounded-full bg-white shadow-switch-1 transition peer-checked:right-1 peer-checked:translate-x-full peer-checked:[&_.check-icon]:block peer-checked:[&_.x-icon]:hidden",
{
"-top-1 left-0 size-7 shadow-switch-2": backgroundSize === "sm",
"peer-checked:bg-primary peer-checked:dark:bg-white":
background !== "dark",
},
)}
>
{withIcon && (
<>
<CheckIcon className="check-icon hidden fill-white dark:fill-dark" />
<XIcon className="x-icon" />
</>
)}
</div>
</div>
</label>
);
}
@@ -0,0 +1,34 @@
"use client";
import { usePathname } from "next/navigation";
import type { PropsWithChildren } from "react";
import { Header } from "./header";
import { Sidebar } from "./sidebar";
import { AuthGuard, LoginGuard } from "@/contexts";
export function ConditionalLayout({ children }: PropsWithChildren) {
const pathname = usePathname();
const isAuthPage = pathname.startsWith("/auth");
return (
<>
{isAuthPage ? (
<LoginGuard>
<main>{children}</main>
</LoginGuard>
) : (
<AuthGuard>
<div className="flex min-h-screen">
<Sidebar />
<div className="w-full bg-gray-2 dark:bg-[#020d1a]">
<Header />
<main className="isolate mx-auto w-full max-w-screen-2xl overflow-hidden p-4 md:p-6 2xl:p-10">
{children}
</main>
</div>
</div>
</AuthGuard>
)}
</>
);
}
+17
View File
@@ -0,0 +1,17 @@
import type { IconProps } from "@/types/icon-props";
export function MenuIcon(props: IconProps) {
return (
<svg
width="25"
height="24"
viewBox="0 0 25 24"
fill="currentColor"
{...props}
>
<path d="M3.5625 6C3.5625 5.58579 3.89829 5.25 4.3125 5.25H20.3125C20.7267 5.25 21.0625 5.58579 21.0625 6C21.0625 6.41421 20.7267 6.75 20.3125 6.75L4.3125 6.75C3.89829 6.75 3.5625 6.41422 3.5625 6Z" />
<path d="M3.5625 18C3.5625 17.5858 3.89829 17.25 4.3125 17.25L20.3125 17.25C20.7267 17.25 21.0625 17.5858 21.0625 18C21.0625 18.4142 20.7267 18.75 20.3125 18.75L4.3125 18.75C3.89829 18.75 3.5625 18.4142 3.5625 18Z" />
<path d="M4.3125 11.25C3.89829 11.25 3.5625 11.5858 3.5625 12C3.5625 12.4142 3.89829 12.75 4.3125 12.75L20.3125 12.75C20.7267 12.75 21.0625 12.4142 21.0625 12C21.0625 11.5858 20.7267 11.25 20.3125 11.25L4.3125 11.25Z" />
</svg>
);
}
+54
View File
@@ -0,0 +1,54 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { useSidebarContext } from "../sidebar/sidebar-context";
import { MenuIcon } from "./icons";
import { Notification } from "./notification";
import { ThemeToggleSwitch } from "./theme-toggle";
import { UserInfo } from "./user-info";
export function Header() {
const { toggleSidebar, isMobile } = useSidebarContext();
return (
<header className="sticky top-0 z-30 flex items-center justify-between border-b border-stroke bg-white px-4 py-5 shadow-1 dark:border-stroke-dark dark:bg-gray-dark md:px-5 2xl:px-10">
<button
onClick={toggleSidebar}
className="rounded-lg border px-1.5 py-1 dark:border-stroke-dark dark:bg-[#020D1A] hover:dark:bg-[#FFFFFF1A] lg:hidden"
>
<MenuIcon />
<span className="sr-only">Toggle Sidebar</span>
</button>
{isMobile && (
<Link href={"/"} className="ml-2 max-[430px]:hidden min-[375px]:ml-4">
<Image
src={"/images/logo/logo-icon.svg"}
width={32}
height={32}
alt=""
role="presentation"
/>
</Link>
)}
<div className="max-xl:hidden">
<h1 className="mb-0.5 text-heading-5 font-bold text-dark dark:text-white">
Opportunity Lens
</h1>
<p className="font-medium">Opportunity Lens management panel</p>
</div>
<div className="flex flex-1 items-center justify-end gap-2 min-[375px]:gap-4">
<ThemeToggleSwitch />
<Notification />
<div className="shrink-0">
<UserInfo />
</div>
</div>
</header>
);
}
@@ -0,0 +1,14 @@
import { SVGProps } from "react";
export function BellIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg width={20} height={20} viewBox="0 0 20 20" fill="none" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10 1.042A6.458 6.458 0 003.542 7.5v.587c0 .58-.172 1.148-.495 1.631l-.957 1.436a2.934 2.934 0 001.67 4.459c.63.171 1.264.316 1.903.435l.002.005c.64 1.71 2.353 2.905 4.335 2.905 1.982 0 3.694-1.196 4.335-2.905l.002-.005a23.736 23.736 0 001.903-.435 2.934 2.934 0 001.67-4.459l-.958-1.436a2.941 2.941 0 01-.494-1.631V7.5A6.458 6.458 0 0010 1.042zm2.813 15.239a23.71 23.71 0 01-5.627 0c.593.85 1.623 1.427 2.814 1.427 1.19 0 2.221-.576 2.813-1.427zM4.792 7.5a5.208 5.208 0 1110.416 0v.587c0 .827.245 1.636.704 2.325l.957 1.435c.638.957.151 2.257-.958 2.56a22.467 22.467 0 01-11.822 0 1.684 1.684 0 01-.959-2.56l.958-1.435a4.192 4.192 0 00.704-2.325V7.5z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,129 @@
"use client";
import {
Dropdown,
DropdownContent,
DropdownTrigger,
} from "@/components/ui/dropdown";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
import Image from "next/image";
import Link from "next/link";
import { useState } from "react";
import { BellIcon } from "./icons";
const notificationList = [
{
image: "/images/user/user-15.png",
title: "Piter Joined the Team!",
subTitle: "Congratulate him",
},
{
image: "/images/user/user-03.png",
title: "New message",
subTitle: "Devid sent a new message",
},
{
image: "/images/user/user-26.png",
title: "New Payment received",
subTitle: "Check your earnings",
},
{
image: "/images/user/user-28.png",
title: "Jolly completed tasks",
subTitle: "Assign new task",
},
{
image: "/images/user/user-27.png",
title: "Roman Joined the Team!",
subTitle: "Congratulate him",
},
];
export function Notification() {
const [isOpen, setIsOpen] = useState(false);
const [isDotVisible, setIsDotVisible] = useState(true);
const isMobile = useIsMobile();
return (
<Dropdown
isOpen={isOpen}
setIsOpen={(open) => {
setIsOpen(open);
if (setIsDotVisible) setIsDotVisible(false);
}}
>
<DropdownTrigger
className="grid size-12 place-items-center rounded-full border bg-gray-2 text-dark outline-none hover:text-primary focus-visible:border-primary focus-visible:text-primary dark:border-dark-4 dark:bg-dark-3 dark:text-white dark:focus-visible:border-primary"
aria-label="View Notifications"
>
<span className="relative">
<BellIcon />
{isDotVisible && (
<span
className={cn(
"absolute right-0 top-0 z-1 size-2 rounded-full bg-red-light ring-2 ring-gray-2 dark:ring-dark-3",
)}
>
<span className="absolute inset-0 -z-1 animate-ping rounded-full bg-red-light opacity-75" />
</span>
)}
</span>
</DropdownTrigger>
<DropdownContent
align={isMobile ? "end" : "center"}
className="border border-stroke bg-white px-3.5 py-3 shadow-md dark:border-dark-3 dark:bg-gray-dark min-[350px]:min-w-[20rem]"
>
<div className="mb-1 flex items-center justify-between px-2 py-1.5">
<span className="text-lg font-medium text-dark dark:text-white">
Notifications
</span>
<span className="rounded-md bg-primary px-[9px] py-0.5 text-xs font-medium text-white">
5 new
</span>
</div>
<ul className="mb-3 max-h-[23rem] space-y-1.5 overflow-y-auto">
{notificationList.map((item, index) => (
<li key={index} role="menuitem">
<Link
href="#"
onClick={() => setIsOpen(false)}
className="flex items-center gap-4 rounded-lg px-2 py-1.5 outline-none hover:bg-gray-2 focus-visible:bg-gray-2 dark:hover:bg-dark-3 dark:focus-visible:bg-dark-3"
>
<Image
src={item.image}
className="size-14 rounded-full object-cover"
width={200}
height={200}
alt="User"
/>
<div>
<strong className="block text-sm font-medium text-dark dark:text-white">
{item.title}
</strong>
<span className="truncate text-sm font-medium text-dark-5 dark:text-dark-6">
{item.subTitle}
</span>
</div>
</Link>
</li>
))}
</ul>
<Link
href="#"
onClick={() => setIsOpen(false)}
className="block rounded-lg border border-primary p-2 text-center text-sm font-medium tracking-wide text-primary outline-none transition-colors hover:bg-blue-light-5 focus:bg-blue-light-5 focus:text-primary focus-visible:border-primary dark:border-dark-3 dark:text-dark-6 dark:hover:border-dark-5 dark:hover:bg-dark-3 dark:hover:text-dark-7 dark:focus-visible:border-dark-5 dark:focus-visible:bg-dark-3 dark:focus-visible:text-dark-7"
>
See all notifications
</Link>
</DropdownContent>
</Dropdown>
);
}
@@ -0,0 +1,33 @@
import type { SVGProps } from "react";
export function Sun(props: SVGProps<SVGSVGElement>) {
return (
<svg
width={20}
height={20}
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path d="M10 1.042c.345 0 .625.28.625.625V2.5a.625.625 0 11-1.25 0v-.833c0-.346.28-.625.625-.625zM3.666 3.665a.625.625 0 01.883 0l.328.328a.625.625 0 01-.884.884l-.327-.328a.625.625 0 010-.884zm12.668 0a.625.625 0 010 .884l-.327.328a.625.625 0 01-.884-.884l.327-.327a.625.625 0 01.884 0zM10 5.626a4.375 4.375 0 100 8.75 4.375 4.375 0 000-8.75zM4.375 10a5.625 5.625 0 1111.25 0 5.625 5.625 0 01-11.25 0zm-3.333 0c0-.345.28-.625.625-.625H2.5a.625.625 0 110 1.25h-.833A.625.625 0 011.042 10zm15.833 0c0-.345.28-.625.625-.625h.833a.625.625 0 010 1.25H17.5a.625.625 0 01-.625-.625zm-1.752 5.123a.625.625 0 01.884 0l.327.327a.625.625 0 11-.884.884l-.327-.327a.625.625 0 010-.884zm-10.246 0a.625.625 0 010 .884l-.328.327a.625.625 0 11-.883-.884l.327-.327a.625.625 0 01.884 0zM10 16.875c.345 0 .625.28.625.625v.833a.625.625 0 01-1.25 0V17.5c0-.345.28-.625.625-.625z" />
</svg>
);
}
export function Moon(props: SVGProps<SVGSVGElement>) {
return (
<svg
width={20}
height={20}
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.18 2.334a7.71 7.71 0 108.485 8.485A6.042 6.042 0 119.18 2.335zM1.042 10a8.958 8.958 0 018.958-8.958c.598 0 .896.476.948.855.049.364-.086.828-.505 1.082a4.792 4.792 0 106.579 6.579c.253-.42.717-.555 1.081-.506.38.052.856.35.856.948A8.958 8.958 0 011.04 10z"
/>
</svg>
);
}
@@ -0,0 +1,56 @@
import { cn } from "@/lib/utils";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { Moon, Sun } from "./icons";
const THEMES = [
{
name: "light",
Icon: Sun,
},
{
name: "dark",
Icon: Moon,
},
];
export function ThemeToggleSwitch() {
const { setTheme, theme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
return (
<button
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
className="group rounded-full bg-gray-3 p-[5px] text-[#111928] outline-1 outline-primary focus-visible:outline dark:bg-[#020D1A] dark:text-current"
>
<span className="sr-only">
Switch to {theme === "light" ? "dark" : "light"} mode
</span>
<span aria-hidden className="relative flex gap-2.5">
{/* Indicator */}
<span className="absolute size-[38px] rounded-full border border-gray-200 bg-white transition-all dark:translate-x-[48px] dark:border-none dark:bg-dark-2 dark:group-hover:bg-dark-3" />
{THEMES.map(({ name, Icon }) => (
<span
key={name}
className={cn(
"relative grid size-[38px] place-items-center rounded-full",
name === "dark" && "dark:text-white",
)}
>
<Icon />
</span>
))}
</span>
</button>
);
}
@@ -0,0 +1,66 @@
import type { SVGProps } from "react";
type SVGPropsType = SVGProps<SVGSVGElement>;
export function UserIcon(props: SVGPropsType) {
return (
<svg
width={20}
height={20}
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 .938a3.562 3.562 0 100 7.124A3.562 3.562 0 009 .938zM6.562 4.5a2.437 2.437 0 114.875 0 2.437 2.437 0 01-4.875 0zM9 9.188c-1.735 0-3.334.394-4.518 1.06-1.167.657-2.045 1.652-2.045 2.877v.076c0 .872-.001 1.965.958 2.747.472.384 1.132.657 2.025.838.894.181 2.06.276 3.58.276s2.685-.095 3.58-.276c.893-.18 1.553-.454 2.025-.838.96-.782.958-1.875.957-2.747v-.076c0-1.226-.877-2.22-2.044-2.877-1.184-.666-2.783-1.06-4.518-1.06zm-5.438 3.937c0-.639.467-1.331 1.471-1.896.987-.555 2.388-.916 3.967-.916 1.579 0 2.98.36 3.967.916 1.004.565 1.47 1.258 1.47 1.896 0 .98-.03 1.533-.542 1.95-.278.227-.743.448-1.538.609-.793.16-1.876.254-3.357.254-1.48 0-2.564-.094-3.357-.255-.795-.16-1.26-.381-1.538-.608-.512-.417-.543-.97-.543-1.95z"
/>
</svg>
);
}
export function SettingsIcon(props: SVGPropsType) {
return (
<svg
width={20}
height={20}
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 6.188a2.813 2.813 0 100 5.625 2.813 2.813 0 000-5.626zM7.312 9a1.688 1.688 0 113.376 0 1.688 1.688 0 01-3.376 0z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.981.938c-.333 0-.612 0-.84.015a2.117 2.117 0 00-.68.142c-.506.209-.907.61-1.117 1.116-.108.263-.138.54-.15.841a.65.65 0 01-.311.55.65.65 0 01-.631-.005c-.267-.141-.522-.254-.804-.291a2.063 2.063 0 00-1.525.408c-.187.144-.33.32-.462.519-.128.19-.267.43-.434.72l-.019.032c-.166.289-.306.53-.406.735a2.117 2.117 0 00-.218.66c-.071.543.076 1.091.409 1.525.173.226.398.39.654.55A.65.65 0 012.766 9a.65.65 0 01-.32.544c-.255.16-.48.325-.653.55-.333.435-.48.983-.409 1.526.03.233.113.445.218.66.1.205.24.446.406.735l.02.033c.166.288.305.53.433.72.133.197.275.374.462.518.434.333.983.48 1.525.408.282-.037.537-.15.804-.29a.65.65 0 01.63-.005.65.65 0 01.313.549c.011.3.04.578.15.841.209.506.61.907 1.116 1.117.217.09.442.125.68.14.228.017.507.017.84.017h.038c.333 0 .612 0 .84-.016.238-.016.463-.051.68-.142.506-.209.907-.61 1.117-1.116.108-.263.138-.54.15-.841a.65.65 0 01.311-.55.65.65 0 01.631.005c.267.141.522.254.804.291a2.062 2.062 0 001.525-.408c.187-.144.33-.32.462-.519.128-.19.267-.43.434-.72l.019-.032c.166-.289.305-.53.406-.736.105-.214.187-.426.218-.66a2.062 2.062 0 00-.409-1.524c-.173-.226-.398-.39-.654-.55A.65.65 0 0115.234 9a.65.65 0 01.32-.544c.255-.16.48-.325.653-.55.333-.435.48-.983.409-1.526a2.117 2.117 0 00-.218-.66c-.1-.205-.24-.446-.406-.735l-.02-.033c-.166-.288-.305-.53-.433-.72a2.117 2.117 0 00-.462-.518 2.062 2.062 0 00-1.525-.408c-.282.037-.537.15-.804.29a.65.65 0 01-.63.005.65.65 0 01-.313-.549c-.011-.3-.04-.578-.15-.841a2.063 2.063 0 00-1.116-1.116 2.118 2.118 0 00-.68-.142c-.228-.016-.507-.016-.84-.015H8.98zm-1.09 1.196c.058-.024.146-.046.327-.059.185-.012.425-.013.782-.013.357 0 .597 0 .782.013.181.013.269.035.327.059.23.095.412.278.507.507.03.073.055.186.065.453.022.595.329 1.167.874 1.481a1.775 1.775 0 001.719.016c.237-.125.347-.16.425-.17a.938.938 0 01.693.186c.05.038.113.103.214.253.103.155.223.362.402.671.179.31.298.517.38.684.08.163.104.25.113.312a.937.937 0 01-.186.693c-.048.062-.133.14-.36.283A1.775 1.775 0 0014.109 9c0 .629.342 1.18.846 1.497.227.143.312.22.36.283a.938.938 0 01.186.693c-.009.062-.033.15-.113.312-.082.167-.201.374-.38.684-.179.309-.299.516-.402.67-.101.151-.165.216-.214.254a.937.937 0 01-.693.186c-.078-.01-.188-.045-.425-.17a1.775 1.775 0 00-1.72.016 1.775 1.775 0 00-.873 1.48c-.01.268-.035.381-.065.454a.937.937 0 01-.507.507 1.034 1.034 0 01-.327.059c-.185.012-.425.012-.782.012-.357 0-.597 0-.782-.012a1.033 1.033 0 01-.327-.059.937.937 0 01-.507-.507c-.03-.073-.055-.186-.065-.454a1.775 1.775 0 00-.874-1.48 1.775 1.775 0 00-1.719-.016c-.237.125-.347.16-.425.17a.937.937 0 01-.693-.186 1.034 1.034 0 01-.214-.253 12.818 12.818 0 01-.402-.671c-.179-.31-.298-.517-.38-.684a1.035 1.035 0 01-.113-.312.937.937 0 01.186-.693c.048-.063.133-.14.36-.283.504-.316.846-.868.846-1.497 0-.629-.342-1.18-.846-1.497-.227-.143-.312-.22-.36-.283a.937.937 0 01-.186-.693c.009-.062.033-.15.113-.312.082-.167.201-.375.38-.684.179-.31.299-.517.402-.67.101-.151.165-.216.214-.254a.938.938 0 01.693-.186c.078.01.188.045.425.17a1.775 1.775 0 001.72-.016c.544-.314.85-.886.873-1.48.01-.268.035-.381.065-.454a.937.937 0 01.507-.507z"
/>
</svg>
);
}
export function LogOutIcon(props: SVGPropsType) {
return (
<svg
width={20}
height={20}
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_7095_11691)">
<path d="M11.209.938c-1.026 0-1.852 0-2.503.087-.675.09-1.243.285-1.695.736-.393.394-.592.878-.697 1.446-.101.553-.12 1.229-.125 2.04a.562.562 0 101.125.006c.005-.82.026-1.401.107-1.842.078-.426.203-.672.386-.854.207-.208.499-.343 1.05-.417.566-.076 1.317-.078 2.393-.078H12c1.077 0 1.828.002 2.394.078.55.074.842.21 1.05.417.207.207.342.499.416 1.05.077.566.078 1.316.078 2.393v6c0 1.077-.002 1.827-.078 2.394-.074.55-.209.842-.417 1.05-.207.207-.499.342-1.049.416-.566.076-1.317.078-2.394.078h-.75c-1.076 0-1.827-.002-2.394-.078-.55-.074-.842-.21-1.05-.417-.182-.182-.307-.428-.385-.854-.081-.44-.102-1.022-.107-1.842a.563.563 0 00-1.125.006c.004.811.024 1.487.125 2.04.105.568.304 1.052.697 1.446.452.451 1.02.645 1.695.736.65.087 1.477.087 2.503.087h.832c1.026 0 1.853 0 2.503-.087.675-.09 1.243-.285 1.695-.736.451-.452.645-1.02.736-1.695.088-.65.088-1.477.088-2.503V5.96c0-1.026 0-1.853-.088-2.503-.09-.675-.285-1.243-.736-1.695-.452-.451-1.02-.645-1.695-.736-.65-.088-1.477-.088-2.503-.087h-.832z" />
<path d="M11.25 8.438a.562.562 0 110 1.124H3.02l1.471 1.26a.563.563 0 01-.732.855l-2.625-2.25a.562.562 0 010-.854l2.625-2.25a.562.562 0 11.732.854l-1.47 1.26h8.229z" />
</g>
<defs>
<clipPath id="clip0_7095_11691">
<rect width={18} height={18} rx={5} />
</clipPath>
</defs>
</svg>
);
}
@@ -0,0 +1,119 @@
"use client";
import { ChevronUpIcon } from "@/assets/icons";
import {
Dropdown,
DropdownContent,
DropdownTrigger,
} from "@/components/ui/dropdown";
import { cn } from "@/lib/utils";
import Image from "next/image";
import Link from "next/link";
import { useState } from "react";
import { LogOutIcon, SettingsIcon, UserIcon } from "./icons";
export function UserInfo() {
const [isOpen, setIsOpen] = useState(false);
const USER = {
name: "John Smith",
email: "johnson@nextadmin.com",
img: "/images/user/user-03.png",
};
return (
<Dropdown isOpen={isOpen} setIsOpen={setIsOpen}>
<DropdownTrigger className="rounded align-middle outline-none ring-primary ring-offset-2 focus-visible:ring-1 dark:ring-offset-gray-dark">
<span className="sr-only">My Account</span>
<figure className="flex items-center gap-3">
<Image
src={USER.img}
className="size-12"
alt={`Avatar of ${USER.name}`}
role="presentation"
width={200}
height={200}
/>
<figcaption className="flex items-center gap-1 font-medium text-dark dark:text-dark-6 max-[1024px]:sr-only">
<span>{USER.name}</span>
<ChevronUpIcon
aria-hidden
className={cn(
"rotate-180 transition-transform",
isOpen && "rotate-0",
)}
strokeWidth={1.5}
/>
</figcaption>
</figure>
</DropdownTrigger>
<DropdownContent
className="border border-stroke bg-white shadow-md dark:border-dark-3 dark:bg-gray-dark min-[230px]:min-w-[17.5rem]"
align="end"
>
<h2 className="sr-only">User information</h2>
<figure className="flex items-center gap-2.5 px-5 py-3.5">
<Image
src={USER.img}
className="size-12"
alt={`Avatar for ${USER.name}`}
role="presentation"
width={200}
height={200}
/>
<figcaption className="space-y-1 text-base font-medium">
<div className="mb-2 leading-none text-dark dark:text-white">
{USER.name}
</div>
<div className="leading-none text-gray-6">{USER.email}</div>
</figcaption>
</figure>
<hr className="border-[#E8E8E8] dark:border-dark-3" />
<div className="p-2 text-base text-[#4B5563] dark:text-dark-6 [&>*]:cursor-pointer">
<Link
href={"/profile"}
onClick={() => setIsOpen(false)}
className="flex w-full items-center gap-2.5 rounded-lg px-2.5 py-[9px] hover:bg-gray-2 hover:text-dark dark:hover:bg-dark-3 dark:hover:text-white"
>
<UserIcon />
<span className="mr-auto text-base font-medium">View profile</span>
</Link>
<Link
href={"/pages/settings"}
onClick={() => setIsOpen(false)}
className="flex w-full items-center gap-2.5 rounded-lg px-2.5 py-[9px] hover:bg-gray-2 hover:text-dark dark:hover:bg-dark-3 dark:hover:text-white"
>
<SettingsIcon />
<span className="mr-auto text-base font-medium">
Account Settings
</span>
</Link>
</div>
<hr className="border-[#E8E8E8] dark:border-dark-3" />
<div className="p-2 text-base text-[#4B5563] dark:text-dark-6">
<button
className="flex w-full items-center gap-2.5 rounded-lg px-2.5 py-[9px] hover:bg-gray-2 hover:text-dark dark:hover:bg-dark-3 dark:hover:text-white"
onClick={() => setIsOpen(false)}
>
<LogOutIcon />
<span className="text-base font-medium">Log out</span>
</button>
</div>
</DropdownContent>
</Dropdown>
);
}
@@ -0,0 +1,20 @@
import { cn } from "@/lib/utils";
import type { ReactNode } from "react";
type PropsType = {
title: string;
children: ReactNode;
className?: string;
};
export function ShowcaseSection({ title, children, className }: PropsType) {
return (
<div className="rounded-[10px] bg-white shadow-1 dark:bg-gray-dark dark:shadow-card">
<h2 className="border-b border-stroke px-4 py-4 font-medium text-dark dark:border-dark-3 dark:text-white sm:px-6 xl:px-7.5">
{title}
</h2>
<div className={cn("p-4 sm:p-6 xl:p-10", className)}>{children}</div>
</div>
);
}
@@ -0,0 +1,159 @@
import { title } from "process";
import * as Icons from "../icons";
import { z } from "zod";
const navSubItemSchema: z.ZodType<any> = z.lazy(() =>
z.object({
title: z.string(),
url: z.string(),
icon: z.any(),
items: z.array(navSubItemSchema).default([]),
}),
);
const navItemSchema = z.object({
label: z.string(),
items: z.array(navSubItemSchema),
});
const navDataSchema = z.array(navItemSchema);
export type NavSubItem = z.infer<typeof navSubItemSchema>;
export type NavData = z.infer<typeof navDataSchema>;
export const NAV_DATA: NavData = [
{
label: "MAIN MENU",
items: [
{
title: "Dashboard",
url: "/",
icon: Icons.HomeIcon,
items: [],
},
{
title: "Admins",
url: "/admins",
icon: Icons.User,
items: [],
},
{
title: "companies",
url: "/companies",
icon: Icons.Building,
items: [],
},
{
title: "Customers",
url: "/customers",
icon: Icons.User,
items: [],
},
{
title: "Tenders",
url: "/tenders",
icon: Icons.Table,
items: [],
},
],
},
// {
// label: "MAIN MENU",
// items: [
// {
// title: "Dashboard",
// icon: Icons.HomeIcon,
// items: [
// {
// title: "eCommerce",
// url: "/",
// },
// ],
// },
// {
// title: "Calendar",
// url: "/calendar",
// icon: Icons.Calendar,
// items: [],
// },
// {
// title: "Profile",
// url: "/profile",
// icon: Icons.User,
// items: [],
// },
// {
// title: "Forms",
// icon: Icons.Alphabet,
// items: [
// {
// title: "Form Elements",
// url: "/forms/form-elements",
// },
// {
// title: "Form Layout",
// url: "/forms/form-layout",
// },
// ],
// },
// {
// title: "Tables",
// url: "/tables",
// icon: Icons.Table,
// items: [
// {
// title: "Tables",
// url: "/tables",
// },
// ],
// },
// {
// title: "Pages",
// icon: Icons.Alphabet,
// items: [
// {
// title: "Settings",
// url: "/pages/settings",
// },
// ],
// },
// ],
// },
// {
// label: "OTHERS",
// items: [
// {
// title: "Charts",
// icon: Icons.PieChart,
// items: [
// {
// title: "Basic Chart",
// url: "/charts/basic-chart",
// },
// ],
// },
// {
// title: "UI Elements",
// icon: Icons.FourCircle,
// items: [
// {
// title: "Alerts",
// url: "/ui-elements/alerts",
// },
// {
// title: "Buttons",
// url: "/ui-elements/buttons",
// },
// ],
// },
// {
// title: "Authentication",
// icon: Icons.Authentication,
// items: [
// {
// title: "Sign In",
// url: "/auth/sign-in",
// },
// ],
// },
// ],
// },
];
@@ -0,0 +1,7 @@
export const UI_ELEMENTS = ["Alerts", "Buttons"]
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
.map((value) => ({
title: value,
url: "/ui-elements/" + value.split(" ").join("-").toLowerCase(),
isPro: !["Alerts", "Buttons"].includes(value),
}));
+202
View File
@@ -0,0 +1,202 @@
import { SVGProps } from "react";
export type PropsType = SVGProps<SVGSVGElement>;
export function ChevronUp(props: PropsType) {
return (
<svg
width={16}
height={8}
viewBox="0 0 16 8"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.553.728a.687.687 0 01.895 0l6.416 5.5a.688.688 0 01-.895 1.044L8 2.155 2.03 7.272a.688.688 0 11-.894-1.044l6.417-5.5z"
/>
</svg>
);
}
export function Building(props: PropsType) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 -960 960 960"
fill="currentColor"
{...props}
>
<path d="M80-120v-720h400v160h400v560H80Zm80-80h240v-80H160v80Zm0-160h240v-80H160v80Zm0-160h240v-80H160v80Zm0-160h240v-80H160v80Zm320 480h320v-400H480v400Zm80-240v-80h160v80H560Zm0 160v-80h160v80H560Z" />
</svg>
);
}
export function HomeIcon(props: PropsType) {
return (
<svg
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
{...props}
>
<path d="M9 17.25a.75.75 0 000 1.5h6a.75.75 0 000-1.5H9z" />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 1.25c-.725 0-1.387.2-2.11.537-.702.327-1.512.81-2.528 1.415l-1.456.867c-1.119.667-2.01 1.198-2.686 1.706C2.523 6.3 2 6.84 1.66 7.551c-.342.711-.434 1.456-.405 2.325.029.841.176 1.864.36 3.146l.293 2.032c.237 1.65.426 2.959.707 3.978.29 1.05.702 1.885 1.445 2.524.742.64 1.63.925 2.716 1.062 1.056.132 2.387.132 4.066.132h2.316c1.68 0 3.01 0 4.066-.132 1.086-.137 1.974-.422 2.716-1.061.743-.64 1.155-1.474 1.445-2.525.281-1.02.47-2.328.707-3.978l.292-2.032c.185-1.282.332-2.305.36-3.146.03-.87-.062-1.614-.403-2.325C22 6.84 21.477 6.3 20.78 5.775c-.675-.508-1.567-1.039-2.686-1.706l-1.456-.867c-1.016-.605-1.826-1.088-2.527-1.415-.724-.338-1.386-.537-2.111-.537zM8.096 4.511c1.057-.63 1.803-1.073 2.428-1.365.609-.284 1.047-.396 1.476-.396.43 0 .867.112 1.476.396.625.292 1.37.735 2.428 1.365l1.385.825c1.165.694 1.986 1.184 2.59 1.638.587.443.91.809 1.11 1.225.199.416.282.894.257 1.626-.026.75-.16 1.691-.352 3.026l-.28 1.937c-.246 1.714-.422 2.928-.675 3.845-.247.896-.545 1.415-.977 1.787-.433.373-.994.593-1.925.71-.951.119-2.188.12-3.93.12h-2.213c-1.743 0-2.98-.001-3.931-.12-.93-.117-1.492-.337-1.925-.71-.432-.372-.73-.891-.977-1.787-.253-.917-.43-2.131-.676-3.845l-.279-1.937c-.192-1.335-.326-2.277-.352-3.026-.025-.732.058-1.21.258-1.626.2-.416.521-.782 1.11-1.225.603-.454 1.424-.944 2.589-1.638l1.385-.825z"
/>
</svg>
);
}
export function Calendar(props: PropsType) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
d="M17 14a1 1 0 100-2 1 1 0 000 2zM17 18a1 1 0 100-2 1 1 0 000 2zM13 13a1 1 0 11-2 0 1 1 0 012 0zM13 17a1 1 0 11-2 0 1 1 0 012 0zM7 14a1 1 0 100-2 1 1 0 000 2zM7 18a1 1 0 100-2 1 1 0 000 2z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7 1.75a.75.75 0 01.75.75v.763c.662-.013 1.391-.013 2.193-.013h4.113c.803 0 1.532 0 2.194.013V2.5a.75.75 0 011.5 0v.827c.26.02.506.045.739.076 1.172.158 2.121.49 2.87 1.238.748.749 1.08 1.698 1.238 2.87.153 1.14.153 2.595.153 4.433v2.112c0 1.838 0 3.294-.153 4.433-.158 1.172-.49 2.121-1.238 2.87-.749.748-1.698 1.08-2.87 1.238-1.14.153-2.595.153-4.433.153H9.944c-1.838 0-3.294 0-4.433-.153-1.172-.158-2.121-.49-2.87-1.238-.748-.749-1.08-1.698-1.238-2.87-.153-1.14-.153-2.595-.153-4.433v-2.112c0-1.838 0-3.294.153-4.433.158-1.172.49-2.121 1.238-2.87.749-.748 1.698-1.08 2.87-1.238.233-.031.48-.056.739-.076V2.5A.75.75 0 017 1.75zM5.71 4.89c-1.005.135-1.585.389-2.008.812-.423.423-.677 1.003-.812 2.009-.023.17-.042.35-.058.539h18.336c-.016-.19-.035-.369-.058-.54-.135-1.005-.389-1.585-.812-2.008-.423-.423-1.003-.677-2.009-.812-1.027-.138-2.382-.14-4.289-.14h-4c-1.907 0-3.261.002-4.29.14zM2.75 12c0-.854 0-1.597.013-2.25h18.474c.013.653.013 1.396.013 2.25v2c0 1.907-.002 3.262-.14 4.29-.135 1.005-.389 1.585-.812 2.008-.423.423-1.003.677-2.009.812-1.027.138-2.382.14-4.289.14h-4c-1.907 0-3.261-.002-4.29-.14-1.005-.135-1.585-.389-2.008-.812-.423-.423-.677-1.003-.812-2.009-.138-1.027-.14-2.382-.14-4.289v-2z"
fill="currentColor"
/>
</svg>
);
}
export function User(props: PropsType) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 1.25a4.75 4.75 0 100 9.5 4.75 4.75 0 000-9.5zM8.75 6a3.25 3.25 0 116.5 0 3.25 3.25 0 01-6.5 0zM12 12.25c-2.313 0-4.445.526-6.024 1.414C4.42 14.54 3.25 15.866 3.25 17.5v.102c-.001 1.162-.002 2.62 1.277 3.662.629.512 1.51.877 2.7 1.117 1.192.242 2.747.369 4.773.369s3.58-.127 4.774-.369c1.19-.24 2.07-.605 2.7-1.117 1.279-1.042 1.277-2.5 1.276-3.662V17.5c0-1.634-1.17-2.96-2.725-3.836-1.58-.888-3.711-1.414-6.025-1.414zM4.75 17.5c0-.851.622-1.775 1.961-2.528 1.316-.74 3.184-1.222 5.29-1.222 2.104 0 3.972.482 5.288 1.222 1.34.753 1.961 1.677 1.961 2.528 0 1.308-.04 2.044-.724 2.6-.37.302-.99.597-2.05.811-1.057.214-2.502.339-4.476.339-1.974 0-3.42-.125-4.476-.339-1.06-.214-1.68-.509-2.05-.81-.684-.557-.724-1.293-.724-2.601z"
fill="currentColor"
/>
</svg>
);
}
export function Alphabet(props: PropsType) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.25 7A.75.75 0 013 6.25h10a.75.75 0 010 1.5H3A.75.75 0 012.25 7zm14.25-.75a.75.75 0 01.684.442l4.5 10a.75.75 0 11-1.368.616l-1.437-3.194H14.12l-1.437 3.194a.75.75 0 11-1.368-.616l4.5-10a.75.75 0 01.684-.442zm-1.704 6.364h3.408L16.5 8.828l-1.704 3.786zM2.25 12a.75.75 0 01.75-.75h7a.75.75 0 010 1.5H3a.75.75 0 01-.75-.75zm0 5a.75.75 0 01.75-.75h5a.75.75 0 010 1.5H3a.75.75 0 01-.75-.75z"
fill="currentColor"
/>
</svg>
);
}
export function Table(props: PropsType) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18.29 4.89c-1.028-.138-2.383-.14-4.29-.14h-4c-1.907 0-3.261.002-4.29.14-1.005.135-1.585.389-2.008.812-.423.423-.677 1.003-.812 2.009-.138 1.028-.14 2.382-.14 4.289 0 1.907.002 3.261.14 4.29.135 1.005.389 1.585.812 2.008.423.423 1.003.677 2.009.812 1.028.138 2.382.14 4.289.14h4c1.907 0 3.262-.002 4.29-.14 1.005-.135 1.585-.389 2.008-.812.423-.423.677-1.003.812-2.009.138-1.028.14-2.382.14-4.289 0-1.907-.002-3.261-.14-4.29-.135-1.005-.389-1.585-.812-2.008-.423-.423-1.003-.677-2.009-.812zm.199-1.487c1.172.158 2.121.49 2.87 1.238.748.749 1.08 1.698 1.238 2.87.153 1.14.153 2.595.153 4.433v.112c0 1.838 0 3.294-.153 4.433-.158 1.172-.49 2.121-1.238 2.87-.749.748-1.698 1.08-2.87 1.238-1.14.153-2.595.153-4.433.153H9.944c-1.838 0-3.294 0-4.433-.153-1.172-.158-2.121-.49-2.87-1.238-.748-.749-1.08-1.698-1.238-2.87-.153-1.14-.153-2.595-.153-4.433v-.112c0-1.838 0-3.294.153-4.433.158-1.172.49-2.121 1.238-2.87.749-.748 1.698-1.08 2.87-1.238 1.14-.153 2.595-.153 4.433-.153h4.112c1.838 0 3.294 0 4.433.153zM8.25 17a.75.75 0 01.75-.75h6a.75.75 0 010 1.5H9a.75.75 0 01-.75-.75z"
/>
</svg>
);
}
export function PieChart(props: PropsType) {
return (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M14.254 1.365c-1.096-.306-2.122.024-2.851.695-.719.66-1.153 1.646-1.153 2.7v6.695a2.295 2.295 0 002.295 2.295h6.694c1.055 0 2.042-.434 2.701-1.153.67-.729 1.001-1.755.695-2.851a12.102 12.102 0 00-8.38-8.381zM11.75 4.76c0-.652.27-1.232.668-1.597.386-.355.886-.508 1.433-.355 3.55.991 6.349 3.79 7.34 7.34.153.548 0 1.048-.355 1.434-.365.397-.945.667-1.597.667h-6.694a.795.795 0 01-.795-.795V4.761z"
fill="currentColor"
/>
<path
d="M8.672 4.716a.75.75 0 00-.45-1.432C4.183 4.554 1.25 8.328 1.25 12.79c0 5.501 4.46 9.961 9.96 9.961 4.462 0 8.236-2.932 9.505-6.973a.75.75 0 10-1.43-.45 8.465 8.465 0 01-8.074 5.923 8.46 8.46 0 01-8.461-8.46 8.465 8.465 0 015.922-8.074z"
fill="currentColor"
/>
</svg>
);
}
export function FourCircle(props: PropsType) {
return (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.5 1.75a4.75 4.75 0 100 9.5 4.75 4.75 0 000-9.5zM3.25 6.5a3.25 3.25 0 116.5 0 3.25 3.25 0 01-6.5 0zM17.5 12.75a4.75 4.75 0 100 9.5 4.75 4.75 0 000-9.5zm-3.25 4.75a3.25 3.25 0 116.5 0 3.25 3.25 0 01-6.5 0zM12.75 6.5a4.75 4.75 0 119.5 0 4.75 4.75 0 01-9.5 0zm4.75-3.25a3.25 3.25 0 100 6.5 3.25 3.25 0 000-6.5zM6.5 12.75a4.75 4.75 0 100 9.5 4.75 4.75 0 000-9.5zM3.25 17.5a3.25 3.25 0 116.5 0 3.25 3.25 0 01-6.5 0z"
fill="currentColor"
/>
</svg>
);
}
export function Authentication(props: PropsType) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
{...props}
>
<path d="M14.945 1.25c-1.367 0-2.47 0-3.337.117-.9.12-1.658.38-2.26.981-.524.525-.79 1.17-.929 1.928-.135.737-.161 1.638-.167 2.72a.75.75 0 001.5.008c.006-1.093.034-1.868.142-2.457.105-.566.272-.895.515-1.138.277-.277.666-.457 1.4-.556.755-.101 1.756-.103 3.191-.103h1c1.436 0 2.437.002 3.192.103.734.099 1.122.28 1.4.556.276.277.456.665.555 1.4.102.754.103 1.756.103 3.191v8c0 1.435-.001 2.436-.103 3.192-.099.734-.279 1.122-.556 1.399-.277.277-.665.457-1.399.556-.755.101-1.756.103-3.192.103h-1c-1.435 0-2.436-.002-3.192-.103-.733-.099-1.122-.28-1.399-.556-.243-.244-.41-.572-.515-1.138-.108-.589-.136-1.364-.142-2.457a.75.75 0 10-1.5.008c.006 1.082.032 1.983.167 2.72.14.758.405 1.403.93 1.928.601.602 1.36.86 2.26.982.866.116 1.969.116 3.336.116h1.11c1.368 0 2.47 0 3.337-.116.9-.122 1.658-.38 2.26-.982.602-.602.86-1.36.982-2.26.116-.867.116-1.97.116-3.337v-8.11c0-1.367 0-2.47-.116-3.337-.121-.9-.38-1.658-.982-2.26-.602-.602-1.36-.86-2.26-.981-.867-.117-1.97-.117-3.337-.117h-1.11z" />
<path d="M2.001 11.249a.75.75 0 000 1.5h11.973l-1.961 1.68a.75.75 0 10.976 1.14l3.5-3a.75.75 0 000-1.14l-3.5-3a.75.75 0 00-.976 1.14l1.96 1.68H2.002z" />
</svg>
);
}
export function ArrowLeftIcon(props: PropsType) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.89775 4.10225C8.11742 4.32192 8.11742 4.67808 7.89775 4.89775L4.358 8.4375H15C15.3107 8.4375 15.5625 8.68934 15.5625 9C15.5625 9.31066 15.3107 9.5625 15 9.5625H4.358L7.89775 13.1023C8.11742 13.3219 8.11742 13.6781 7.89775 13.8977C7.67808 14.1174 7.32192 14.1174 7.10225 13.8977L2.60225 9.39775C2.38258 9.17808 2.38258 8.82192 2.60225 8.60225L7.10225 4.10225C7.32192 3.88258 7.67808 3.88258 7.89775 4.10225Z"
fill=""
/>
</svg>
);
}
+181
View File
@@ -0,0 +1,181 @@
"use client";
import { Logo } from "@/components/logo";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
import { NAV_DATA, NavSubItem } from "./data";
import { ArrowLeftIcon, ChevronUp } from "./icons";
import { MenuItem } from "./menu-item";
import { useSidebarContext } from "./sidebar-context";
import Image from "next/image";
export function Sidebar() {
const pathname = usePathname();
const { setIsOpen, isOpen, isMobile, toggleSidebar } = useSidebarContext();
const [expandedItems, setExpandedItems] = useState<string[]>([]);
const toggleExpanded = (title: string) => {
// setExpandedItems((prev) => (prev.includes(title) ? [] : [title]));
// Uncomment the following line to enable multiple expanded items
setExpandedItems((prev) =>
prev.includes(title) ? prev.filter((t) => t !== title) : [...prev, title],
);
};
useEffect(() => {
// Keep collapsible open, when it's subpage is active
NAV_DATA.some((section) => {
return section.items.some((item) => {
return item.items.some((subItem: NavSubItem) => {
if (subItem.url === pathname) {
if (!expandedItems.includes(item.title)) {
toggleExpanded(item.title);
}
// Break the loop
return true;
}
});
});
});
}, [pathname]);
return (
<>
{/* Mobile Overlay */}
{isMobile && isOpen && (
<div
className="fixed inset-0 z-40 bg-black/50 transition-opacity duration-300"
onClick={() => setIsOpen(false)}
aria-hidden="true"
/>
)}
<aside
className={cn(
"max-w-[290px] overflow-hidden border-r border-gray-200 bg-white transition-[width] duration-200 ease-linear dark:border-gray-800 dark:bg-gray-dark",
isMobile ? "fixed bottom-0 top-0 z-50" : "sticky top-0 h-screen",
isOpen ? "w-full" : "w-0",
)}
aria-label="Main navigation"
aria-hidden={!isOpen}
inert={!isOpen}
>
<div className="flex h-full flex-col py-10 pl-[25px] pr-[7px]">
<div className="relative pr-4.5">
<Link
href={"/"}
onClick={() => isMobile && toggleSidebar()}
className="px-0 py-2.5 min-[850px]:py-0"
>
<Logo />
</Link>
{isMobile && (
<button
onClick={toggleSidebar}
className="absolute left-3/4 right-4.5 top-1/2 -translate-y-1/2 text-right"
>
<span className="sr-only">Close Menu</span>
<ArrowLeftIcon className="ml-auto size-7" />
</button>
)}
</div>
{/* Navigation */}
<div className="custom-scrollbar mt-6 flex-1 overflow-y-auto pr-3 min-[850px]:mt-10">
{NAV_DATA.map((section) => (
<div key={section.label} className="mb-6">
<h2 className="mb-5 text-sm font-medium text-dark-4 dark:text-dark-6">
{section.label}
</h2>
<nav role="navigation" aria-label={section.label}>
<ul className="space-y-2">
{section.items.map((item) => (
<li key={item.title}>
{item.items.length ? (
<div>
<MenuItem
isActive={item.items.some(
({ url }: { url: string }) => url === pathname,
)}
onClick={() => toggleExpanded(item.title)}
>
<item.icon
className="size-6 shrink-0"
aria-hidden="true"
/>
<span>{item.title}</span>
<ChevronUp
className={cn(
"ml-auto rotate-180 transition-transform duration-200",
expandedItems.includes(item.title) &&
"rotate-0",
)}
aria-hidden="true"
/>
</MenuItem>
{expandedItems.includes(item.title) && (
<ul
className="ml-9 mr-0 space-y-1.5 pb-[15px] pr-0 pt-2"
role="menu"
>
{item.items.map((subItem: NavSubItem) => (
<li key={subItem.title} role="none">
<MenuItem
as="link"
href={subItem.url}
isActive={pathname === subItem.url}
>
<span>{subItem.title}</span>
</MenuItem>
</li>
))}
</ul>
)}
</div>
) : (
(() => {
const href =
"url" in item
? item.url + ""
: "/" +
item.title.toLowerCase().split(" ").join("-");
return (
<MenuItem
className="flex items-center gap-3 py-3"
as="link"
href={href}
isActive={pathname === href}
>
<item.icon
className="size-6 shrink-0"
aria-hidden="true"
/>
<span>{item.title}</span>
</MenuItem>
);
})()
)}
</li>
))}
</ul>
</nav>
</div>
))}
</div>
</div>
</aside>
</>
);
}
@@ -0,0 +1,62 @@
import { cn } from "@/lib/utils";
import { cva } from "class-variance-authority";
import Link from "next/link";
import { useSidebarContext } from "./sidebar-context";
const menuItemBaseStyles = cva(
"rounded-lg px-3.5 font-medium text-dark-4 transition-all duration-200 dark:text-dark-6",
{
variants: {
isActive: {
true: "bg-[rgba(87,80,241,0.07)] text-primary hover:bg-[rgba(87,80,241,0.07)] dark:bg-[#FFFFFF1A] dark:text-white",
false:
"hover:bg-gray-100 hover:text-dark hover:dark:bg-[#FFFFFF1A] hover:dark:text-white",
},
},
defaultVariants: {
isActive: false,
},
},
);
export function MenuItem(
props: {
className?: string;
children: React.ReactNode;
isActive: boolean;
} & ({ as?: "button"; onClick: () => void } | { as: "link"; href: string }),
) {
const { toggleSidebar, isMobile } = useSidebarContext();
if (props.as === "link") {
return (
<Link
href={props.href}
// Close sidebar on clicking link if it's mobile
onClick={() => isMobile && toggleSidebar()}
className={cn(
menuItemBaseStyles({
isActive: props.isActive,
className: "relative block py-2",
}),
props.className,
)}
>
{props.children}
</Link>
);
}
return (
<button
onClick={props.onClick}
aria-expanded={props.isActive}
className={menuItemBaseStyles({
isActive: props.isActive,
className: "flex w-full items-center gap-3 py-3",
})}
>
{props.children}
</button>
);
}
@@ -0,0 +1,61 @@
"use client";
import { useIsMobile } from "@/hooks/use-mobile";
import { createContext, useContext, useEffect, useState } from "react";
type SidebarState = "expanded" | "collapsed";
type SidebarContextType = {
state: SidebarState;
isOpen: boolean;
setIsOpen: (open: boolean) => void;
isMobile: boolean;
toggleSidebar: () => void;
};
const SidebarContext = createContext<SidebarContextType | null>(null);
export function useSidebarContext() {
const context = useContext(SidebarContext);
if (!context) {
throw new Error("useSidebarContext must be used within a SidebarProvider");
}
return context;
}
export function SidebarProvider({
children,
defaultOpen = true,
}: {
children: React.ReactNode;
defaultOpen?: boolean;
}) {
const [isOpen, setIsOpen] = useState(defaultOpen);
const isMobile = useIsMobile();
useEffect(() => {
if (isMobile) {
setIsOpen(false);
} else {
setIsOpen(true);
}
}, [isMobile]);
function toggleSidebar() {
setIsOpen((prev) => !prev);
}
return (
<SidebarContext.Provider
value={{
state: isOpen ? "expanded" : "collapsed",
isOpen,
setIsOpen,
isMobile,
toggleSidebar,
}}
>
{children}
</SidebarContext.Provider>
);
}
+41
View File
@@ -0,0 +1,41 @@
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
export function AdminsSkeleton() {
return (
<div className="rounded-[10px] bg-white px-7.5 pb-4 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card">
<h2 className="mb-5.5 text-body-2xlg font-bold text-dark dark:text-white">
Admins
</h2>
<Table>
<TableHeader>
<TableRow className="border-none uppercase [&>th]:text-center">
<TableHead className="!text-left">Full name</TableHead>
<TableHead>Email</TableHead>
<TableHead className="!text-right">Role</TableHead>
<TableHead>Username</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{Array.from({ length: 5 }).map((_, i) => (
<TableRow key={i}>
<TableCell colSpan={100}>
<Skeleton className="h-8" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
+119
View File
@@ -0,0 +1,119 @@
"use client";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useAdminsPresenter } from "./useAdminsPresenter";
import { PencilSquareIcon, TrashIcon } from "@/assets/icons";
import ConfirmationModal from "@/components/ui/ConfirmationModal";
import { AdminsSkeleton } from "./Skeleton";
import Link from "next/link";
const AdminsTable = () => {
const {
allUsers,
router,
isPending,
onConfirmDelete,
isModalOpen,
setIsModalOpen,
modalConfig,
setCurrentUser,
pathName,
} = useAdminsPresenter();
if (isPending) return <AdminsSkeleton />;
return (
<div className="flex flex-col rounded-[10px] bg-white px-7.5 pb-4 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card">
<button className="mb-5 flex w-fit justify-center self-end rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90">
<Link href={`${pathName}/create`}>Create Admin</Link>
</button>
<Table>
<TableHeader>
<TableRow className="border-none uppercase [&>th]:text-start">
<TableHead colSpan={100} className="text-start font-extrabold">
Full name
</TableHead>
<TableHead colSpan={100} className="text-start font-extrabold">
Email
</TableHead>
<TableHead colSpan={100} className="text-start font-extrabold">
Role
</TableHead>
<TableHead colSpan={100} className="text-start font-extrabold">
Username
</TableHead>
<TableHead colSpan={100} className="text-start font-extrabold">
Actions
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{allUsers.map((item) => {
return (
<TableRow key={item.id} className="odd:bg-gray-2 dark:odd:bg-gray-7">
<TableCell className="text-start" colSpan={100}>
{item.full_name}
</TableCell>
<TableCell className="text-start" colSpan={100}>
{item.email}
</TableCell>
<TableCell className="text-start" colSpan={100}>
{item.role}
</TableCell>
<TableCell className="text-start" colSpan={100}>
{item.username}
</TableCell>
<TableCell className="text-start xl:pr-7.5">
<div className="flex items-center justify-start gap-x-3.5">
<button
className="hover:text-red-500"
onClick={() => {
setCurrentUser(item);
setIsModalOpen(true);
}}
>
<span className="sr-only">Delete Admin </span>
<TrashIcon />
</button>
<button
className="hover:text-primary"
onClick={() => router.push(`/admins/edit/${item.id}`)}
>
<span className="sr-only">Edit Admin </span>
<PencilSquareIcon />
</button>
</div>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
{isModalOpen && (
<ConfirmationModal
isOpen={isModalOpen}
title={modalConfig.title || "Confirm"}
message={modalConfig.message || "Are you sure?"}
variant={modalConfig.variant || "warning"}
size={modalConfig.size || "md"}
confirmText={modalConfig.confirmText ?? "Confirm"}
cancelText={modalConfig.cancelText ?? "Cancel"}
onConfirm={() => {
onConfirmDelete();
}}
onCancel={() => setIsModalOpen(false)}
/>
)}
</div>
);
};
export default AdminsTable;

Some files were not shown because too many files have changed in this diff Show More