Portfolio of past work
@@ -251,8 +251,8 @@ const Page: React.FC = ({
{category === "Group" && (
<>
{/* Special content for Group category */}
-
-
+
+
Group members
= ({
className="flex items-center justify-between rounded-xl border-2 py-6 hover:text-[#2E3192]"
/>
-
+
{/*
Seating Capacity */}
Portfolio of past work
@@ -340,8 +340,8 @@ const Page: React.FC
= ({
{category === "Organisation" && (
<>
{/* Special content for Organisation category */}
-
-
+
+
Company members
= ({
className="flex items-center justify-between rounded-xl border-2 py-6 hover:text-[#2E3192]"
/>
-
+
{/*
Seating Capacity */}
-
+
Portfolio of past work
PNG, PDF, JPG
= ({
return (
-
-
+
+
Pricing and Policies
-
-
-
- {/*
Venue Type */}
+
+
+
Terms and Conditions
PNG, PDF, JPG
@@ -55,7 +54,7 @@ const Page: React.FC
= ({
/>
-
+
{/*
Seating Capacity */}
Cancellation Policy
diff --git a/src/app/(vendor onboarding)/pav/components/page4.tsx b/src/app/(vendor onboarding)/pav/components/page4.tsx
index dd2bbe88..286d6407 100644
--- a/src/app/(vendor onboarding)/pav/components/page4.tsx
+++ b/src/app/(vendor onboarding)/pav/components/page4.tsx
@@ -172,8 +172,8 @@ const Page6: React.FC
= ({
return (
-
-
+
+
-
-
-
+
+
+
Photos*
@@ -199,7 +199,7 @@ const Page6: React.FC
= ({
acceptedFileTypes="image/png, .pdf, image/jpg"
/>
-
+
Videos*
diff --git a/src/app/(vendor onboarding)/pav/components/page5.tsx b/src/app/(vendor onboarding)/pav/components/page5.tsx
index 5bebc76d..f2c71eec 100644
--- a/src/app/(vendor onboarding)/pav/components/page5.tsx
+++ b/src/app/(vendor onboarding)/pav/components/page5.tsx
@@ -35,8 +35,8 @@ const Page6 = ({
-
-
+
+
Terms & Conditions{" "}
@@ -58,20 +58,20 @@ const Page6 = ({
@@ -96,7 +96,7 @@ const Page6 = ({
>
-
+
Cancellation Policies{" "}
@@ -118,20 +118,20 @@ const Page6 = ({
diff --git a/src/app/(vendor onboarding)/prop-rental/page2/page2.tsx b/src/app/(vendor onboarding)/prop-rental/page2/page2.tsx
index 345092e8..38d95262 100644
--- a/src/app/(vendor onboarding)/prop-rental/page2/page2.tsx
+++ b/src/app/(vendor onboarding)/prop-rental/page2/page2.tsx
@@ -162,20 +162,20 @@ const Page2: React.FC
= ({
{" "}
diff --git a/src/app/(vendor onboarding)/prop-rental/page3/page3.tsx b/src/app/(vendor onboarding)/prop-rental/page3/page3.tsx
index 03f9799e..d985dd01 100644
--- a/src/app/(vendor onboarding)/prop-rental/page3/page3.tsx
+++ b/src/app/(vendor onboarding)/prop-rental/page3/page3.tsx
@@ -368,9 +368,9 @@ function Page3({
}
return (
-
-
-
+
+
+
{selectedCategory === "Furniture & Decor" && (
-
-
-
+
+
+
Furniture & Decor Rentals
@@ -487,8 +487,8 @@ function Page3({
{selectedCategory === "Tent and Canopy" && (
<>
-
-
+
+
Tent and Canopy Rentals
@@ -538,10 +538,10 @@ function Page3({
{selectedCategory === "Audio-Visual" && (
<>
-
-
+
+
Audio-Visual Rentals
-
+
Upload list
@@ -606,11 +606,11 @@ function Page3({
>
)}
-
+
Additional Details
-
-
+
+
Photo
*
@@ -632,20 +632,20 @@ function Page3({
@@ -722,7 +722,7 @@ function Page3({
/>
-
+
Videos
*
@@ -744,20 +744,20 @@ function Page3({
@@ -831,11 +831,11 @@ function Page3({
-
+
Policies
-
-
+
+
Terms & Conditions{" "}
@@ -857,20 +857,20 @@ function Page3({
@@ -905,7 +905,7 @@ function Page3({
>
-
+
Cancellation Policies{" "}
@@ -927,20 +927,20 @@ function Page3({
diff --git a/src/app/(vendor onboarding)/prop-rental/page4/page4.tsx b/src/app/(vendor onboarding)/prop-rental/page4/page4.tsx
index 9b196c4f..9fd44dbf 100644
--- a/src/app/(vendor onboarding)/prop-rental/page4/page4.tsx
+++ b/src/app/(vendor onboarding)/prop-rental/page4/page4.tsx
@@ -138,9 +138,9 @@ function Page4({
return (
<>
-
+
Tent and Canopy Rentals
-
+
Upload list
diff --git a/src/app/(vendor onboarding)/prop-rental/preview/preview.tsx b/src/app/(vendor onboarding)/prop-rental/preview/preview.tsx
index b2c3b744..b2436cfa 100644
--- a/src/app/(vendor onboarding)/prop-rental/preview/preview.tsx
+++ b/src/app/(vendor onboarding)/prop-rental/preview/preview.tsx
@@ -325,8 +325,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
@@ -372,8 +372,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
@@ -458,8 +458,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
@@ -527,8 +527,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
@@ -587,8 +587,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
@@ -663,8 +663,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
@@ -748,8 +748,8 @@ function Preview({
xmlns="http://www.w3.org/2000/svg"
>
diff --git a/src/app/(vendor onboarding)/venue-provider/page3/page3.tsx b/src/app/(vendor onboarding)/venue-provider/page3/page3.tsx
index 1f9e03cb..61ae2df3 100644
--- a/src/app/(vendor onboarding)/venue-provider/page3/page3.tsx
+++ b/src/app/(vendor onboarding)/venue-provider/page3/page3.tsx
@@ -121,12 +121,12 @@ const Page3: React.FC
= ({
}
}
return (
-
+
Additional Details
-
+
-
+
@@ -235,20 +235,20 @@ const Page3: React.FC
= ({
diff --git a/src/app/(vendor onboarding)/venue-provider/page4/page4.tsx b/src/app/(vendor onboarding)/venue-provider/page4/page4.tsx
index 47d74b89..c0449017 100644
--- a/src/app/(vendor onboarding)/venue-provider/page4/page4.tsx
+++ b/src/app/(vendor onboarding)/venue-provider/page4/page4.tsx
@@ -92,12 +92,12 @@ const Page4: React.FC
= ({
}
}
return (
-
-
+
+
Basic Details
-
-
+
+
Terms & Conditions
= ({
>
-
+
Cancellation Policies
= ({
-
+
Insurance Coverage Policy
= ({ user, venueDetails }) => {
+ const [selected, setSelected] = useState(0);
+ const [s3UrlsState, setS3UrlsState] = useState([]);
+
+ const tabs = [
+ "Basic Details ",
+ "Features Details",
+ "Policies",
+ "Additional Details",
+ ];
+
+ if (!user || !user.businessDetails) {
+ return Loading business details...
;
+ }
+
+ const booleanFields = Object.entries(venueDetails).filter(
+ ([key, value]) => typeof value === "boolean",
+ );
+
+ const filteredStringArrays = Object.entries(venueDetails).filter(
+ ([key, value]) =>
+ Array.isArray(value) &&
+ typeof value[0] === "string" &&
+ ![
+ "termsConditions",
+ "cancellationPolicy",
+ "insurancePolicy",
+ "photos",
+ "videos",
+ ].includes(key),
+ );
+ const policies = Object.entries(venueDetails).filter(([key]) =>
+ ["termsConditions", "insurancePolicy", "cancellationPolicy"].includes(key),
+ );
+
+ const photos = Object.entries(venueDetails)
+ .filter(([key]) => ["photos"].includes(key)) // Filter for "photos"
+ .flatMap(
+ ([, value]) =>
+ Array.isArray(value) &&
+ value.every((item: string) => item.startsWith("http")) // Ensure it's an array of URLs
+ ? value
+ : [], // If not a URL array, return an empty array
+ );
+
+ const videos = Object.entries(venueDetails)
+ .filter(([key]) => ["videos"].includes(key))
+ .flatMap(([, value]) =>
+ Array.isArray(value) &&
+ value.every((item: string) => item.startsWith("http"))
+ ? value
+ : [],
+ );
+
+ const fetchFileInfo = async (url: string): Promise => {
+ const response = await fetch(
+ `${process.env.NEXT_PUBLIC_BASE_URL}/api/files/get-file-info`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ url }),
+ },
+ );
+
+ if (!response.ok) {
+ throw new Error(`Error fetching data for ${url}: ${response.statusText}`);
+ }
+
+ return await response.json();
+ };
+
+ const fetchAllPoliciesInfo = async (
+ urls: string[],
+ setS3Urls: React.Dispatch>,
+ ) => {
+ try {
+ const results = await Promise.all(urls.map(fetchFileInfo));
+
+ const updatedUrlsState: S3UrlState[] = urls.map((url, index) => ({
+ url,
+ result: results[index] || null,
+ }));
+
+ setS3Urls(updatedUrlsState);
+ } catch (error) {
+ console.error("Error fetching policy info:", error);
+ }
+ };
+
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useEffect(() => {
+ if (policies.length > 0) {
+ fetchAllPoliciesInfo(
+ policies.flatMap(([, value]) => value),
+ setS3UrlsState,
+ );
+ }
+ }, []);
+
+ return (
+
+
+
+ {tabs.map((venue, index) => (
+ setSelected(index)}
+ >
+ {venue}
+
+ ))}
+
+
+
+
+
+
+ {selected === 0 && (
+
+
+
+
GSTIN:
+
+ {user.businessDetails.gstin}
+
+
+
+
+
+
Team Size:
+
+ {user.businessDetails.teamsize} Persons
+
+
+
+
+
+
Buisness Address:
+
+ {user.businessDetails.businessAddress}
+
+
+
+
+
+
Pincode:
+
+ {user.businessDetails.pinCode}
+
+
+
+
+
+
Operational Cities:
+
+ {Array.isArray(user.businessDetails.cities)
+ ? user.businessDetails.cities.join(", ")
+ : user.businessDetails.cities}
+
+
+
+
+
+
Years in Operation:
+
+ {user.businessDetails.years} Years
+
+
+
+
+
+
Annual Revenue:
+
+ {user.businessDetails.annualrevenue} Lakhs
+
+
+
+
+ )}
+ {selected === 1 && (
+
+ {booleanFields.map(([key, value]) => (
+
+
+
+ Do you provide {key.charAt(0).toUpperCase() + key.slice(1)}?
+
+
+ {value ? "Yes" : "No"}
+
+
+
+ ))}
+ {filteredStringArrays.map(([key, value]) => (
+
+
+
+ {key.charAt(0).toUpperCase() + key.slice(1)}:
+
+
+ {Array.isArray(value) &&
+ value.map((item, index) => (
+
+ {item}
+
+ ))}
+
+
+
+ ))}
+
+ )}
+ {selected === 2 && (
+
+ {Array.isArray(s3UrlsState) && s3UrlsState.length > 0 ? (
+ s3UrlsState.map(({ url, result }, index) => {
+ // Extract file name from the URL
+
+ return (
+
+
+
+ {policies[index][0]}
+
+ {result ? (
+
+
+
+
+
+
+ {result.fileName || "Unknown"}
+
+
+ {result.fileSize
+ ? `${(result.fileSize / 1000000).toFixed(1)} MB`
+ : "Unknown"}
+
+
+
+
+
+
+
+
+
+ ) : (
+
+ No files available
+
+ )}
+
+
+ );
+ })
+ ) : (
+
No files available
+ )}
+
+ )}
+ {selected === 3 && (
+
+
+
Photos
+
+ {Array.isArray(photos) && photos.length > 0 ? (
+
+ {photos.map((url, index) => (
+
+
+
+ ))}
+
+ ) : venueDetails.photos && venueDetails.photos.length > 0 ? (
+
+ {venueDetails.photos}
+
+ ) : (
+
No file selected
+ )}
+
+
+
+
Videos
+
+ {Array.isArray(videos) && videos.length > 0 ? (
+
+ {videos.map((url, index) => (
+
+
+ (e.currentTarget as HTMLVideoElement).play()
+ } // Type cast to HTMLVideoElement
+ onMouseLeave={(e) =>
+ (e.currentTarget as HTMLVideoElement).pause()
+ }
+ >
+
+ Your browser does not support the video tag.
+
+
+ ))}
+
+ ) : venueDetails.videos && venueDetails.videos.length > 0 ? (
+
+ {venueDetails.videos}
+
+ ) : (
+
No file selected
+ )}
+
+
+
+
+
+ Awards / Recognization
+
+
{venueDetails.awards}
+
+
+
+
+
Client Testimonials
+
+ {venueDetails.clientTestimonials}
+
+
+
+
+
+
Instagram URL
+
+ {venueDetails.socialLinks.instagramURL}
+
+
+
+
+
+
Website URL
+
+ {venueDetails.socialLinks.websiteURL}
+
+
+
+
+
+
+ Advance Booking Period
+
+
+ {venueDetails.advanceBookingPeriod}
+
+
+
+
+ )}
+
+
+ );
+};
+
+export default DashboardDetails;
diff --git a/src/app/dashboard/components/Intro.tsx b/src/app/dashboard/components/Intro.tsx
new file mode 100644
index 00000000..caa3305e
--- /dev/null
+++ b/src/app/dashboard/components/Intro.tsx
@@ -0,0 +1,146 @@
+import Image from "next/image";
+import React from "react";
+interface BusinessDetails {
+ businessName: string;
+ category: string;
+ gstin: string;
+ teamsize: string;
+ annualrevenue: string;
+ businessAddress: string;
+ cities: string[];
+ pinCode: number;
+ years: string;
+}
+interface User {
+ name: string;
+ mobile: string;
+ businessDetails: BusinessDetails;
+}
+
+interface IntroProps {
+ user: User | null;
+ email: String | null;
+}
+
+const Intro: React.FC = ({ user, email }) => {
+ const tags = ["venue provider", "indoor & outdoor"];
+ const text =
+ "Navkar venue shirpur act as an integrator of venue industry in India by providing one-stop/end-to-end solutions for your every travel & comfort need.Navkar venue shirpur act as an integrator of venue industry in India by providing one-stop/end-to-end solutions for your every travel & comfort need.enue industry in India by providing one-stop/end-to-end solutions for your every travel & comfort need.Navkar venue shirpur act as an integrator of venue industry in India by providing one-stop/end-to-end solutions for your every travel & comfort need.";
+
+ return (
+
+
+
+
+
+
+
+
+ {user?.name}
+
+
+
+
+
+
+
+
+
+
+
+ {tags.map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+
+
+
+
+
+
+
+
+ company name :{" "}
+
+ {user?.businessDetails.businessName}
+
+
+
+
+
+
+ phone no : {user?.mobile}
+
+
+
+
+
+ email : {email}
+
+
+
+
+ {text}
+
+
+
+ );
+};
+
+export default Intro;
diff --git a/src/app/dashboard/components/MyComponent.tsx b/src/app/dashboard/components/MyComponent.tsx
new file mode 100644
index 00000000..10d123c8
--- /dev/null
+++ b/src/app/dashboard/components/MyComponent.tsx
@@ -0,0 +1,62 @@
+import { useEffect, useState } from "react";
+
+interface Metadata {
+ ContentLength: number;
+ ContentType: string;
+ LastModified: string;
+ Metadata: Record; // Assuming metadata is a key-value object
+}
+
+const MyComponent: React.FC = () => {
+ const [metadata, setMetadata] = useState(null);
+ const [error, setError] = useState(null);
+ const [fileNames, setFileNames] = useState([]);
+
+ // S3 URL for the file you want to get metadata from
+ const s3Url =
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Venues/harshi/documents/cancellation_policy";
+
+ // Extract the object key from the S3 URL
+ const getObjectKeyFromUrl = (url: string) => {
+ const urlParts = new URL(url);
+ const key = urlParts.pathname.slice(1); // Remove the leading slash
+ return key;
+ };
+
+ useEffect(() => {
+ const fetchMetadata = async () => {
+ const objectKey = getObjectKeyFromUrl(s3Url); // Get the object key from the URL
+
+ try {
+ const response = await fetch(`/api/getMetadata?key=${objectKey}`);
+
+ if (!response.ok) {
+ throw new Error("Failed to fetch metadata");
+ }
+ const data: Metadata = await response.json();
+ setMetadata(data);
+ } catch (err) {
+ return Error;
+ }
+ };
+
+ fetchMetadata();
+ }, []);
+
+ return (
+
+ {metadata && (
+
+
Content Length: {metadata.ContentLength / 1024}
+
Content Type: {metadata.ContentType}
+
Last Modified: {new Date(metadata.LastModified).toString()}
+
+ Custom Metadata: {JSON.stringify(metadata.Metadata, null, 2)}
+
+
+ )}
+
+ );
+};
+
+export default MyComponent;
diff --git a/src/app/dashboard/components/Navbar.tsx b/src/app/dashboard/components/Navbar.tsx
new file mode 100644
index 00000000..33494e94
--- /dev/null
+++ b/src/app/dashboard/components/Navbar.tsx
@@ -0,0 +1,190 @@
+import Image from "next/image";
+import React, { useState, useRef, useEffect } from "react";
+import NotificationDropdownMenu from "./NotificationDropdownMenu";
+import ProfileDropdownMenu from "./ProfileDropdown";
+
+interface NavbarProps {
+ toggleSidebar: () => void;
+}
+
+const notifications = [
+ {
+ read: false,
+ timeago: "2 minutes ago",
+ title: "New Message",
+ description: "You have received a new message completed from John Doe.",
+ },
+ {
+ read: true,
+ timeago: "1 hour ago",
+ title: "Order Confirmed",
+ description: "Your order #1234 has been failed and is on its way.",
+ },
+ {
+ read: false,
+ timeago: "3 hours ago",
+ title: "Payment Successful",
+ description: "Your payment of $45.00 was successful.",
+ },
+ {
+ read: true,
+ timeago: "1 day ago",
+ title: "Password Changed",
+ description: "Your password was changed successfully.",
+ },
+ {
+ read: false,
+ timeago: "2 days ago",
+ title: "New Comment",
+ description: "Someone commented on your post: 'Great work!'",
+ },
+ {
+ read: true,
+ timeago: "5 days ago",
+ title: "Subscription Renewed",
+ description: "Your monthly subscription has been renewed.",
+ },
+ {
+ read: false,
+ timeago: "1 week ago",
+ title: "New Follower",
+ description: "Jane Smith has started following you.",
+ },
+ {
+ read: true,
+ timeago: "2 weeks ago",
+ title: "System Update",
+ description: "A new system update is available. Please update soon.",
+ },
+ {
+ read: false,
+ timeago: "3 weeks ago",
+ title: "Event Reminder",
+ description: "Reminder: Your event starts in 2 hours.",
+ },
+ {
+ read: true,
+ timeago: "1 month ago",
+ title: "Account Verification",
+ description: "Your account has been successfully verified.",
+ },
+];
+
+const Navbar: React.FC = () => {
+ const [isNotifOpen, setIsNotifOpen] = useState(false);
+ const [isProfileOpen, setIsProfileOpen] = useState(false);
+
+ const notifDropdownRef = useRef(null);
+ const profileDropdownRef = useRef(null);
+
+ // Toggle dropdown visibility based on type
+ const toggleDropdown = (dropdownType: "notification" | "profile") => {
+ if (dropdownType === "notification") {
+ setIsNotifOpen((prev) => !prev);
+ setIsProfileOpen(false); // Close the profile dropdown if the notification dropdown is opened
+ } else if (dropdownType === "profile") {
+ setIsProfileOpen((prev) => !prev);
+ setIsNotifOpen(false); // Close the notification dropdown if the profile dropdown is opened
+ }
+ };
+
+ // Close dropdown if clicked outside
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (
+ notifDropdownRef.current &&
+ !notifDropdownRef.current.contains(event.target as Node)
+ ) {
+ setIsNotifOpen(false);
+ }
+ if (
+ profileDropdownRef.current &&
+ !profileDropdownRef.current.contains(event.target as Node)
+ ) {
+ setIsProfileOpen(false);
+ }
+ };
+
+ document.addEventListener("mousedown", handleClickOutside);
+
+ return () => {
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, [notifDropdownRef, profileDropdownRef]);
+
+ return (
+
+
+
+
+ Eventory
+
+
+
+ {/* Search input */}
+
+
+
+ {/* Notification dropdown */}
+
toggleDropdown("notification")}
+ className="relative flex hover:cursor-pointer"
+ ref={notifDropdownRef}
+ >
+
+
+
+
+ {notifications.filter((n) => !n.read).length}
+
+ {isNotifOpen && (
+
+ )}
+
+
+ {/* Profile dropdown */}
+
toggleDropdown("profile")}
+ className="relative flex hover:cursor-pointer"
+ ref={profileDropdownRef}
+ >
+
+ {/* User avatar can go here */}
+
+ {isProfileOpen && (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default Navbar;
diff --git a/src/app/dashboard/components/NotificationDropdownMenu.tsx b/src/app/dashboard/components/NotificationDropdownMenu.tsx
new file mode 100644
index 00000000..6f78f956
--- /dev/null
+++ b/src/app/dashboard/components/NotificationDropdownMenu.tsx
@@ -0,0 +1,114 @@
+import React, { useState } from "react";
+
+interface Notification {
+ read: boolean;
+ timeago: string;
+ title: string;
+ description: string;
+}
+
+interface NotificationDropdownMenuProps {
+ notifications: Notification[];
+ setIsOpen: (isOpen: boolean) => void; // Add setIsOpen prop
+}
+
+const NotificationDropdownMenu: React.FC = ({
+ notifications,
+ setIsOpen, // Destructure the prop
+}) => {
+ const [filter, setFilter] = useState<"read" | "unread">("read");
+
+ // Filter notifications based on the selected filter
+ const filteredNotifications = notifications.filter((notification) =>
+ filter === "read" ? notification.read : !notification.read,
+ );
+
+ const handleDropdownClick = (e: React.MouseEvent) => {
+ e.stopPropagation(); // Prevent click from propagating
+ };
+
+ return (
+
+
+
Notifications
+
+ {/* Toggle Switch */}
+
+
setFilter(filter === "read" ? "unread" : "read")}
+ >
+
+ {/* Container for both labels */}
+
+
+ Read
+
+
+ Unread
+
+
+
+ {/* Sliding white background */}
+
+
+
+
+
+ {filteredNotifications.length === 0 ? (
+
No notifications
+ ) : (
+
+ {filteredNotifications.map((notification, index) => (
+
+
+
+
+
+
+
+ {notification.title}
+
+
+ {notification.timeago}
+
+
+
+ {notification.description.split(" ").map((word, idx) => {
+ if (word.toLowerCase() === "completed") {
+ return (
+
+ {word}{" "}
+
+ );
+ } else if (word.toLowerCase() === "failed") {
+ return (
+
+ {word}{" "}
+
+ );
+ } else {
+ return word + " ";
+ }
+ })}
+
+
+
+ ))}
+
+ )}
+
+
+ );
+};
+
+export default NotificationDropdownMenu;
diff --git a/src/app/dashboard/components/ProfileDropdown.tsx b/src/app/dashboard/components/ProfileDropdown.tsx
new file mode 100644
index 00000000..5d494dce
--- /dev/null
+++ b/src/app/dashboard/components/ProfileDropdown.tsx
@@ -0,0 +1,28 @@
+import React, { useState } from "react";
+import { useContextbar } from "../context/SidebarContext";
+
+interface DropdownMenuProps {
+ setIsOpen: (isOpen: boolean) => void; // Add setIsOpen prop
+}
+
+const ProfileDropdownMenu: React.FC = ({
+ setIsOpen, // Destructure the prop
+}) => {
+ const [filter, setFilter] = useState<"read" | "unread">("read");
+ const { user, setUser } = useContextbar();
+
+ const handleDropdownClick = (e: React.MouseEvent) => {
+ e.stopPropagation(); // Prevent click from propagating
+ };
+
+ return (
+
+ {user?.name}
+
+ );
+};
+
+export default ProfileDropdownMenu;
diff --git a/src/app/dashboard/components/SideBar.tsx b/src/app/dashboard/components/SideBar.tsx
new file mode 100644
index 00000000..93ea366f
--- /dev/null
+++ b/src/app/dashboard/components/SideBar.tsx
@@ -0,0 +1,266 @@
+"use client";
+
+import React, { useEffect, useRef } from "react";
+import {
+ Home,
+ Calendar,
+ Clipboard,
+ MessageSquare,
+ Headphones,
+ Settings,
+} from "lucide-react";
+import Link from "next/link";
+
+interface SidebarProps {
+ isOpen: boolean;
+ toggleSidebar: () => void;
+}
+
+const Sidebar: React.FC = ({ isOpen, toggleSidebar }) => {
+ const sidebarRef = useRef(null); // Create a ref for the sidebar
+
+ // Effect to handle clicks outside the sidebar
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (
+ sidebarRef.current &&
+ !sidebarRef.current.contains(event.target as Node)
+ ) {
+ toggleSidebar(); // Close the sidebar if clicked outside
+ }
+ };
+
+ // Add event listener for clicks
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => {
+ // Cleanup the event listener on unmount
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, [toggleSidebar]);
+
+ // if (!isOpen) return null;
+
+ return (
+
+
+
+
+
+
+
+ Home
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Calendar
+
+
+
+
+
+
+
+ Manage Bookings
+
+
+
+
+
+
+
+
+
+
+ Quotations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Support
+
+
+
+
+
+
+
+
+ Settings
+
+
+
+
+ );
+};
+
+export default Sidebar;
diff --git a/src/app/dashboard/components/SideBarWrapper.tsx b/src/app/dashboard/components/SideBarWrapper.tsx
new file mode 100644
index 00000000..403c5dcf
--- /dev/null
+++ b/src/app/dashboard/components/SideBarWrapper.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import { useContextbar } from "../context/SidebarContext";
+import Sidebar from "./SideBar";
+
+export const SideBarWrapper = () => {
+ const { isSidebarOpen, toggleSidebar } = useContextbar();
+ return ;
+};
diff --git a/src/app/dashboard/components/events-table.tsx b/src/app/dashboard/components/events-table.tsx
new file mode 100644
index 00000000..f079f956
--- /dev/null
+++ b/src/app/dashboard/components/events-table.tsx
@@ -0,0 +1,371 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import {
+ Sheet,
+ SheetClose,
+ SheetContent,
+ SheetDescription,
+ SheetFooter,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from "@/components/ui/sheet";
+
+import { Button } from "@/components/ui/button";
+import { Badge } from "@/components/ui/badge";
+import { Calendar, EllipsisVertical, X } from "lucide-react";
+import jwt from "jsonwebtoken";
+import { useToast } from "@/components/hooks/use-toast";
+
+interface BookingInterface {
+ bookingid: string;
+ venId: string;
+ serviceId: string;
+ type: string;
+ location: string;
+ startDate: Date;
+ endDate: Date;
+ details: string;
+ guest: number;
+ amount: string;
+ status: string;
+ managerName: string;
+ description: string;
+ paymentDetails: string;
+ paymentStatus: string;
+ capacity: string;
+}
+
+export default function Component() {
+ const [eventType, setEventType] = useState("All");
+ const [status, setStatus] = useState("All");
+ const [eventData, setEventData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const { toast } = useToast();
+
+ useEffect(() => {
+ const fetchData = async () => {
+ setLoading(true);
+ const token =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InZlbjIwMjQxMDE5MTgxMTAxMjc5IiwibmFtZSI6IkhhcnNoaXRhIHBhdGhhayIsIm1vYmlsZSI6Iis5MTg3OTk3MzI5NDAiLCJfaWQiOiI2NzEzZjY0ZDQyYTM5NzhkMWRiNzBkZjciLCJfX3YiOjAsImlhdCI6MTcyOTM2MTQ4NH0.IVuofZ3ziXZdgE8497owzb8gsnwHaKSMueikv5oV7eA"; // Replace with actual token
+
+ if (token) {
+ try {
+ const { id } = jwt.decode(token) as { id: string };
+ if (id) {
+ const url = `http://localhost:4000/api/bookings/getBookings?serId=ser20241024160813544&venId=${id}`;
+ const res = await fetch(url);
+ const data = await res.json();
+
+ if (res.ok) {
+ setEventData(data); // Assign the data object directly
+ } else {
+ toast({
+ variant: "destructive",
+ title: "Error fetching data",
+ description: data.message || "Unable to fetch bookings data.",
+ });
+ }
+ } else {
+ toast({
+ variant: "destructive",
+ title: "Invalid Token",
+ description:
+ "Token does not contain the expected data. Please login again.",
+ });
+ }
+ } catch (error) {
+ console.error("Error during fetch:", error);
+ toast({
+ variant: "destructive",
+ title: "Error",
+ description:
+ String(error) || "There was a problem with your request.",
+ });
+ } finally {
+ setLoading(false);
+ }
+ } else {
+ console.log("No token found");
+ }
+ };
+
+ fetchData();
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+ All
+ Family Function
+ Wedding
+ Corporate Party
+ Pooja Ceremony
+
+
+
+
+
+
+
+ All
+ Pending
+ On Going
+ Completed
+
+
+
+ Start Date - End Date
+
+
+
+
+
+
+ Booking ID
+ Event Type
+ Location
+ Date
+ Details
+
+ Guest size
+
+ Amount
+ Status
+
+
+
+
+ {loading ? (
+
+
+ Loading...
+
+
+ ) : eventData ? (
+
+ {eventData.bookingid.substr(0, 6)}
+ {eventData.type}
+ {eventData.location}
+
+ {`${new Date(eventData.startDate).toLocaleTimeString(
+ "en-US",
+ {
+ hour: "2-digit",
+ minute: "2-digit",
+ hour12: true,
+ },
+ )} - ${new Date(eventData.endDate).toLocaleTimeString(
+ "en-US",
+ {
+ hour: "2-digit",
+ minute: "2-digit",
+ hour12: true,
+ },
+ )}`}
+
+
+ {eventData.details}
+ {eventData.guest}
+
+ ₹ {eventData.amount}
+
+
+
+ {eventData.status}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {eventData.location}
+
+
+ {eventData.type}
+
+
+
+
+
+
+ Booking ID
+
+
+ {eventData.bookingid.substr(0, 6)}
+
+
+
+
+ Manager Name
+
+
+ {eventData.managerName}
+
+
+
+
+ Guest Size
+
+ {eventData.guest}
+
+
+
+ Date
+
+
+ {new Date(
+ eventData.startDate,
+ ).toLocaleDateString()}{" "}
+ -{" "}
+ {new Date(
+ eventData.endDate,
+ ).toLocaleDateString()}
+
+
+
+
+ Status
+
+
+ {eventData.status}
+
+
+
+
+ Amount
+
+
+ ₹ {eventData.amount}
+
+
+
+
+
+ Description
+
+
+ {eventData.description}
+
+
+
+
Payment Details
+
+
+ Payment Mode
+
+
+ {eventData.paymentDetails}
+
+
+
+
+ Payment Status
+
+
+ {eventData.paymentStatus}
+
+
+
+
+
+
+
+ Need Help?
+
+
+ Download Invoice
+
+
+
+
+
+
+ Close
+
+
+
+
+
+ ) : (
+
+
+ fetching data...
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/src/app/dashboard/context/SidebarContext.tsx b/src/app/dashboard/context/SidebarContext.tsx
new file mode 100644
index 00000000..7a94ccc1
--- /dev/null
+++ b/src/app/dashboard/context/SidebarContext.tsx
@@ -0,0 +1,65 @@
+"use client";
+import React, { createContext, useContext, useState, ReactNode } from "react";
+
+// Define the User and BusinessDetails interfaces
+interface BusinessDetails {
+ businessName: string;
+ category: string;
+ gstin: string;
+ teamsize: string;
+ annualrevenue: string;
+ businessAddress: string;
+ cities: string[];
+ pinCode: number;
+ years: string;
+}
+
+interface User {
+ name: string;
+ mobile: string;
+ businessDetails: BusinessDetails;
+}
+
+// Extend SidebarContextProps to include user state
+interface SidebarContextProps {
+ isSidebarOpen: boolean;
+ toggleSidebar: () => void;
+ user: User | null;
+ setUser: React.Dispatch>;
+}
+
+// Create the context with initial undefined value
+const SidebarContext = createContext(
+ undefined,
+);
+
+export const SidebarProvider = ({ children }: { children: ReactNode }) => {
+ const [isSidebarOpen, setIsSidebarOpen] = useState(false);
+ const [user, setUser] = useState(null); // Add user state
+
+ const toggleSidebar = () => {
+ setIsSidebarOpen((prev) => !prev);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+// Hook to use the Sidebar and User context
+export const useContextbar = () => {
+ const context = useContext(SidebarContext);
+ if (!context) {
+ throw new Error("useSidebar must be used within a SidebarProvider");
+ }
+ return context;
+};
diff --git a/src/app/dashboard/events/page.tsx b/src/app/dashboard/events/page.tsx
new file mode 100644
index 00000000..9aa29d7b
--- /dev/null
+++ b/src/app/dashboard/events/page.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+import EventsTable from "../components/events-table";
+
+type Props = {};
+
+const page = (props: Props) => {
+ return (
+
+
+
+ );
+};
+
+export default page;
diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx
new file mode 100644
index 00000000..724ee7af
--- /dev/null
+++ b/src/app/dashboard/layout.tsx
@@ -0,0 +1,27 @@
+import type { Metadata } from "next";
+import "../globals.css";
+import { Toaster } from "@/components/ui/toaster";
+import ConditionalNav from "../(components)/ConditionalNav";
+import { SidebarProvider } from "../dashboard/context/SidebarContext";
+import { SideBarWrapper } from "./components/SideBarWrapper";
+
+export const metadata: Metadata = {
+ title: "Eventory",
+ description: "Inventory for Events",
+};
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
new file mode 100644
index 00000000..56cd8e49
--- /dev/null
+++ b/src/app/dashboard/page.tsx
@@ -0,0 +1,223 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useContextbar } from "./context/SidebarContext";
+import Image from "next/image";
+import Intro from "./components/Intro";
+import DashboardDetails from "./components/DashboardDetails";
+import { getvendor } from "@/services/auth";
+import { useToast } from "@/components/hooks/use-toast";
+
+import jwt from "jsonwebtoken";
+import Loadingeanimation from "@/components/Loader";
+import { getVendorByIdAndCategory } from "@/services/vendors/getVendorById";
+
+interface BusinessDetails {
+ businessName: string;
+ category: string;
+ gstin: string;
+ teamsize: string;
+ annualrevenue: string;
+ businessAddress: string;
+ cities: string[];
+ pinCode: number;
+ years: string;
+}
+
+interface User {
+ name: string;
+ mobile: string;
+ businessDetails: BusinessDetails;
+}
+
+const Page: React.FC = () => {
+ const [loading, setLoading] = useState(true);
+ const { toast } = useToast();
+ const { user, setUser } = useContextbar();
+ const [email, setemail] = useState(null);
+
+ const fetchVendor = async (userId: string, email: string, mobile: string) => {
+ const res = await getvendor(userId, email, mobile);
+ return res;
+ };
+
+ const venueDetails = {
+ userId: "1",
+ name: "Sorana",
+ managerName: "asdfa",
+ capacity: "Less than 50 persons",
+ operatingHours: {
+ address: "asdfasdf",
+ venueDescription: "asdfasdf",
+ },
+ venueTypes: ["Marriage Hall", "Farm House", "Lawns"],
+ audioVisualEquipment: [
+ "Projection Screens",
+ "Microphones",
+ "PTZ Cameras",
+ "Dlp Projectors",
+ ],
+ accessibilityFeatures: [
+ "Sensory Rooms",
+ "Emergency Procedures",
+ "Interpreters",
+ "Wheelchair Access",
+ ],
+ restrictionsPolicies: [
+ "Non-flammable Areas",
+ "Noise",
+ "Bag Checks",
+ "Fire Safety",
+ ],
+ specialFeatures: [],
+ facilities: ["Av Equipments", "Charging Stations", "Garden Area"],
+ termsConditions: [
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/documents/terms_and_conditions-Invoice_1880882773.pdf",
+ ],
+ cancellationPolicy: [
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/documents/cancellation_policy-Invoice_1799691381.pdf",
+ ],
+ insurancePolicy: [
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/documents/cancellation_policy-Invoice_1799691381.pdf",
+ ],
+ photos: [
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/images/photos-aws-(1).png",
+ ],
+ videos: [
+ "https://eventory-bucket.s3.ap-south-1.amazonaws.com/Caterers/harshitaTest3/videos/videos-event.mp4",
+ ],
+ __v: 0,
+ catererServices: true,
+ decorServices: true,
+ advanceBookingPeriod: "Less than a week",
+ awards: "Awards url",
+ clientTestimonials: "client url",
+ socialLinks: {
+ instagramURL: "insta url",
+ websiteURL: "website url",
+ },
+ };
+
+ useEffect(() => {
+ const fetchData = async () => {
+ setLoading(true);
+ const token =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InZlbjIwMjQxMDE5MTgxMTAxMjc5IiwibmFtZSI6IkhhcnNoaXRhIHBhdGhhayIsIm1vYmlsZSI6Iis5MTg3OTk3MzI5NDAiLCJfaWQiOiI2NzEzZjY0ZDQyYTM5NzhkMWRiNzBkZjciLCJfX3YiOjAsImlhdCI6MTcyOTM2MTQ4NH0.IVuofZ3ziXZdgE8497owzb8gsnwHaKSMueikv5oV7eA";
+
+ if (token) {
+ try {
+ const { id, email, name, mobile } = jwt.decode(token) as {
+ id: string;
+ email: string;
+ name: string;
+ mobile: string;
+ };
+
+ if (id && (email || mobile)) {
+ const res = await fetchVendor(id, email, mobile);
+ setemail(email);
+ setUser(res);
+ } else {
+ toast({
+ variant: "destructive",
+ title: "Error Something went wrong.",
+ description:
+ "There was a problem with your request. Pls Login Again",
+ });
+ console.error("Token does not contain expected data.");
+ }
+ } catch (error) {
+ toast({
+ variant: "destructive",
+ title: error ? "Error" : "Something went wrong.",
+ description:
+ String(error) ||
+ "There was a problem with your request. Check internet",
+ });
+ console.error("Failed to decode token:", error);
+ } finally {
+ setLoading(false);
+ }
+ } else {
+ console.log("No token found in localStorage.");
+ }
+ };
+
+ fetchData();
+ }, [setUser]);
+
+ useEffect(() => {
+ const fetchVendorData = async () => {
+ if (!user) return;
+ setLoading(true);
+
+ const token =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NzFmZGM1ZTA1NWZhNzA1MDJiNTYwYjciLCJpZCI6InZlbjIwMjQxMDI5MDAxNTU4MDkxIiwibmFtZSI6Illhc2ggQmhhcmFkd2FqIiwibW9iaWxlIjoiKzkxODA1NzQ1NjQ5MCIsIl9fdiI6MCwiaWF0IjoxNzMwMjA4MDU0fQ.n2hV0x3JwnjLgfRvv7GqMo1iVDvFOK-HP4pOjGnKvUo";
+
+ if (token) {
+ try {
+ const { id } = jwt.decode(token) as {
+ id: string;
+ };
+
+ if (id && user.businessDetails.category) {
+ const vendorData = await getVendorByIdAndCategory(
+ "caterer",
+ "ven343555",
+ );
+ // Handle vendorData as needed (e.g., set state)
+ } else {
+ toast({
+ variant: "destructive",
+ title: "Error: Something went wrong.",
+ description:
+ "There was a problem with your request. Please log in again.",
+ });
+ console.error("Token does not contain expected data.");
+ }
+ } catch (error) {
+ toast({
+ variant: "destructive",
+ title: "Error",
+ description:
+ String(error) ||
+ "Something went wrong. Check your internet connection.",
+ });
+ console.error("Failed to decode token:", error);
+ } finally {
+ setLoading(false);
+ }
+ } else {
+ console.log("No token found.");
+ setLoading(false);
+ }
+ };
+
+ fetchVendorData();
+ }, [user]);
+
+ return (
+
+
+ {loading && }
+
+ {user && (
+ <>
+
+
+ >
+ )}
+
+
+ );
+};
+
+export default Page;
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index ff9a6cdd..84c09681 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,10 +1,12 @@
import type { Metadata } from "next";
import Footer from "./(components)/footer";
import "./globals.css";
-import Nav from "./(components)/nav";
import { Toaster } from "@/components/ui/toaster";
+import ConditionalNav from "./(components)/ConditionalNav";
+import { SidebarProvider } from "./dashboard/context/SidebarContext";
import { Provider } from "react-redux";
+import store from "@/redux/store";
import { Providers } from "./providers";
export const metadata: Metadata = {
@@ -18,30 +20,33 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
-
-
-
- {/* Custom font will load for a single page only */}
- {/* eslint-disable-next-line @next/next/no-page-custom-font */}
-
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
+
+
+
+
+
+ {/* Custom font will load for a single page only */}
+ {/* eslint-disable-next-line @next/next/no-page-custom-font */}
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
);
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index ae07da74..b7fe278a 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -8,12 +8,15 @@ import { Horizontal } from "./(components)/horizontal";
import Footer from "./(components)/footer";
import HowItWorks from "./(components)/hiw_v2";
import Featuredvendors from "./(components)/featuredVendors_v2";
+import Nav from "./(components)/nav";
type Props = {};
const page = (props: Props) => {
return (
-
+
+ {/*
*/}
+
{/*
*/}
diff --git a/src/components/MultiDropdown.tsx b/src/components/MultiDropdown.tsx
index e3f0d7fe..3bf56b46 100644
--- a/src/components/MultiDropdown.tsx
+++ b/src/components/MultiDropdown.tsx
@@ -63,9 +63,9 @@ const MultipleDropdown: React.FC
= ({
diff --git a/src/components/categoryBar.tsx b/src/components/categoryBar.tsx
new file mode 100644
index 00000000..f5f65059
--- /dev/null
+++ b/src/components/categoryBar.tsx
@@ -0,0 +1,175 @@
+import React from "react";
+
+type CategoryBarProps = {
+ event: string;
+ selected: string;
+ setSelected: (item: string) => void;
+ view: string;
+ setView: (viewType: string) => void;
+};
+
+const CategoryBar: React.FC = ({
+ event,
+ selected,
+ setSelected,
+ view,
+ setView,
+}) => {
+ const handleSelect = (item: string) => {
+ setSelected(item);
+ };
+
+ const handleViewSelect = (viewType: string) => {
+ setView(viewType);
+ };
+
+ return (
+
+
+ {event &&
Home/{event}/SearchResult }
+
+ {/* Left section - Venues list */}
+
+ {["Venues 1", "Venues 2", "Venues 3", "Venues 4", "Venues 5"].map(
+ (venue, index) => (
+ handleSelect(venue)}
+ >
+ {venue}
+
+ ),
+ )}
+
+
+ {/* Right section - View options and sort */}
+