chore: setup project for production

This commit is contained in:
afnaann
2025-02-19 17:00:55 +05:30
commit 12caeee710
271 changed files with 16199 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
import React from 'react'
const AboutUsTopBanner = () => {
return (
<div className='min-h-[30vh] text-[#b68d40] bg-[#122620] flex flex-col justify-center items-center'>
<h1 className=' sm:text-2xl text-sm sm:w-3/5 text-center mx-auto'>&quot;Rudraksha is merely a seed for some and for some it is the majestic bead that changed their life. It is therefore the way you wear, energize and select the Rudraksha that makes the difference.&quot;</h1>
<h2 className='sm:text-sm text-xs'>- Late Mr. Balaram Khatiwada (Founding Father, Gupta Rudraksha)</h2>
</div>
)
}
export default AboutUsTopBanner

View File

@@ -0,0 +1,137 @@
import Image from "next/image";
import React from "react";
const AboutUsSecondBanner = () => {
return (
<>
<div className="flex gap-4 flex-col md:flex-row w-full max-w-6xl mx-auto p-4 sm:py-5 min-h-[70vh]">
<div className="w-full md:w-1/2 mb-4 md:mb-0 md:mr-4">
<Image
src="/about-us/img-one.jpg"
alt="Random placeholder image"
layout="responsive" // Ensures responsiveness based on parent container
width={1920}
height={400}
className="rounded-lg shadow-md object-cover"
/>
</div>
<div className="w-full ">
<h2 className="sm:text-4xl font-bold mb-4 tracking-wider ">1960s</h2>
<h2 className="text-[#AC8C6B] text-2xl font-bold">
Late Mr. Balaram Khatiwada
</h2>
<p className="mb-4 w-full">
In the late 1960s, Mr. Balaram Khatiwada who used to be a priest at
the Pashupatinath temple started Gupta Rudraksha as a shop which
sold flowers, Rudraksha and Saligrams to the devotees who visited
Pashupatinath temple.What differentiated Gupta Rudraksha from other
vendors is our founding father&apos;s commitment to authenticity and
his way of treating customers as family members.
</p>
<h2 className="text-[#AC8C6B] text-2xl font-bold">
Cultural Expansion
</h2>
<p>
Till this date, we carry this culture and have increased the size of
our family to thousands of customers from more than 160 countries.
Furthermore, Mr. Balaram being a vedic scholar himself believed that
each Rudraksha must be energized with the touch of Lord
Pashupatinath to deliver maximum benefit to the wearer.
</p>
</div>
</div>
{/* second section */}
<div className="flex gap-4 flex-col-reverse md:flex-row w-full max-w-6xl mx-auto p-4 sm:py-5 min-h-[70vh]">
<div className="w-full ">
<h2 className="sm:text-4xl font-bold mb-4 tracking-wider ">
1990s-2000s
</h2>
<h2 className="text-[#AC8C6B] text-2xl font-bold">
Mr. Mukunda Khatiwada&apos;s Involvement:
</h2>
<li className="mb-4 w-full py-2">
Mr. Mukunda observes the exploitation of Rudraksha and the spread of
myths about it on the internet.
</li>
<h2 className="text-[#AC8C6B] text-2xl font-bold">
Exploitation and Myths
</h2>
<li className="mb-4 w-full py-2">
Mr. Mukunda, as seen in an image with Late Mrs. Laxmi Khatiwada,
gets involved in the family business from a very young age. He is
taught by his father about Rudraksha since the age of 5.
</li>
<h2 className="text-[#AC8C6B] text-2xl font-bold">
Leading Online Store
</h2>
<li className="mb-4 w-full py-2">
Mr. Mukunda Khatiwada launches Gupta Rudraksha as an online store
and aims to ensure seekers of authentic Rudraksha are provided with
genuine products and to preserve traditional practices.
</li>
<li className="mb-4 w-full">
Gupta Rudraksha becomes the leading online store, the only one based
in Nepal offering Rudraksha energized in the traditional fashion at
Pashupatinath Temple.
</li>
</div>
<div className="w-full md:w-1/2 mb-4 md:mb-0 md:mr-4">
<Image
src="/about-us/img-two.jpg"
alt="Random placeholder image"
layout="responsive"
width={1920}
height={400}
className="object-cover rounded-lg shadow-md"
/>
</div>
</div>
{/* third section */}
<div className="flex gap-4 flex-col md:flex-row w-full max-w-6xl mx-auto p-4 sm:py-5 min-h-[70vh]">
<div className="w-full md:w-1/2 mb-4 md:mb-0 md:mr-4">
<Image
src="/about-us/img-three.jpg"
alt="Random placeholder image"
layout="responsive"
width={1920}
height={400}
className="object-cover rounded-lg shadow-md"
/>
</div>
<div className="w-full ">
<h2 className="sm:text-4xl font-bold mb-4 tracking-wider ">
Present
</h2>
<h2 className="text-[#AC8C6B] text-2xl font-bold">Global Reach</h2>
<li className="mb-1 w-full ">
Gupta Rudraksha supplies 90% of all Gupta Rudraksha globally.
</li>
<li className="mb-1 w-full ">
The largest seller of Indra Mala (1-21 Mukhi) in the world.
</li>
<li className="mb-4 w-full ">
Boasts the largest collection of Gupta Rudraksha and Shaligram
globally.
</li>
<h2 className="text-[#AC8C6B] text-2xl font-bold">Clientele</h2>
<li className="my-3">
Mr. Mukunda Khatiwada has provided Rudraksha to various celebrities,
business tycoons, yogis, gurus, and individuals from various walks
of life.
</li>
<h2 className="text-[#AC8C6B] text-2xl font-bold">
Continued Legacy
</h2>
<li className="my-3">
Gupta Rudraksha continues to uphold the values of authenticity,
tradition, and customer-centricity established by Mr. Balaram
Khatiwada..
</li>
</div>
</div>
</>
);
};
export default AboutUsSecondBanner;

View File

@@ -0,0 +1,82 @@
'use client'
import MainContext from "@/app/contexts/mainContext";
import authAxios from "@/utils/axios";
import Link from "next/link";
import { useRouter } from "next/navigation";
import React, { useContext } from "react";
import toast from "react-hot-toast";
const AccountSidebar = () => {
const router = useRouter()
const { setToken } = useContext(MainContext)
const logoutFn = async () => {
const response = await authAxios.post('/account/logout/')
if (response.status == 200) {
localStorage.removeItem('token')
setToken(null)
toast.success(response.data.message)
router.push('/')
}
console.log(response)
}
return (
<aside className="bg-white shadow-md overflow-x-auto md:w-64 md:min-h-screen">
<div className="flex md:flex-col">
<nav className="flex md:flex-col whitespace-nowrap">
<Link
href="/accounts/profile"
className="block py-2 px-4 text-gray-700 hover:bg-gray-200"
>
<span className="inline-block mr-2">👤</span> My profile
</Link>
<Link
href="/accounts/profile/orders"
className="block py-2 px-4 text-gray-700 hover:bg-gray-200"
>
<span className="inline-block mr-2">📦</span> Orders{" "}
</Link>
{/* <Link
href="/accounts/profile/addresses"
className="block py-2 px-4 text-gray-700 hover:bg-gray-200"
>
<span className="inline-block mr-2">📍</span> Addresses{" "}
<span className="ml-2 inline-block bg-gray-200 rounded-full px-2 py-1 text-xs">
1
</span>
</Link> */}
<Link
href="/accounts/profile/change-password"
className="block py-2 px-4 text-gray-700 hover:bg-gray-200"
>
<span className="inline-block mr-2">🔑</span> Change password
</Link>
<button
onClick={()=> logoutFn()}
className="block py-2 px-4 text-gray-700 hover:bg-gray-200 pr-80"
>
<span className="inline-block mr-2">🚪</span> Logout
</button>
</nav>
</div>
<style jsx>{`
@media (max-width: 768px) {
aside {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
aside::-webkit-scrollbar {
display: none;
}
aside {
-ms-overflow-style: none;
scrollbar-width: none;
}
}
`}</style>
</aside>
);
};
export default AccountSidebar;

View File

@@ -0,0 +1,193 @@
'use client'
import { useState } from 'react';
import authAxios from '@/utils/axios';
import toast from 'react-hot-toast';
import { useRouter } from 'next/navigation';
const AddNewAddress = () => {
const [formData, setFormData] = useState({
first_name: '',
last_name: '',
company: '',
address: '',
apartment: '',
city: '',
country: '',
zipcode: '',
phone: ''
});
const router = useRouter();
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError('');
try {
const response = await authAxios.post('/account/addresses/', formData);
toast.success('Address added successfully')
router.push('/accounts/profile/addresses')
// Handle success (e.g., redirect or show success message)
console.log('Address added successfully:', response.data);
} catch (err) {
setError(err.response?.data?.message || 'Failed to add address');
} finally {
setLoading(false);
}
};
return (
<div className="bg-white p-6 rounded-lg shadow-md">
<h2 className="text-2xl font-semibold mb-6">Add a new address</h2>
{error && <div className="mb-4 text-red-500">{error}</div>}
<form onSubmit={handleSubmit}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label htmlFor="first_name" className="block text-sm font-medium text-gray-700 mb-1">First name</label>
<input
type="text"
id="first_name"
name="first_name"
value={formData.first_name}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
<div>
<label htmlFor="last_name" className="block text-sm font-medium text-gray-700 mb-1">Last name</label>
<input
type="text"
id="last_name"
name="last_name"
value={formData.last_name}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
</div>
<div className="mt-4">
<label htmlFor="company" className="block text-sm font-medium text-gray-700 mb-1">Company</label>
<input
type="text"
id="company"
name="company"
value={formData.company}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
<div className="mt-4">
<label htmlFor="address" className="block text-sm font-medium text-gray-700 mb-1">Address</label>
<input
type="text"
id="address"
name="address"
value={formData.address}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
<div className="mt-4">
<label htmlFor="apartment" className="block text-sm font-medium text-gray-700 mb-1">Apartment, suite, etc.</label>
<input
type="text"
id="apartment"
name="apartment"
value={formData.apartment}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
<div className="mt-4">
<label htmlFor="city" className="block text-sm font-medium text-gray-700 mb-1">City</label>
<input
type="text"
id="city"
name="city"
value={formData.city}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
<div className="mt-4">
<label htmlFor="country" className="block text-sm font-medium text-gray-700 mb-1">Country/Region</label>
<select
id="country"
name="country"
value={formData.country}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
>
<option value="">Select a country</option>
<option value="IN">India</option>
</select>
</div>
<div className="mt-4">
<label htmlFor="zipcode" className="block text-sm font-medium text-gray-700 mb-1">Postal/Zip Code</label>
<input
type="text"
id="zipcode"
name="zipcode"
value={formData.zipcode}
onChange={handleChange}
className="w-full p-2 border border-gray-300 rounded"
/>
</div>
<div className="mt-4">
<label htmlFor="phone" className="block text-sm font-medium text-gray-700 mb-1">Phone</label>
<div className="flex">
<select className="p-2 border border-gray-300 rounded-l" style={{width: '80px'}}>
<option value="IN">🇮🇳 +91</option>
</select>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
className="flex-grow p-2 border border-gray-300 rounded-r"
/>
</div>
</div>
<div className="mt-6 flex justify-end space-x-4">
<button
type="button"
className="px-4 py-2 border border-gray-300 rounded text-gray-700 hover:bg-gray-50"
>
Cancel
</button>
<button
type="submit"
disabled={loading}
className="px-4 py-2 bg-[#96724f] text-white rounded hover:bg-[#AC8C6B] disabled:opacity-50"
>
{loading ? 'Submitting...' : 'Submit'}
</button>
</div>
</form>
</div>
);
};
export default AddNewAddress;

View File

@@ -0,0 +1,95 @@
'use client'
import authAxios from '@/utils/axios';
import { MapPin, Edit, Trash2 } from 'lucide-react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import React, { useEffect, useState } from 'react';
const Addresses = () => {
const [addresses, setAddresses] = useState([]);
const [error, setError] = useState('');
const [isDeleting, setIsDeleting] = useState(false);
const router = useRouter();
const fetchAddresses = async () => {
try {
const response = await authAxios.get('/account/addresses/');
setAddresses(response.data);
} catch (error) {
setError('Failed to fetch addresses');
console.error(error);
}
};
const handleEdit = (id) => {
router.push(`/accounts/profile/addresses/${id}`);
};
const handleDelete = async (id) => {
if (!window.confirm('Are you sure you want to delete this address?')) return;
setIsDeleting(true);
try {
await authAxios.delete(`/account/addresses/${id}/`);
setAddresses(addresses.filter(address => address.id !== id));
} catch (error) {
setError('Failed to delete address');
console.error(error);
} finally {
setIsDeleting(false);
}
};
useEffect(() => {
fetchAddresses();
}, []);
return (
<div>
<h1 className="text-3xl font-semibold border-b pb-4 text-zinc-700">Address</h1>
<Link href='/accounts/profile/new-address'>
<div className='p-6 hover:border-yellow-400 border rounded-md w-fit mt-4 flex justify-center items-center flex-col'>
<MapPin className='text-[#AC8C6B]' />
<h1>Add new address</h1>
</div>
</Link>
{error && <p className="text-red-500 mt-4">{error}</p>}
{addresses.map((address) => (
<div key={address.id} className='border sm:p-6 p-2 w-3/6 mt-4 border-slate-800 relative'>
<div className="absolute top-4 right-4 flex gap-2">
<button
onClick={() => handleEdit(address.id)}
className="p-2 text-blue-600 hover:bg-blue-50 rounded-full"
disabled={isDeleting}
>
<Edit size={18} />
</button>
<button
onClick={() => handleDelete(address.id)}
className="p-2 text-red-600 hover:bg-red-50 rounded-full"
disabled={isDeleting}
>
<Trash2 size={18} />
</button>
</div>
<h2 className='text-lg font-bold'>{address.first_name} {address.last_name}</h2>
{address.company && <p className='text-md font-medium'>{address.company}</p>}
<p className='text-md'>
{address.address}
{address.apartment && `, ${address.apartment}`}
</p>
<p className='text-md'>
{address.city}, {address.country} - {address.zipcode}
</p>
<p className='text-md font-semibold'>Phone: {address.phone}</p>
</div>
))}
</div>
);
};
export default Addresses;

View File

@@ -0,0 +1,209 @@
'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import authAxios from '@/utils/axios';
const EditProfile = () => {
const [profile, setProfile] = useState({
email: '',
first_name: '',
last_name: '',
phone: '',
accepts_marketing: '',
birth_day: '',
gender: '',
profile_pic: null,
});
const router = useRouter();
useEffect(() => {
const fetchProfileData = async () => {
const response = await authAxios.get('/account/profile');
console.log(response)
setProfile(response.data);
};
fetchProfileData();
}, []);
const handleChange = (e) => {
const { name, value } = e.target;
setProfile((prevProfile) => ({
...prevProfile,
[name]: value,
}));
};
const handleCheckboxChange = (e) => {
setProfile((prevProfile) => ({
...prevProfile,
accepts_marketing: e.target.checked ? 'Yes' : 'No',
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
console.log(profile);
const formData = new FormData();
formData.append('email', profile.email);
formData.append('first_name', profile.first_name);
formData.append('last_name', profile.last_name);
formData.append('phone', profile.phone);
formData.append('accepts_marketing', profile.accepts_marketing);
formData.append('birth_day', profile.birth_day);
formData.append('gender', profile.gender);
if (profile.profile_pic && profile.profile_pic instanceof File) {
console.log('hello')
formData.append('profile_pic', profile.profile_pic);
}
try {
const response = await authAxios.patch('/account/profile-update/', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
console.log(response)
if (response.status === 200) {
router.push('/accounts/profile');
} else {
alert('Failed to update profile');
}
} catch (error) {
console.error('Error updating profile:', error);
alert('An error occurred while updating the profile.');
}
};
return (
<div className="bg-white p-6 rounded-lg shadow-md">
<h2 className="text-2xl font-semibold mb-6">Edit Profile</h2>
<form onSubmit={handleSubmit}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label htmlFor="firstName" className="block text-sm font-medium text-gray-700 mb-1">First name</label>
<input
type="text"
id="firstName"
name="first_name"
className="w-full p-2 border border-gray-300 rounded"
value={profile.first_name || ''}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="lastName" className="block text-sm font-medium text-gray-700 mb-1">Last name</label>
<input
type="text"
id="lastName"
name="last_name"
className="w-full p-2 border border-gray-300 rounded"
value={profile.last_name || ''}
onChange={handleChange}
/>
</div>
</div>
<div className="mt-4">
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input
type="email"
id="email"
name="email"
className="w-full p-2 border border-gray-300 rounded"
value={profile.email || ''}
onChange={handleChange}
/>
</div>
<div className="mt-4">
<label htmlFor="phone" className="block text-sm font-medium text-gray-700 mb-1">Phone</label>
<div className="flex">
<select className="p-2 border border-gray-300 rounded-l" style={{ width: '80px' }}>
<option value="IN" className='w-10 '>+91</option>
</select>
<input
type="tel"
id="phone"
name="phone"
className="flex-grow p-2 border border-gray-300 rounded-r"
value={profile.phone || ''}
onChange={handleChange}
/>
</div>
</div>
<div className="mt-4">
<label htmlFor="birthDay" className="block text-sm font-medium text-gray-700 mb-1">Birth Date</label>
<input
type="date"
id="birthDay"
name="birth_day"
className="w-full p-2 border border-gray-300 rounded"
value={profile.birth_day || ''}
onChange={handleChange}
/>
</div>
<div className="mt-4">
<label htmlFor="gender" className="block text-sm font-medium text-gray-700 mb-1">Gender</label>
<select
id="gender"
name="gender"
className="w-full p-2 border border-gray-300 rounded"
value={profile.gender || ''}
onChange={handleChange}
>
<option value="">Select Gender</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</select>
</div>
<div className="mt-4">
<label htmlFor="profilePic" className="block text-sm font-medium text-gray-700 mb-1">Profile Picture</label>
<input
type="file"
id="profilePic"
name="profile_pic"
className="w-full p-2 border border-gray-300 rounded"
onChange={(e) => setProfile({ ...profile, profile_pic: e.target.files[0] })}
/>
</div>
<div className="mt-4">
<label className="inline-flex items-center">
<input
type="checkbox"
className="form-checkbox"
checked={profile.accepts_marketing === 'Yes'}
onChange={handleCheckboxChange}
/>
<span className="ml-2">Accepts Marketing</span>
</label>
</div>
<div className="mt-6 flex justify-end space-x-4">
<button
type="button"
onClick={() => router.push('/account/profile')}
className="px-4 py-2 border border-gray-300 rounded text-gray-700 hover:bg-gray-50"
>
Cancel
</button>
<button
type="submit"
className="px-4 py-2 bg-[#96724f] text-white rounded hover:bg-[#AC8C6B]"
>
Save Changes
</button>
</div>
</form>
</div>
);
};
export default EditProfile;

View File

@@ -0,0 +1,184 @@
"use client";
import React, { useState } from "react";
import { Card, CardHeader, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import Image from "next/image";
const BlogPost = ({ title, author, date, excerpt, imageUrl }) => (
<div className="mb-6 flex sm:flex-row flex-col">
<div className=" h-full bg-purple-100 sm:w-1/2">
<Link href={`/blogs/blog/${title}`}>
<Image
src={imageUrl}
alt={title || "Image"}
className="object-cover rounded-md"
layout="responsive"
width={500}
height={300}
/>
</Link>
</div>
<div className="sm:w-2/3 p-4">
<Link href={`/blogs/blog/${title}`}>
<h3 className="text-xl sm:text-2xl font-bold">{title}</h3>
</Link>
<p className="text-sm sm:text-lg text-gray-500 mb-2">
{author} | {date}
</p>
<p className="text-sm">{excerpt}</p>
</div>
</div>
);
const PopularArticle = ({ title, author, date }) => (
<div className="mb-4">
<h4 className="font-semibold">{title}</h4>
<p className="text-sm text-gray-500">
{author} | {date}
</p>
</div>
);
const BlogHome = () => {
const [currentPage, setCurrentPage] = useState(1);
const postsPerPage = 3;
const recentBlogPosts = [
{
title: "Benefits of Wearing Rudraksha Mala",
author: "Gupta Rudraksha",
date: "29 August, 2024",
excerpt:
"Rudraksha are sacred beads of great significance in Hinduism and various spiritual practices. The term Rudraksha combines two Sanskrit words: 'Rudra,' another name for Lord Sh...",
imageUrl: "/blogs/significance-of-dhanteras.webp",
},
{
title: "Shravan Maas for Spiritual Growth and Divine Connection",
author: "Gupta Rudraksha",
date: "04 September, 2024",
excerpt:
"Shrawan Mass, a sacred month in the Hindu calendar, holds deep spiritual significance for millions of devotees. But what exactly is Shravan Maas, and why is it so important? Let...",
imageUrl: "/blogs/navaratri-siginificance.webp",
},
{
title: "The Complete Guide to Rudraksha Energization",
author: "Gupta Rudraksha",
date: "28 August, 2024",
excerpt:
"For centuries, Rudraksha beads have been valued not only for their aesthetic beauty, but also for their powerful spiritual and healing properties. Whether you're a seasoned prac...",
imageUrl: "/blogs/rudraksha-pran-pratishtha-pooja.webp",
},
{
title: "Strengthening Planetary Forces with Rudraksha",
author: "Gupta Rudraksha",
date: "26 April, 2024",
excerpt:
"In the vast universe, planets hold immense power over our lives, influencing everything from our moods to our destinies. However, Rudraksha beads, ancient treasures from the ear...",
imageUrl: "/api/placeholder/300/200",
},
];
const popularArticles = [
{
title: "Dhanteras Significance and How Rudraksha Brings Prosperity",
author: "Gupta Rudraksha",
date: "30 September, 2024",
},
{
title:
"Certified Rudraksha: Nepal's 1st ISO 9001:2015 Certified Organization",
author: "Gupta Admin",
date: "30 September, 2024",
},
];
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = recentBlogPosts.slice(indexOfFirstPost, indexOfLastPost);
const paginate = (pageNumber) => setCurrentPage(pageNumber);
return (
<div className="container max-w-8xl mx-auto sm:px-20 px-3 ">
<h1 className="sm:text-5xl pt-3 text-3xl font-bold mb-8">
Insights from Gupta Rudraksha
</h1>
<p className="sm:text-2xl text-lg ">
Explore our latest articles on the spiritual, cultural, and healing
aspects
</p>
{/* top container for one blog card */}
<dir className="min-h-[30vh] flex sm:flex-row flex-col-reverse">
<div className="mb-6 flex sm:flex-row flex-col">
<div className="h-full bg-purple-100">
<Link href={`/blogs/blog/`}>
<Image
src="/blogs/significance-of-dhanteras.webp"
alt="images blog"
layout="intrinsic"
width={600}
height={400}
className="object-cover rounded-md"
/>
</Link>
</div>
<div className="sm:w-2/3 p-4">
<Link href={`/blogs/blog/`}>
<h3 className="text-xl sm:text-2xl font-bold">
Dhanteras Significance and How Rudraksha Brings Prosperity and
Protection
</h3>
</Link>
<p className="text-sm sm:text-lg text-gray-500 mb-2">
Gupta Rudraksha | 30 September, 2024
</p>
<p className="text-sm py-4 line-clamp-2">
Dhanteras, the first day of Diwali festival, marks a unique
celebration of wealth and prosperity in Hindu tradition. As the
name suggests - &apos;Dhan&apos; meaning wealth and
&apos;Teras&apos; ref
</p>
</div>
</div>
<div className="w-full lg:w-1/3 px-4">
<h2 className="text-2xl font-bold mb-4">Popular Articles</h2>
{popularArticles.map((article, index) => (
<PopularArticle key={index} {...article} />
))}
</div>
</dir>
<div className="flex flex-wrap -mx-4">
<div className="w-full lg:w-2/3 px-4">
<h2 className="sm:text-4xl text-2xl font-bold mb-4">Recent Blogs</h2>
{currentPosts.map((post, index) => (
<BlogPost key={index} {...post} />
))}
<div className="flex justify-center space-x-2 mb-8 items-center pt-6">
{[...Array(Math.ceil(recentBlogPosts.length / postsPerPage))].map(
(_, index) => (
<Button
key={index}
onClick={() => paginate(index + 1)}
variant={currentPage === index + 1 ? "default" : "outline"}
>
{index + 1}
</Button>
)
)}
</div>
</div>
<div className="w-full lg:w-1/3 px-4">
<h2 className="text-2xl font-bold mb-4">Popular Articles</h2>
{popularArticles.map((article, index) => (
<PopularArticle key={index} {...article} />
))}
</div>
</div>
</div>
);
};
export default BlogHome;

View File

@@ -0,0 +1,47 @@
"use client";
import Image from "next/image";
import React, { useEffect, useState } from "react";
import "./blog.css";
const SingleBlog = () => {
const [blogResData, setResData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("/api/blog");
const blog = await response.json();
setResData(blog.blogdata);
} catch (error) {
console.error("Error fetching blog data:", error);
}
};
fetchData();
}, []);
return (
<div className="max-w-4xl mx-auto p-5 space-y-6 bg-white shadow-lg rounded-lg">
{/* Blog Image */}
<div className="w-full flex justify-center">
<Image
src={"/blogs/significance-of-dhanteras.webp"}
height={500}
width={800}
alt="Blog Cover Image"
className="rounded-lg object-cover"
/>
</div>
{/* Blog Content */}
<div className="prose lg:prose-xl mx-auto text-gray-800 leading-relaxed">
{blogResData ? (
<div dangerouslySetInnerHTML={{ __html: blogResData }} />
) : (
<p className="text-center text-gray-500">Loading blog content...</p>
)}
</div>
</div>
);
};
export default SingleBlog;

187
components/blog/blog.css Normal file
View File

@@ -0,0 +1,187 @@
/* General Blog Styles */
.blog-content {
font-family: 'Arial', sans-serif;
color: #333;
line-height: 1.7;
margin: 20px;
margin: 0 auto;
padding: 0 20px;
}
.blog-content h1 {
font-size: 2.5em;
margin-bottom: 20px;
color: #c0392b;
}
.blog-content h2 {
font-size: 2.2em;
margin-bottom: 18px;
color: #2980b9;
}
.blog-content h3 {
font-size: 1.9em;
margin-bottom: 12px;
color: #27ae60;
}
.blog-content p {
font-size: 1.2em;
margin-bottom: 20px;
color: #555;
}
.blog-content ul {
list-style-type: disc;
padding-left: 25px;
margin-bottom: 20px;
}
.blog-content li {
margin-bottom: 10px;
font-size: 1.1em;
}
/* Section Backgrounds and Styles */
.intro, .festival, .rudraksha, .recommendations, .rituals, .conclusion {
padding: 20px;
margin-bottom: 25px;
border-left: 6px solid;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.intro {
background-color: #f9f9f9;
border-color: #c0392b;
}
.festival {
background-color: #ecf0f1;
border-color: #2980b9;
}
.rudraksha {
background-color: #fdfefe;
border-color: #8e44ad;
}
.recommendations {
background-color: #f1c40f;
border-color: #e67e22;
}
.rituals {
background-color: #f8f9f9;
border-color: #16a085;
}
.conclusion {
background-color: #f0f3f4;
border-color: #27ae60;
}
/* Responsive Styles */
@media (max-width: 1200px) {
.blog-content h1 {
font-size: 2.2em;
}
.blog-content h2 {
font-size: 2em;
}
.blog-content h3 {
font-size: 1.75em;
}
.blog-content p {
font-size: 1.15em;
}
.blog-content {
padding: 0 15px;
}
.intro, .festival, .rudraksha, .recommendations, .rituals, .conclusion {
padding: 18px;
}
}
@media (max-width: 992px) {
.blog-content h1 {
font-size: 2em;
}
.blog-content h2 {
font-size: 1.8em;
}
.blog-content h3 {
font-size: 1.6em;
}
.blog-content p {
font-size: 1.1em;
}
.blog-content {
padding: 0 12px;
}
.intro, .festival, .rudraksha, .recommendations, .rituals, .conclusion {
padding: 15px;
}
}
@media (max-width: 768px) {
.blog-content h1 {
font-size: 1.8em;
}
.blog-content h2 {
font-size: 1.6em;
}
.blog-content h3 {
font-size: 1.4em;
}
.blog-content p {
font-size: 1.05em;
}
.blog-content {
padding: 0 10px;
}
.intro, .festival, .rudraksha, .recommendations, .rituals, .conclusion {
padding: 12px;
}
}
@media (max-width: 576px) {
.blog-content h1 {
font-size: 1.6em;
}
.blog-content h2 {
font-size: 1.4em;
}
.blog-content h3 {
font-size: 1.2em;
}
.blog-content p {
font-size: 1em;
}
.blog-content {
padding: 0 8px;
}
.intro, .festival, .rudraksha, .recommendations, .rituals, .conclusion {
padding: 10px;
}
}

View File

@@ -0,0 +1,35 @@
import Image from "next/image";
import React from "react";
const BuyRudrakshaOne = () => {
return (
<div className="h-[50vh] sm:flex justify-between w-full items-center gap-7 hidden bg-[url('/sidhi-mala/Artboard_1_bf5ccd46-7152-4355-82a8-9e9f27c1bfc2.jpg')]">
<div className="w-[100%] flex justify-end">
<Image
src="/sidhi-mala/sidhha-feature-2_medium.png"
alt=""
layout="intrinsic"
className="object-contain rounded-md"
/>{" "}
</div>
<div className="flex flex-col gap-7 text-white">
<h1 className="text-4xl font-serif">Rudraksha</h1>
<p className="w-3/4 text-lg">
Rudraksha Gupta Rudraksha offers an extensive collection of A+ Grade,
high-quality, and X-ray certified Gupta Rudraksha, ranging from 1
Mukhi to 26 Mukhi, along with rare beads like Gaurishankar, Ganesha,
Garbha Gauri, and Trijuti Rudraksha. Rudraksha has been used as a tool
for professional and spiritual transformation since the beginning of
the time. Sanatana Dharma regards rudraksha as the most potent and
powerful tool to purify one&apos;s Karma and attract prosperity. As
the world&apos;s largest supplier of authentic Gupta Rudraksha, Gupta
Rudraksha ensures each bead is certified for authenticity and
energized for effectiveness following Vedic guidelines. Discover the
power of original Gupta Rudraksha at Gupta Rudraksha.
</p>
</div>
</div>
);
};
export default BuyRudrakshaOne;

View File

@@ -0,0 +1,55 @@
import Link from "next/link";
import React from "react";
const PopularRudrakshaCombination = () => {
return (
<div className="bg-[#EDE8E0] min-h-screen p-4">
<h1 className="sm:pt-14 pb-8 font-serif mt-4 sm:text-6xl text-2xl text-zinc-800 text-center">
Popular Rudraksha Combination
</h1>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 sm:gap-4 gap-7">
<div className="text-white flex flex-col bg-[url('/buy-rudraksha/zodiac_combo_1x_1_f7d5771c-e186-4efe-93ec-f985fd30178d.webp')] justify-start sm:h-[300px] bg-cover bg-center bg-no-repeat w-full p-6">
<h1 className="sm:text-4xl sm:w-[30%] text-lg mb-3">
Zodiac Combination
</h1>
<Link href={"/collections/zodiac-combination"}>
<button className="px-4 py-4 border-none text-white border font-semibold bg-[#b68d40] ">
Explore Combination
</button>
</Link>
</div>
<div className="text-white flex flex-col justify-start sm:h-[300px] bg-cover bg-center w-full p-6 bg-[url('/buy-rudraksha/goals_aspirations_combo_1x_1_6da0bb78-1e20-4c48-b7a5-de4d6995b51c.webp')]">
<h1 className="sm:text-4xl sm:w-[60%] text-lg mb-3">Combination by Goals
and Aspirations</h1>
<Link href={"/collections/combination-by-goals-and-aspirations"}>
<button className="px-4 py-4 border-none text-white border font-semibold bg-[#b68d40] ">
Explore Combination
</button>
</Link>
</div>
<div className="text-white flex flex-col justify-start sm:h-[300px] bg-cover bg-center bg-no-repeat w-full p-6 bg-[url('/buy-rudraksha/maha_dasha_1x_1_e12fc2ae-e143-45fd-9199-33e0012f1b2c.webp')]">
<h1 className="sm:text-4xl sm:w-[50%] text-lg mb-3">Combination for
Maha Dasha</h1>
<Link href={"/collections/combination-for-maha-dasha"}>
<button className="px-4 py-4 border-none text-white border font-semibold bg-[#b68d40] ">
Explore Combination
</button>
</Link>
</div>
<div className="text-white flex flex-col justify-start sm:h-[300px] bg-cover bg-center w-full p-6 bg-no-repeat bg-[url('/buy-rudraksha/rudraksha_kavach_1x_1_1d5d5deb-91bb-4e92-9a42-76a7b84aef11.webp')]">
<h1 className="sm:text-4xl sm:w-[30%] text-lg mb-3">Rudraksha Kavach</h1>
<Link href={"/collections/rudraksha-kavach"}>
<button className="px-4 py-4 border-none text-white border font-semibold bg-[#b68d40] ">
Explore Combination
</button>
</Link>
</div>
</div>
</div>
);
};
export default PopularRudrakshaCombination;

View File

@@ -0,0 +1,77 @@
import ZodiacBasedSignClient from "./ZodiacBasedSignClient";
const zodiacSigns = [
{
name: "Aries",
rudraksha: { price: 200.0, type: "Medium", mukhi: 13 },
gaurishankar: { price: 200.0, type: "Medium", mukhi: 13 },
},
{
name: "Gemini",
rudraksha: { price: 65.0, type: "Medium", mukhi: 6 },
gaurishankar: { price: 200.0, type: "Collector", mukhi: 13 },
},
{
name: "Leo",
rudraksha: { price: 160.0, type: "Medium", mukhi: 12 },
gaurishankar: { price: 200.0, type: "Collector", mukhi: 12 },
},
{
name: "Libra",
rudraksha: { price: 160.0, type: "Medium", mukhi: 12 },
gaurishankar: { price: 400.0, type: "Collector", mukhi: 15 },
},
{
name: "Sagittarius",
rudraksha: { price: 65.0, type: "Medium", mukhi: 5 },
gaurishankar: { price: 400.0, type: "Collector", mukhi: 14 },
},
{
name: "Taurus",
rudraksha: { price: 160.0, type: "Medium", mukhi: 12 },
gaurishankar: { price: 400.0, type: "Collector", mukhi: 15 },
},
{
name: "Cancer",
rudraksha: { price: 300.0, type: "Medium", mukhi: 2 },
gaurishankar: { price: 200.0, type: "Collector", mukhi: 10 },
},
{
name: "Virgo",
rudraksha: { price: 55.0, type: "Medium", mukhi: 6 },
gaurishankar: { price: 200.0, type: "Collector", mukhi: 13 },
},
{
name: "Scorpio",
rudraksha: { price: 200.0, type: "Medium", mukhi: 13 },
gaurishankar: { price: 200.0, type: "Collector", mukhi: 13 },
},
{
name: "Capricorn",
rudraksha: { price: null, type: "Medium", mukhi: null },
gaurishankar: { price: 400.0, type: "Collector", mukhi: 14 },
},
{
name: "Aquarius",
rudraksha: { price: null, type: "Medium", mukhi: null },
gaurishankar: { price: 400.0, type: "Collector", mukhi: 14 },
},
{
name: "Pisces",
rudraksha: { price: 65.0, type: "Medium", mukhi: 5 },
gaurishankar: { price: 400.0, type: "Collector", mukhi: 14 },
},
];
const ZodiacBasedSign = () => {
return (
<div className="min-h-screen py-10 bg-slate-50">
<h1 className="text-4xl font-serif text-zinc-800 text-center mb-10">
Rudraksha Based On Zodiac Signs
</h1>
<ZodiacBasedSignClient zodiacSigns={zodiacSigns} />
</div>
);
};
export default ZodiacBasedSign;

View File

@@ -0,0 +1,70 @@
"use client";
import Link from "next/link";
import React from "react";
const ZodiacBasedSignClient = ({ zodiacSigns }) => {
return (
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6">
{zodiacSigns.map((sign) => (
<div
key={sign.name}
className="border border-[#AC8C6B] overflow-hidden"
>
<div className="p-4 flex sm:flex-row flex-col sm:gap-0 gap-3">
<div className="sm:w-1/3 flex items-center justify-center">
<h2 className="sm:text-2xl uppercase font-serif text-yellow-800">
{sign.name}
</h2>
</div>
<div className="sm:w-2/3 grid grid-cols-2 gap-2">
<MiniCard
price={sign.rudraksha.price}
type={sign.rudraksha.type}
mukhi={sign.rudraksha.mukhi}
name="Rudraksha"
/>
<MiniCard
price={sign.gaurishankar.price}
type={sign.gaurishankar.type}
mukhi={sign.gaurishankar.mukhi}
name="Gauri Shankar"
/>
</div>
</div>
</div>
))}
</div>
</div>
);
};
const MiniCard = ({ price, type, mukhi, name }) => (
<div className="bg-pink-100 p-2 rounded">
<Link href={`/products/${mukhi}-mukhi-${name}`}>
{price !== null ? (
<p className="text-sm sm:text-[17px] my-2 w-1/2 font-medium text-zinc-700">
${price.toFixed(2)} | {type}
</p>
) : (
<p className="text-sm font-medium text-zinc-700">
Price not available | {type}
</p>
)}
</Link>
<Link href={`/products/${mukhi}-mukhi-${name}`}>
{mukhi !== null ? (
<p className="text-sm sm:text-[17px] w-1/2 text-zinc-600">
{mukhi} Mukhi {name}
</p>
) : (
<p className="text-sm sm:text-[17px] my-2 w-1/2 text-zinc-600">
Mukhi not specified | {name}
</p>
)}
</Link>
</div>
);
export default ZodiacBasedSignClient;

View File

@@ -0,0 +1,9 @@
import React from "react";
const CertificationBannerOne = () => {
return (
<div className="bg-[url('/certification/certification-one.jpg')] min-h-[50vh] bg-center bg-cover"></div>
);
};
export default CertificationBannerOne;

View File

@@ -0,0 +1,68 @@
'use client'
import { ChevronRight } from 'lucide-react';
import React, { useState } from 'react'
const CertificationBannerTwo = () => {
const [selectedInfo, setSelectedInfo] = useState(0);
const infoItems = [
{
title: "Introduction",
description: "Since 1973, Gupta Rudraksha has been committed to maintaining the highest quality standards for all its Rudraksha and Shaligram. To take our commitment to quality assurance even further, we have successfully complied with all the quality standards set forward by the International Organization for Standardization (ISO), and Gupta Rudraksha has been recognized as Nepal's first and only ISO 9001:2015 certified Rudraksha organization."
},
{
title: "100% lifetime Moneyback Authenticity Guarantee",
description: "Gupta Rudraksha is dedicated to preserving the sacred and ancient tradition of Rudraksha while making it accessible to seekers worldwide. Our certification process reflects our unwavering commitment to authenticity, quality, and the spiritual well-being of our customers.Choose Rudraksha beads with the Gupta Rudraksha certification, and embark on your spiritual journey with confidence and trust."
},
{
title:"Book Premium Rudraksha Prana Pratistha Pooja",
description:"All Our Pooja done based on your Birth Chart and your specific details following Vedic principles. Video Recording of the entire ceremony will be shared with you (Live Pooja is available upon request)."
}
];
const handleInfoClick = (index) => {
setSelectedInfo(index);
};
return (
<div className="bg-slate-50 p-4">
<h1 className="sm:text-5xl sm:mt-24 text-2xl font-serif text-center tracking-wide mb-12">
Gupta Rudraksha Information
</h1>
<div className="grid sm:grid-cols-3 gap-8">
<div className="flex flex-col gap-4 sm:pl-10">
{infoItems.map((item, index) => (
<div
key={index}
className="cursor-pointer"
onClick={() => handleInfoClick(index)}
>
<h2 className={`text-xl sm:my-4 ${selectedInfo === index ? 'text-yellow-700' : ''} hover:translate-x-4 hover:font-semibold hover:text-yellow-700 transition-all flex items-center`}>
{selectedInfo === index ? (
<ChevronRight className="mr-2" size={20} />
) : (
""
)}
{item.title}
</h2>
</div>
))}
</div>
<div className="sm:col-span-2">
{selectedInfo !== null && (
<div className="bg-white p-6">
<div className="flex flex-col gap-3 justify-start items-start">
<h1 className='sm:text-4xl text-xl font-semibold'>{infoItems[selectedInfo].title}</h1>
<p className="mb-4 mt-2 text-[1.05rem]">
{infoItems[selectedInfo].description}
</p>
</div>
</div>
)}
</div>
</div>
</div>
)
}
export default CertificationBannerTwo

View File

@@ -0,0 +1,81 @@
"use client";
import React, { useState } from "react";
import { X } from "lucide-react";
import Image from "next/image";
const CertificationGallerySection = () => {
const [selectedImage, setSelectedImage] = useState(null);
const images = [
"/certification/gallery10.jpeg",
"/certification/gallery5.png",
"/certification/gallery12.jpeg",
"/certification/gallery11.jpeg",
];
const handleImageClick = (index) => {
setSelectedImage(index);
};
const handleClosePopup = () => {
setSelectedImage(null);
};
return (
<div className="container mx-auto max-w-6xl px-4 py-8">
<h2 className="text-3xl sm:text-5xl font-bold mb-6 text-center">
Chamber of Commerce
</h2>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 mb-4">
{images.slice(0, 3).map((src, index) => (
<div key={index} className="aspect-w-1 aspect-h-1">
<Image
src={src}
alt={`Gallery image ${index + 1}`}
// layout="responsive"
width={500} // Adjust based on your desired image width
height={500} // Adjust based on your desired image height
className="object-cover w-full h-full cursor-pointer"
onClick={() => handleImageClick(index)}
/>
</div>
))}
</div>
<div className="aspect-w-4 aspect-h-2">
<Image
src={images[3]}
alt="Gallery image 5"
layout="responsive"
width={800} // Adjust based on your desired image width
height={400} // Adjust based on your desired image height
className="object-cover w-full h-full cursor-pointer"
onClick={() => handleImageClick(4)}
/>
</div>
{selectedImage !== null && (
<div className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50">
<div className="relative max-w-3xl w-full">
<Image
src={images[selectedImage]}
alt={`Gallery image ${selectedImage + 1}`}
width={1200} // Adjust based on your desired image width
height={800} // Adjust based on your desired image height
className="w-full h-auto"
/>
<button
onClick={handleClosePopup}
className="absolute top-4 right-4 text-yellow-400"
>
<X size={24} />
</button>
</div>
</div>
)}
</div>
);
};
export default CertificationGallerySection;

View File

@@ -0,0 +1,96 @@
"use client";
import Image from "next/image";
import React, { useState, useEffect } from "react";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import Link from "next/link";
import axios from "axios";
import { backendUrl } from "@/utils/axios";
const DEFAULT_IMAGE = "/sidhi-mala/Designer_30.png"; // Default image
const FaqCard = ({ params }) => {
const [faq, setFaq] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchFaq = async () => {
try {
const response = await axios.get(
`${backendUrl}/products/faq/${params.id}/`
);
setFaq(response.data);
} catch (err) {
setError("Failed to fetch FAQs. Please try again later.");
} finally {
setLoading(false);
}
};
fetchFaq();
}, [params.id]);
if (loading) {
return <p className="text-center text-xl mt-10">Loading FAQs...</p>;
}
if (error) {
return <p className="text-center text-red-600 mt-10">{error}</p>;
}
if (!faq || faq.length === 0) {
return <p className="text-center text-xl mt-10">No FAQs available.</p>;
}
const hasImage = faq.some((item) => item.image !== null);
const imageToShow = hasImage
? `${backendUrl}${faq.find((item) => item.image !== null).image}`
: DEFAULT_IMAGE;
return (
<div className="min-h-screen sm:block hidden bg-[#FFFFFF]">
<h1 className="sm:pt-14 pb-8 font-serif mt-4 sm:text-6xl text-2xl text-zinc-800 text-center">
Frequently Asked Questions
</h1>
<div className="min-h-[80%] flex">
<Image
src={imageToShow}
height={600}
width={400}
alt="FAQ Image"
className="h-[550px] w-[550px] ml-14"
/>
<div className="flex-1 p-8">
{faq.map((item, index) => (
<Accordion type="single" collapsible className="w-full" key={index}>
<AccordionItem value={item.question}>
<AccordionTrigger className="text-xl mb-5 font-semibold text-zinc-900 hover:no-underline">
{item.question}
</AccordionTrigger>
<AccordionContent className="text-zinc-700">
{item.answer}
</AccordionContent>
</AccordionItem>
</Accordion>
))}
</div>
</div>
<div className="h-[30vh] sm:block hidden m-9">
<h2 className="my-6 text-2xl font-semibold w-[350px]">
Quick Answers to Some Frequently Asked Questions.
</h2>
<Link href={"/pages/contact"}>
<button className="px-4 py-4 border font-semibold border-black">
Get Support
</button>
</Link>
</div>
</div>
);
};
export default FaqCard;

View File

@@ -0,0 +1,164 @@
"use client";
import { useState } from "react";
import { Mail, MapPin, Phone } from "lucide-react";
export default function ContactUs() {
const [message, setMessage] = useState({
name: "",
email: "",
phone: "",
message: "",
});
const handleChange = (e) => {
const { name, value } = e.target;
setMessage((prevState) => ({
...prevState,
[name]: value,
}));
};
const handleSubmit = (e) => {
e.preventDefault();
const whatsappNumber = "9779803287986";
const formattedMessage = `Name: ${message.name}%0AEmail: ${message.email}%0APhone: ${message.phone}%0AMessage: ${message.message}`;
const whatsappURL = `https://api.whatsapp.com/send?phone=${whatsappNumber}&text=${formattedMessage}`;
window.open(whatsappURL, "_blank");
setMessage({
name: "",
email: "",
phone: "",
message: "",
});
};
return (
<div className="min-h-screen">
<header className="text-slate-800 py-4 text-center md:text-start md:ml-40 lg:ml-80">
<h1 className="text-3xl md:text-4xl lg:text-5xl font-emilys font-semibold">
Contact Us
</h1>
<p className="mt-2 text-sm md:text-base">
Empowering Spiritual Connections - Feel Free to Connect with Us - Our
Doorway to Spiritual Assistance
</p>
</header>
<main className="container mx-auto px-4 py-8">
<div className="flex justify-center">
<div className="flex flex-wrap -mx-4 w-full max-w-7xl">
<div className="w-full lg:w-1/3 px-4 mb-8">
<div className="bg-white custom-border p-6">
<StoreInfo
title="Nepal Store"
address="Gupta Rudraksha, Dakshinamurti, Guru Mandir Marg, Kathmandu 44600, Nepal"
email="nepali.rudrakshabeads@gmail.com"
phone="+9779803287986"
/>
<StoreInfo
title="Malayasia Store"
address="14A, Villa Laman Tasik, Bandar Sri Permaisuri, Cheras 56000 Kuala Lumpur, Malaysia"
email="nepali.rudrakshabeads@gmail.com"
/>
<StoreInfo
title="Gupta Rudraksha India"
address="Sector 62, Noida, Uttar Pradesh-201301"
email="nepali.rudrakshabeads@gmail.com"
phone="+919431828698"
/>
</div>
</div>
<div className="w-full lg:w-2/3 px-4 mb-8">
<div className="h-full custom-border p-6">
<h2 className="text-4xl text-black font-semibold mb-4">
Connecting Souls
</h2>
<p className="mb-4 text-lg">
Reach Out, Let&apos;s Share Spiritual Moments
</p>
<form onSubmit={handleSubmit}>
<div className="flex flex-col gap-4 sm:flex-row">
<input
type="text"
name="name"
className="sm:w-full p-3 border outline-none"
placeholder="Full Name"
value={message.name}
onChange={handleChange}
/>
<input
type="email"
name="email"
className="sm:w-full p-3 border outline-none"
placeholder="Email"
value={message.email}
onChange={handleChange}
/>
</div>
<input
type="text"
name="phone"
className="w-full p-3 border outline-none my-3"
placeholder="Phone Number"
value={message.phone}
onChange={handleChange}
/>
<textarea
name="message"
className="w-full p-2 border border-gray-300 rounded mb-4"
rows="6"
value={message.message}
onChange={handleChange}
placeholder="Your message"
/>
<div className="flex justify-center">
<button
type="submit"
className="bg-[#c08c38] uppercase text-white py-3 px-6 hover:bg-[#7D6032] transition duration-300"
>
Send Message
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
</div>
);
}
function StoreInfo({ title, address, email, phone, note }) {
return (
<div className="mb-6">
<h3 className="text-3xl font-semibold text-black mb-2">{title}</h3>
<div className="flex items-start mb-5">
<MapPin className="w-5 h-5 mr-2 flex-shrink-0 text-[#c08c38]" />
<span>{address}</span>
</div>
<div className="flex items-start mb-5">
<Mail className="w-5 h-5 mr-2 flex-shrink-0 text-[#c08c38]" />
<span>Email: {email}</span>
</div>
{phone && (
<div className="flex items-start">
<Phone className="w-5 h-5 mr-2 flex-shrink-0 text-[#c08c38]" />
<span>Phone: {phone}</span>
</div>
)}
{note && (
<p className="mt-2 p-3 border border-[#c19a5b] w-3/4">
<span className="font-semibold">Note:</span>
<br />
{note}
</p>
)}
</div>
);
}

View File

@@ -0,0 +1,51 @@
import React, { useState } from 'react';
import { ChevronDown } from 'lucide-react';
const CurrencySelect = ({ selectedCurrency, setSelectedCurrency, SUPPORTED_CURRENCIES }) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="relative w-32">
<button
onClick={() => setIsOpen(!isOpen)}
className="w-full px-4 py-2.5 bg-white border border-gray-200 rounded-lg shadow-sm
flex items-center justify-between text-gray-700 text-sm font-medium
hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500
transition-all duration-200 group"
>
{SUPPORTED_CURRENCIES[selectedCurrency]?.country}
<ChevronDown
className={`w-4 h-4 text-gray-400 transition-transform duration-200
${isOpen ? 'rotate-180' : ''} group-hover:text-gray-600`}
/>
</button>
{isOpen && (
<div
className="absolute w-full mt-2 bg-white border border-gray-200 rounded-lg shadow-lg
overflow-hidden z-50 animate-in fade-in slide-in-from-top-2 duration-200"
>
<div className="max-h-60 overflow-auto scrollbar-thin scrollbar-thumb-gray-200 hover:scrollbar-thumb-gray-300">
{Object.entries(SUPPORTED_CURRENCIES).map(([code, { country }]) => (
<button
key={code}
onClick={() => {
setSelectedCurrency(code);
setIsOpen(false);
}}
className={`w-full px-4 py-2.5 text-left text-sm transition-colors duration-150
hover:bg-gray-50 focus:outline-none focus:bg-gray-50
${selectedCurrency === code ? 'bg-blue-50 text-blue-600 font-medium' : 'text-gray-700'}
${selectedCurrency === code ? 'hover:bg-blue-50' : 'hover:bg-gray-50'}`}
>
{country}
</button>
))}
</div>
</div>
)}
</div>
);
};
export default CurrencySelect;

View File

@@ -0,0 +1,54 @@
import React, { useContext } from "react";
import Link from "next/link";
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuList,
NavigationMenuLink,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu";
import ProductContext from "@/app/contexts/productContext";
const DynamicNavbar = ({ toggleMenu }) => {
const { category } = useContext(ProductContext);
if (!category) {
return null;
}
const categoryItems = category?.map((category) => ({
label: category.category_name,
url: `/collections/${category.id}`,
}));
const consultation = {
label: "Rudraksha consultation",
url: "/products/premium-rudraksha-consultation-astrology",
};
const visibleItems = [...categoryItems.slice(0, 4), consultation];
return (
<NavigationMenu className="text-xl">
<NavigationMenuList className="text-2xl">
{visibleItems.map((item) => (
<NavigationMenuItem key={item.label}>
<Link href={item.url} legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
{item.label}
</NavigationMenuLink>
</Link>
</NavigationMenuItem>
))}
<NavigationMenuItem>
<button onClick={toggleMenu} className={navigationMenuTriggerStyle()}>
More
</button>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
};
export default DynamicNavbar;

View File

@@ -0,0 +1,20 @@
import Image from 'next/image'
import React from 'react'
const ExclusiveRudrakshaBanner = () => {
return (
<div className='min-h-[50vh] sm:block hidden'>
<div className="h-[55vh] bg-[url('/exclusive/exclusive_banner.webp')]">
<div className='max-w-7xl mx-auto flex gap-2 h-full w-full justify-center items-center'>
<Image src={'/exclusive/medium.avif'} height={400} width={400} alt='' />
<div className=''>
<h1 className='text-5xl font-serif tracking-wider mb-4 text-white'>Exclusive and Rare Rudraksha Collection at Gupta Rudraksha ®</h1>
<h2 className='text-lg text-white'>Discover the exclusive and rare Rudraksha collection only at Gupta Rudraksha. Our lab-certified, high-quality beads channel ancient spiritual energies for peace, prosperity, and personal growth. Each bead is meticulously chosen to ensure authenticity and potency, providing powerful benefits. Experience genuine, transformative spiritual tools to enhance your life&apos;s journey with Gupta Rudraksha.</h2>
</div>
</div>
</div>
</div>
)
}
export default ExclusiveRudrakshaBanner

View File

@@ -0,0 +1,13 @@
import React from "react";
const ListofRudrakshaCard = () => {
return (
<div className="min-h-screen bg-slate-50">
<h1 className="font-serif text-2xl mx-auto tracking-wide sm:text-4xl mt-11 text-center sm:w-3/5 md:text-5xl text-slate-800 mb-4">
World&apos;s Rare and Premium Collection of Rudraksha
</h1>
</div>
);
};
export default ListofRudrakshaCard;

View File

@@ -0,0 +1,41 @@
import { guranteeData } from "@/utils";
import Image from "next/image";
import React from "react";
const WhyShouldChooseUs = () => {
return (
<div className="min-h-[60vh] bg-zinc-50 mt-14 px-4 sm:px-8">
<div className="text-center mb-12">
<h1 className="font-serif text-3xl sm:text-4xl md:text-5xl text-slate-800 mb-4">
Why should you choose us?
</h1>
<h2 className="text-base sm:text-xl text-slate-700">
Witness the ancient craft of harvesting and crafting these sacred
beads straight from the trees. Experience the authentic power and
beauty of genuine Rudraksha with our exclusive video.`
</h2>
</div>
<div className="flex justify-center gap-6 flex-wrap">
{guranteeData.map((item) => (
<div
key={item.id}
className="flex flex-col justify-center items-center mb-4 w-full sm:w-[45%] md:w-[30%] lg:w-[18%]"
>
<Image
height={300}
width={300}
src={item.imageUrl}
alt={item.title}
className="w-[100px] h-[100px] sm:w-[160px] sm:h-[160px] object-cover"
/>
<h2 className="text-sm sm:text-lg uppercase text-zinc-800 mt-3 text-center w-[80%]">
{item.title}
</h2>
</div>
))}
</div>
</div>
);
};
export default WhyShouldChooseUs;

View File

@@ -0,0 +1,107 @@
import Link from "next/link"
import { motion } from "framer-motion"
import { Facebook, Twitter, Instagram, Youtube, PhoneIcon as Whatsapp, ArrowRight } from "lucide-react"
const footerLinks = [
{
title: "Exclusive Services",
links: [
{ name: "Return And Cancellation Policy", href: "/policies/refund-policy" },
{ name: "Privacy Policy", href: "/policies/privacy-policy" },
{ name: "Book a Consultation", href: "/products/premium-rudraksha-consultation-astrology" },
],
},
{
title: "May We Help You?",
links: [
{ name: "Help and Contact", href: "/pages/contact-us" },
{ name: "Track Order", href: "/pages/track-order" },
{ name: "Shipping Information", href: "/pages/shipping-information" },
],
},
{
title: "Our Brands",
links: [
// { name: "Why Gupta Rudraksha?", href: "/pages/about-us" },
{ name: "Certification and Guarantee", href: "/pages/certification-and-guarantee" },
{ name: "Terms of Service", href: "/policies/terms-of-services" },
],
},
]
const socialLinks = [
{ name: "Facebook", icon: Facebook, href: "https://www.facebook.com/share/15qi5L1EsK/" },
{ name: "Instagram", icon: Instagram, href: "https://www.instagram.com/grb.religiongoods?igsh=ejNqZXZmMTVudzk=" },
{ name: "YouTube", icon: Youtube, href: "https://youtube.com/@guptarudrakshabeads?si=bCVPn8GsneXcFv0s" },
{
name: "WhatsApp",
icon: Whatsapp,
href: "https://api.whatsapp.com/send/?phone=9779803287986&text&type=phone_number&app_absent=0",
},
]
const Footer = () => {
return (
<footer className="bg-[#304938] text-primary-foreground">
<div className="container mx-auto px-4 py-12">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-12">
{footerLinks.map((column, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<h3 className="text-xl font-bold mb-4 text-primary-foreground/90">{column.title}</h3>
<ul className="space-y-2">
{column.links.map((link, linkIndex) => (
<li key={linkIndex}>
<Link href={link.href} className="hover:text-primary-foreground/70 transition-colors">
{link.name}
</Link>
</li>
))}
</ul>
</motion.div>
))}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.3 }}
>
<h3 className="text-xl font-bold mb-4 text-primary-foreground/90">Stay Connected</h3>
<div className="flex flex-wrap gap-4">
{socialLinks.map((social, index) => (
<a
key={index}
href={social.href}
target="_blank"
rel="noopener noreferrer"
className="bg-primary-foreground/10 p-2 rounded-full hover:bg-primary-foreground/20 transition-colors"
>
<social.icon size={24} />
</a>
))}
</div>
</motion.div>
</div>
<div className="border-t border-primary-foreground/20 pt-8 text-center">
<p className="text-sm text-primary-foreground/70">
© {new Date().getFullYear()} Gupta Rudraksha. All rights reserved.
</p>
</div>
</div>
</footer>
)
}
export default Footer

View File

@@ -0,0 +1,79 @@
'use client'
import React, { useContext, useEffect, useState } from "react";
import Link from "next/link";
import { menuItems } from "@/utils";
import ProductContext from "@/app/contexts/productContext";
const FullWidthMenu = ({ isOpen, onClose, isScrolled }) => {
const [isRendered, setIsRendered] = useState(false);
const { category } = useContext(ProductContext);
const categoryItems = category?.map((category) => ({
label: category.category_name,
url: `/collections/${category.id}`,
})) || []
useEffect(() => {
if (isOpen) {
setIsRendered(true);
} else {
const timer = setTimeout(() => setIsRendered(false), 300); // Match this with the transition duration
return () => clearTimeout(timer);
}
}, [isOpen]);
if (!isRendered && !isOpen) {
return null;
}
return (
<div
className={`fixed ${
isScrolled ? "top-24" : "top-36"
} left-0 max-w-[100%] w-full sm:h-full h-[90vh] hide-navbar overflow-y-scroll text-slate-900 bg-white z-40 shadow-md transition-transform duration-300 ease-in ${
isOpen ? "translate-x-0" : "-translate-x-full "
} `}
>
{/* hidden items only show on mobile devices */}
<div className="flex flex-col space-y-8 sm:hidden ml-7 border-b py-6">
{categoryItems.map((item) => (
<category
key={item.label}
href={item.url}
className="text-2xl font-medium hover:text-[#AC8C6B] transition-colors"
onClick={onClose}
>
{item.label}
</category>
))}
</div>
<div className="container mx-auto sm:py-20 py-7 px-6 flex sm:gap-44 md:gap-36 gap-7 sm:flex-row md:flex-row flex-col">
{/* left section */}
<div className="sm:h-[70vh] flex flex-col p-3 justify-evenly sm:gap-8 gap-7 sm:ml-10 sm:border-b pb-8">
{menuItems.map((menuItem, index) => (
<Link href={menuItem.link} key={index} onClick={onClose}>
<h2 className="text-xl font-semibold text-slate-900 hover:text-[#AC8C6B] transition-colors">
{menuItem.name}
</h2>
</Link>
))}
</div>
{/* right section */}
<div className="flex flex-col p-3 justify-evenly sm:gap-3 gap-7 sm:ml-10 min-h-[300px]">
{categoryItems?.map((item) => (
<Link href={item.url} key={item.id} onClick={onClose}>
<h2 className="text-xl font-semibold text-slate-900">
{item.label}
</h2>
</Link>
))}
</div>
</div>
</div>
);
};
export default FullWidthMenu;

View File

@@ -0,0 +1,261 @@
"use client";
import React from "react";
import "./Header.css"; // Include your styles
import HeaderTwo from "./HeaderTwo";
const Header = () => {
return (
<>
<header className="desctop-menu-large small-header headertype2">
<nav className="panel-menu mobile-main-menu">
<ul>
<li className="">
<a href="/pages/buy-rudraksha">Rudraksha</a>
<ul>
<li>
<a href="/collections/nirakar-zero-mukhi">Nirakar (0) Mukhi </a>
</li>
<li>
<a href="/collections/one-mukhi-1-face-rudraksha">1 Mukhi </a>
</li>
<li>
<a href="/collections/two-mukhi-2-face-rudraksha">2 Mukhi</a>
</li>
<li>
<a href="/collections/three-mukhi-3-face-rudraksha">3 Mukhi</a>
</li>
<li>
<a href="/collections/four-mukhi-4-face-rudraksha">4 Mukhi</a>
</li>
<li>
<a href="/collections/five-mukhi-5-face-rudraksha">5 Mukhi</a>
</li>
<li>
<a href="/collections/six-mukhi-6-face-rudraksha">6 Mukhi </a>
</li>
<li>
<a href="/collections/seven-mukhi-7-face-rudraksha">7 Mukhi </a>
</li>
<li>
<a href="/collections/eight-mukhi-8-face-rudraksha">8 Mukhi </a>
</li>
<li>
<a href="/collections/nine-mukhi-9-face-rudraksha">9 Mukhi </a>
</li>
<li>
<a href="/collections/ten-mukhi-10-face-rudraksha">10 Mukhi</a>
</li>
<li>
<a href="/collections/eleven-mukhi-11-face-rudraksha">
11 Mukhi
</a>
</li>
<li>
<a href="/collections/twelve-mukhi-12-face-rudraksha">
12 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/thirteen-mukhi-13-face-rudraksha">
13 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/fourteen-mukhi-14-face-rudraksha">
14 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/15-mukhi-rudraksha-nepali">15 Mukhi </a>
</li>
<li>
<a href="/collections/sixteen-mukhi-16-face-rudraksha">
16 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/seventeen-mukhi-17-face-rudraksha">
17 Mukhi
</a>
</li>
<li>
<a href="/collections/eighteen-mukhi-18-face-rudraksha">
18 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/nineteen-mukhi-19-face-rudraksha">
19 Mukhi
</a>
</li>
<li>
<a href="/collections/twenty-mukhi-20-face-rudraksha">
20 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/twenty-one-mukhi-21-face-rudraksha">
21 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/twenty-two-mukhi-22-face-rudraksha">
22 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/twenty-three-mukhi-23-face-rudraksha">
23 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/twenty-four-mukhi-24-face-rudraksha">
24 Mukhi{" "}
</a>
</li>
<li>
<a href="/collections/25-mukhi-rudraksha">25 Mukhi </a>
</li>
<li>
<a href="/collections/26-mukhi-rudraksha">26 Mukhi </a>
</li>
<li>
<a href="/collections/trijuti-rudraksha">Trijuti Rudraksha </a>
</li>
<li>
<a href="/collections/gauri-shankar-rudraksha">
Gauri Shankar Rudraksha{" "}
</a>
</li>
<li>
<a href="/collections/ganesh-rudraksha">Ganesh Rudraksha </a>
</li>
<li>
<a href="/collections/garbha-gauri-rudraksha">
Garbha Gauri Rurdaksha{" "}
</a>
</li>
</ul>
</li>
<li className="">
<a href="/pages/exclusive-rudraksha">Exclusive</a>
</li>
<li className="">
<a href="/collections/siddha-mala">Siddha Mala</a>
<ul>
<li>
<a href="/products/siddha-mala-economy-1">
Siddha Mala (Economy)
</a>
</li>
<li>
<a href="/products/siddha-mala-basic">Basic Siddha Mala</a>
</li>
<li>
<a href="/products/sarva-siddha-mala">Sarva Siddha Mala </a>
</li>
<li>
<a href="/products/karya-siddha-mala">Karya Siddha Mala</a>
</li>
<li>
<a href="/products/gayatri-siddha-mala">Gayatri Siddha Mala</a>
</li>
<li>
<a href="/products/maha-mrityunjaya-siddha-mala">
Maha MrityunJaya Siddha Mala
</a>
</li>
<li>
<a href="/products/mangal-siddha-mala">Mangal Siddha Mala</a>
</li>
<li>
<a href="/products/indonesian-siddha-mala">
Indonesian Siddha Mala
</a>
</li>
</ul>
</li>
<li className="">
<a href="/products/premium-rudraksha-consultation-astrology">
Rudraksha Consultation
</a>
</li>
<li className="">
<a href="/collections/shaligram">Shaligram</a>
<ul>
<li>
<a href="/collections/vishnu-dashavatar-shaligrams">
Vishnu Dashavatar Shaligrams
</a>
</li>
<li>
<a href="/collections/most-worshipped-shaligrams">
Most Worshipped Shaligrams
</a>
</li>
</ul>
</li>
<li className="main-menus last-child">
<a href="#more_menus">More</a>
</li>
<li className="item-categories">
<a href="/collections/online-pooja">
<span>Pooja</span>
</a>
</li>
<li className="item-categories">
<a href="/collections/rudraksha-japa-mala">
<span>Japa Mala</span>
</a>
</li>
<li className="item-categories">
<a href="/pages/certification-and-guarantee">
<span>Certification and Guarantee</span>
</a>
</li>
<li className="item-categories">
<a href="/pages/rudraksha-combination">
<span>Combination</span>
</a>
</li>
<li className="item-categories">
<a href="/collections/murti-yantra">
<span>Murtis &amp; Yantra</span>
</a>
</li>
<li className="item-categories">
<a href="/pages/energization">
<span>Rudraksha Energization</span>
</a>
</li>
<li className="item-categories">
<a href="/pages/about-us">
<span>Why Gupta Rudraksha?</span>
</a>
</li>
<li className="item-categories">
<a href="/pages/contact">
<span>Contact Us</span>
</a>
</li>
<li className="item-categories">
<a href="/blogs/blog">
<span>Blogs</span>
</a>
</li>
<li className="item-categories">
<a href="/pages/knowledge-center">
<span>Knowledge Center</span>
</a>
</li>
</ul>
</nav>
</header>
<HeaderTwo />
</>
);
};
export default Header;

View File

@@ -0,0 +1,105 @@
import React from "react";
import "./HeaderTwo.css";
import Image from "next/image";
const HeaderTwo = () => {
return (
<div className="tt-mobile-header tt-mobile-header-inline tt-mobile-header-inline-stuck">
<div className="container-fluid">
<div className="tt-header-row">
<div className="tt-mobile-parent-menu">
<div className="tt-menu-toggle mainmenumob-js">
<svg
width={17}
height={15}
viewBox="0 0 17 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16.4023 0.292969C16.4935 0.397135 16.5651 0.507812 16.6172 0.625C16.6693 0.742188 16.6953 0.865885 16.6953 0.996094C16.6953 1.13932 16.6693 1.26953 16.6172 1.38672C16.5651 1.50391 16.4935 1.60807 16.4023 1.69922C16.2982 1.80339 16.1875 1.88151 16.0703 1.93359C15.9531 1.97266 15.8294 1.99219 15.6992 1.99219H1.69531C1.55208 1.99219 1.42188 1.97266 1.30469 1.93359C1.1875 1.88151 1.08333 1.80339 0.992188 1.69922C0.888021 1.60807 0.809896 1.50391 0.757812 1.38672C0.71875 1.26953 0.699219 1.13932 0.699219 0.996094C0.699219 0.865885 0.71875 0.742188 0.757812 0.625C0.809896 0.507812 0.888021 0.397135 0.992188 0.292969C1.08333 0.201823 1.1875 0.130208 1.30469 0.078125C1.42188 0.0260417 1.55208 0 1.69531 0H15.6992C15.8294 0 15.9531 0.0260417 16.0703 0.078125C16.1875 0.130208 16.2982 0.201823 16.4023 0.292969ZM16.4023 6.28906C16.4935 6.39323 16.5651 6.50391 16.6172 6.62109C16.6693 6.73828 16.6953 6.86198 16.6953 6.99219C16.6953 7.13542 16.6693 7.26562 16.6172 7.38281C16.5651 7.5 16.4935 7.60417 16.4023 7.69531C16.2982 7.79948 16.1875 7.8776 16.0703 7.92969C15.9531 7.98177 15.8294 8.00781 15.6992 8.00781H1.69531C1.55208 8.00781 1.42188 7.98177 1.30469 7.92969C1.1875 7.8776 1.08333 7.79948 0.992188 7.69531C0.888021 7.60417 0.809896 7.5 0.757812 7.38281C0.71875 7.26562 0.699219 7.13542 0.699219 6.99219C0.699219 6.86198 0.71875 6.73828 0.757812 6.62109C0.809896 6.50391 0.888021 6.39323 0.992188 6.28906C1.08333 6.19792 1.1875 6.1263 1.30469 6.07422C1.42188 6.02214 1.55208 5.99609 1.69531 5.99609H15.6992C15.8294 5.99609 15.9531 6.02214 16.0703 6.07422C16.1875 6.1263 16.2982 6.19792 16.4023 6.28906ZM16.4023 12.3047C16.4935 12.3958 16.5651 12.5 16.6172 12.6172C16.6693 12.7344 16.6953 12.8646 16.6953 13.0078C16.6953 13.138 16.6693 13.2617 16.6172 13.3789C16.5651 13.4961 16.4935 13.6068 16.4023 13.7109C16.2982 13.8021 16.1875 13.8737 16.0703 13.9258C15.9531 13.9779 15.8294 14.0039 15.6992 14.0039H1.69531C1.55208 14.0039 1.42188 13.9779 1.30469 13.9258C1.1875 13.8737 1.08333 13.8021 0.992188 13.7109C0.888021 13.6068 0.809896 13.4961 0.757812 13.3789C0.71875 13.2617 0.699219 13.138 0.699219 13.0078C0.699219 12.8646 0.71875 12.7344 0.757812 12.6172C0.809896 12.5 0.888021 12.3958 0.992188 12.3047C1.08333 12.2005 1.1875 12.1224 1.30469 12.0703C1.42188 12.0182 1.55208 11.9922 1.69531 11.9922H15.6992C15.8294 11.9922 15.9531 12.0182 16.0703 12.0703C16.1875 12.1224 16.2982 12.2005 16.4023 12.3047Z"
fill="#191919"
/>
</svg>
</div>
</div>
<div className="tt-logo-container">
<a className="tt-logo tt-logo-alignment" href="/">
<Image
src="images/logo_95x.svg"
alt="Logo Rudraksha | Gupta Rudraksha"
width={95}
height={95}
className="tt-retina"
srcSet="images/logo_95x.svg 1x, images/logo_190x.svg 2x"
/>
</a>
</div>
<div className="tt-mobile-parent-menu-icons">
{/* search */}
<div className="tt-mobile-parent-search tt-parent-box">
{/* tt-search */}
<div className="tt-search tt-dropdown-obj">
<button
className="tt-dropdown-toggle"
data-tooltip="Search"
data-tposition="bottom"
>
<svg
style={{ width: "2.5rem", height: "2.5rem" }}
width={25}
height={25}
viewBox="0 0 25 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M22.25 22.8281L20.25 20.8281M11.75 21.8281C12.9976 21.8281 14.2329 21.5824 15.3855 21.105C16.5381 20.6276 17.5854 19.9278 18.4675 19.0456C19.3497 18.1635 20.0494 17.1162 20.5269 15.9636C21.0043 14.811 21.25 13.5757 21.25 12.3281C21.25 11.0806 21.0043 9.84523 20.5269 8.69263C20.0494 7.54004 19.3497 6.49277 18.4675 5.61061C17.5854 4.72845 16.5381 4.02869 15.3855 3.55127C14.2329 3.07385 12.9976 2.82812 11.75 2.82813C9.23044 2.82813 6.81408 3.82901 5.03249 5.61061C3.25089 7.39221 2.25 9.80857 2.25 12.3281C2.25 14.8477 3.25089 17.264 5.03249 19.0456C6.81408 20.8272 9.23044 21.8281 11.75 21.8281Z"
stroke="black"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
<div className="tt-dropdown-menu">
<div className="container">
<form action="/search" method="get" role="search">
<div className="tt-col">
<input
type="hidden"
name="type"
defaultValue="product"
/>
<input
className="tt-search-input"
type="search"
name="q"
placeholder="SEARCH PRODUCTS..."
aria-label="SEARCH PRODUCTS..."
/>
<button type="submit" className="tt-btn-search" />
</div>
<div className="tt-col">
<button className="tt-btn-close icon-f-84" />
</div>
<div className="tt-info-text">
What are you Looking for?
</div>
</form>
</div>
</div>
</div>
{/* /tt-search */}
</div>
{/* /search */}
{/* cart */}
<div className="tt-mobile-parent-cart tt-parent-box" />
{/* /cart */}
</div>
</div>
</div>
</div>
);
};
export default HeaderTwo;

View File

@@ -0,0 +1,114 @@
"use client"
import React, { useContext, useEffect, useState } from "react"
import { Menu, ShoppingBag, UserRound } from "lucide-react"
import { IoMdClose } from "react-icons/io"
import Link from "next/link"
import { NavigationMenu, NavigationMenuList } from "@/components/ui/navigation-menu"
import FullWidthMenu from "./FullWidthMenu"
import MainContext from "@/app/contexts/mainContext"
import DynamicNavbar from "../dynamic-navbar/dynamicNavbar"
import SearchComponent from "../search/searchComponent"
import { useCurrency } from "@/app/contexts/currencyContext"
import CurrencySelect from "../dynamic-navbar/currencySelect"
import Image from "next/image"
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false)
const [isScrolled, setIsScrolled] = useState(false)
const [isMounted, setIsMounted] = useState(false)
const { token } = useContext(MainContext)
const toggleMenu = () => setIsOpen(!isOpen)
const { selectedCurrency, setSelectedCurrency, SUPPORTED_CURRENCIES } = useCurrency()
useEffect(() => {
setIsMounted(true)
const handleScroll = () => {
setIsScrolled(window.scrollY > 60)
}
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}, [])
if (!isMounted) {
return null // or a loading placeholder
}
return (
<>
<header className="fixed top-0 left-0 right-0 z-50 transition-all duration-200">
<nav className={`bg-white p-4 ${isScrolled ? "shadow-lg" : ""}`}>
<div className="container mx-auto flex justify-between items-center">
<div className="flex items-center">
<button onClick={toggleMenu} className="z-50">
{isOpen ? <IoMdClose size={44} /> : <Menu size={44} strokeWidth={1} />}
</button>
<Link href={"/"} className="flex items-center space-x-2">
<Image src="/logo1.jpg" alt="Logo" width={56} height={56} className="object-contain" />
</Link>
</div>
{!isOpen && (
<div
className={`hidden lg:flex items-center w-1/2 space-x-9 capitalize text-xl ${
isScrolled ? "opacity-100" : "opacity-0"
} transition-opacity duration-200`}
>
<NavigationMenu className="text-xl">
<NavigationMenuList className="text-2xl">
<DynamicNavbar toggleMenu={toggleMenu} />
</NavigationMenuList>
</NavigationMenu>
</div>
)}
<div className="flex items-center space-x-4">
<SearchComponent isScrolled={isScrolled} />
<Link href="/pages/shopping-cart">
<ShoppingBag size={20} className={`cursor-pointer ${isScrolled ? "block" : "hidden"}`} />
</Link>
<div className={`cursor-pointer ${isScrolled ? "block" : "hidden"}`}>
{token ? (
<Link href="/accounts/profile">
<UserRound size={20} />
</Link>
) : (
<Link href="/accounts/login">
<button className="bg-[#c19a5b] text-white px-3 py-1 rounded hover:bg-[#b48943] text-sm">
Login
</button>
</Link>
)}
</div>
<CurrencySelect
selectedCurrency={selectedCurrency}
setSelectedCurrency={setSelectedCurrency}
SUPPORTED_CURRENCIES={SUPPORTED_CURRENCIES}
/>
</div>
</div>
</nav>
{!isOpen && (
<div
className={`sm:block hidden bg-white p-2 transition-all duration-300 ${
isScrolled ? "opacity-0 h-0 overflow-hidden" : "opacity-100"
}`}
>
<div className="container mx-auto flex justify-center items-center space-x-16">
<DynamicNavbar toggleMenu={toggleMenu} />
</div>
</div>
)}
</header>
<FullWidthMenu isOpen={isOpen} onClose={toggleMenu} isScrolled={isScrolled} />
<div className="h-[104px] sm:h-[150px]"></div>
</>
)
}
export default Navbar

View File

@@ -0,0 +1,31 @@
import React from "react";
const TopBanner = () => {
return (
<div className="h-12 bg-gradient-to-r from-[#96724f] to-[#AC8C6B] flex items-center text-white">
<marquee
behavior=""
direction=""
className="w-full flex items-center"
>
<div className="flex items-center space-x-2">
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.4999 1.66699L11.2499 2.91699L12.4999 4.16699L13.7499 2.91699L12.4999 1.66699ZM9.16658 2.50033C8.33325 7.50033 14.1666 8.33366 16.6666 5.00033L14.9999 3.75033C14.1666 5.00033 10.8333 6.66699 9.16658 2.50033ZM7.49992 5.83366C5.83325 5.83366 3.74992 7.08366 3.74992 7.08366L4.99992 9.16699C5.83325 8.33366 7.49992 7.91699 8.33325 8.33366C9.99992 9.16699 7.49992 10.8337 5.83325 10.0003V12.917C8.33325 11.667 9.99992 13.3337 9.16658 14.5837C6.66658 18.3337 2.49992 13.3337 2.49992 10.8337C0.833251 15.8337 4.99992 18.3337 7.49992 18.3337C9.99992 18.3337 11.6666 16.667 10.4166 12.5003H11.6666C10.4166 16.2503 14.9999 20.0003 17.4999 15.0003C18.3333 13.3337 18.3333 7.91699 14.1666 7.91699C10.8333 7.91699 11.6666 12.5003 8.74992 11.2503C11.6666 8.33366 9.99992 5.83366 7.49992 5.83366ZM15.8333 10.0003C18.3333 12.5003 12.4999 17.5003 12.4999 12.5003C12.4999 10.8337 14.1666 8.75033 15.8333 10.0003Z"
fill="white"
></path>
</svg>
<span>Place your order by September 26th to receive your items in Navaratri</span>
</div>
</marquee>
</div>
);
};
export default TopBanner;

View File

@@ -0,0 +1,98 @@
import React, { useState } from 'react';
import { ChevronRight } from 'lucide-react';
const rudrakshaData = {
title: "Rudraksha",
subtitle: "Explore the World's largest collection of Authentic A+ Grade Gupta Rudraksha.",
buttonText: "View All Collection",
columns: [
[
{ name: "Nirakar (0) Mukhi" },
{ name: "1 Mukhi" },
{ name: "2 Mukhi" },
{ name: "3 Mukhi" },
{ name: "4 Mukhi" },
{ name: "5 Mukhi" },
{ name: "6 Mukhi" }
],
[
{ name: "7 Mukhi" },
{ name: "8 Mukhi" },
{ name: "9 Mukhi" },
{ name: "10 Mukhi" },
{ name: "11 Mukhi" },
{ name: "12 Mukhi" },
{ name: "13 Mukhi" }
],
[
{ name: "14 Mukhi" },
{ name: "15 Mukhi" },
{ name: "16 Mukhi" },
{ name: "17 Mukhi" },
{ name: "18 Mukhi" },
{ name: "19 Mukhi" },
{ name: "20 Mukhi" }
],
[
{ name: "21 Mukhi" },
{ name: "22 Mukhi" },
{ name: "23 Mukhi" },
{ name: "24 Mukhi" },
{ name: "25 Mukhi" },
{ name: "26 Mukhi" }
],
[
{ name: "Trijuti Rudraksha" },
{ name: "Gauri Shankar Rudraksha" },
{ name: "Ganesh Rudraksha" },
{ name: "Garbha Gauri Rurdaksha" }
]
]
};
const HoverRudrakshaContent = () => {
const [selectedMukhi, setSelectedMukhi] = useState(null);
return (
<div className="bg-gradient-to-r from-orange-100 to-red-100 max-h-[50vh] min-w-[100vw] overflow-y-auto p-8">
<div className=" mx-auto bg-white rounded-xl shadow-2xl overflow-hidden">
<div className="md:flex">
<div className=" bg-orange-600 text-white p-8">
<h2 className="text-4xl font-bold mb-4">{rudrakshaData.title}</h2>
<p className="mb-8 text-lg">{rudrakshaData.subtitle}</p>
<button className="bg-white text-orange-600 px-6 py-3 rounded-full font-semibold hover:bg-orange-100 transition duration-300">
{rudrakshaData.buttonText}
</button>
</div>
<div className=" p-8">
<div className="grid md:grid-cols-5 gap-6">
{rudrakshaData.columns.map((column, columnIndex) => (
<div key={columnIndex}>
{column.map((item, itemIndex) => (
<div
key={itemIndex}
className="mb-2 cursor-pointer group"
onClick={() => setSelectedMukhi(item.name)}
>
<div className="flex items-center space-x-2 p-2 rounded-lg hover:bg-orange-100 transition duration-300">
<ChevronRight className="text-orange-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300" size={16} />
<span className="text-sm font-medium text-gray-700 group-hover:text-orange-600">{item.name}</span>
</div>
</div>
))}
</div>
))}
</div>
</div>
</div>
{selectedMukhi && (
<div className="p-4 bg-orange-100 text-center">
<p className="text-lg font-semibold text-orange-800">Selected: {selectedMukhi}</p>
</div>
)}
</div>
</div>
);
};
export default HoverRudrakshaContent;

View File

@@ -0,0 +1,37 @@
import React from 'react';
import Link from 'next/link';
const HoverShaligram = () => {
return (
<div className="grid grid-cols-3 gap-4 w-full">
<div className='w-full'>
<h3 className="font-bold mb-2">Shaligram Types</h3>
<ul className="space-y-1">
<li><Link href="/shaligram/vishnu">Vishnu Shaligram</Link></li>
<li><Link href="/shaligram/lakshmi">Lakshmi Shaligram</Link></li>
<li><Link href="/shaligram/narayan">Narayan Shaligram</Link></li>
{/* Add more Shaligram types as needed */}
</ul>
</div>
<div>
<h3 className="font-bold mb-2">Benefits</h3>
<ul className="space-y-1">
<li>Spiritual Growth</li>
<li>Protection</li>
<li>Prosperity</li>
{/* Add more benefits as needed */}
</ul>
</div>
<div>
<h3 className="font-bold mb-2">Resources</h3>
<ul className="space-y-1">
<li><Link href="/shaligram/care">Care Instructions</Link></li>
<li><Link href="/shaligram/history">History of Shaligram</Link></li>
<li><Link href="/shaligram/faq">FAQ</Link></li>
</ul>
</div>
</div>
);
};
export default HoverShaligram;

View File

@@ -0,0 +1,99 @@
"use client";
import Image from "next/image";
import React, { useState, useEffect } from "react";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
import Autoplay from "embla-carousel-autoplay";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
const Hero = () => {
const plugin = React.useRef(
Autoplay({ delay: 4000, stopOnInteraction: true })
);
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768);
};
checkMobile();
window.addEventListener("resize", checkMobile);
return () => window.removeEventListener("resize", checkMobile);
}, []);
const heroData = [
{
type: "image",
src: "/rudraksh banner image 2.avif",
overlay: {
title: "Sacred Collection",
subtitle: "Discover Authentic Rudraksha",
description: "Explore our curated selection of premium spiritual items",
link: "/collection",
},
},
{
type: "image",
src: "/rudraksha banner 1.png",
overlay: {
title: "Quality Assured",
subtitle: "Lifetime Authenticity Guarantee",
description: "Every piece comes with our exclusive certification",
link: "/products/premium-rudraksha-consultation-astrology",
},
},
{
type: "image",
src: "/rudraksha banner 2.png",
overlay: {
title: "Sacred Ceremonies",
subtitle: "Traditional Prana Pratistha",
description: "Blessed at the ancient Pashupatinath temple",
link: "/collection/online-pooja",
},
},
];
return (
<div className="relative w-full h-[55vh] bg-background">
<Carousel
plugins={[plugin.current]}
className="w-full h-full"
onMouseEnter={plugin.current.stop}
onMouseLeave={plugin.current.reset}
>
<CarouselContent>
{heroData.map((item, index) => (
<CarouselItem key={index}>
<div className="relative w-full h-[55vh] overflow-hidden">
<Image
src={item.src || "/placeholder.svg"}
alt={`Slide ${index + 1}`}
fill
className="object-cover brightness-75"
priority={index === 0}
/>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious className="left-4 bg-white/10 hover:bg-white/20 backdrop-blur-sm text-white border-none" />
<CarouselNext className="right-4 bg-white/10 hover:bg-white/20 backdrop-blur-sm text-white border-none" />
</Carousel>
</div>
);
};
export default Hero;

View File

@@ -0,0 +1,55 @@
import React from "react";
import Image from "next/image";
import Link from "next/link";
import { productsCards } from "@/utils";
const ExclusiveProductCards = () => {
return (
<div className="container mx-auto px-4 py-8 max-w-8xl">
<div className="text-center mb-12">
<h1 className="font-serif text-5xl text-slate-800 mb-4">
Only at Gupta Rudraksha
</h1>
<h2 className="text-xl text-slate-700">
Explore divinity with Gupta Rudraksha&#39;s rare and authentic collection.
Step into a world of spiritual bliss.
</h2>
</div>
<div className="flex-wrap gap-5 flex items-center justify-center">
{productsCards.map((product) => (
<Link href={`/products/${product.title}`} key={product.id}>
<div
key={product.id}
className="relative bg-[#EDE8E0] overflow-hidden h-[350px] w-[300px] "
>
<div className="absolute top-0 left-0 bg-[#C19A5B] text-white py-1 px-3 rounded-br-lg z-10">
Exclusive
</div>
<div className="h-[300px] w-[300px] flex items-center justify-center">
<Image
src={"/one-one.jpg"}
alt={`Logo for ${product.title}`}
width={160}
height={150}
className="object-contain hover:scale-125 transition-all ease-in duration-300"
/>
</div>
<div className="p-4 ">
<h3 className="text-center text-[1rem] uppercase text-gray-800">
{product.title}
</h3>
</div>
</div>
</Link>
))}
</div>
<div className="py-4 border-y-2 mt-9">
<Link href={'/collections/only-in-nepa-rudraksha'}><h2 className="text-2xl text-center underline text-[#C19A5B]">Shop Exclusive Products</h2></Link>
</div>
</div>
);
};
export default ExclusiveProductCards;

View File

@@ -0,0 +1,30 @@
import React from "react";
const HeroFour = () => {
return (
<div className="min-h-[70vh] mt-10 pb-14 sm:px-6 lg:px-8">
<div className="max-w-8xl mx-auto">
<div className="text-center mb-12">
<h1 className="font-serif text-5xl text-slate-800 mb-4">
Explore Gupta Rudraksha
</h1>
<h2 className="text-xl text-slate-700">
Dive deep with us in our Gupta Rudraksha Journey and our get to know
us even more better.
</h2>
</div>
<iframe
src="https://www.youtube.com/embed/_drMO01Mjtc"
title="Rudraksha &amp; Its REAL POWER explained, Jaap Benefits | Pashupatinath, Bhairav, Nepals History | TRS"
frameBorder="0"
className="mx-auto h-[180px] sm:h-[570px] w-[300px] sm:w-3/4"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
</div>
</div>
);
};
export default HeroFour;

View File

@@ -0,0 +1,30 @@
import Link from "next/link";
import React from "react";
const HeroSeven = () => {
return (
<div className="min-h-screen bg-no-repeat flex flex-col sm:p-5 ">
<div className="text-center mb-6 mt-4 sm:mb-8 sm:mt-6 md:mb-12 md:mt-9 px-4">
<h1 className="font-serif text-3xl sm:text-4xl md:text-5xl text-slate-800 mb-2 sm:mb-3 md:mb-4">
Our Collections
</h1>
<h2 className="text-lg sm:text-xl text-slate-700 max-w-3xl mx-auto">
Explore divinity with Gupta Rudraksha&#39;s rare and authentic collection. Step into a world of spiritual bliss.
</h2>
</div>
<div className="bg-[url('/pooja_banner_3.png')] bg-no-repeat bg-cover bg-center mx-auto w-full sm:max-w-7xl flex-grow">
<div className="flex flex-col justify-end sm:ml-14 items-center sm:items-start gap-3 sm:gap-4 md:gap-5 h-full sm:h-[60%] w-full sm:w-1/2 p-6 sm:p-8 md:p-12">
<h2 className="font-serif text-lg sm:text-xl md:text-2xl">Experience Divine Blessings</h2>
<h2 className="text-3xl sm:text-4xl md:text-5xl font-serif text-slate-800 text-center sm:text-left">Anytime, Anywhere</h2>
<p className="text-base sm:text-lg w-full sm:w-[90%] text-center sm:text-left">
Online Pooja Services by Certified Brahmans, Using Premium Materials, with 100% Satisfaction Guaranteed.
</p>
<Link href={'/pooja-services'}><button className="border border-slate-800 px-4 py-4 mt-7 hover:bg-[#C19A5B] capitalize font-semibold transition-colors ease-in duration-300 font-serif sm:ml-10">explore pooja services</button></Link>
</div>
</div>
</div>
);
};
export default HeroSeven;

View File

@@ -0,0 +1,54 @@
'use client'
import { guranteeData } from "@/utils";
import Image from "next/image";
import React from "react";
import { motion } from "framer-motion";
const HeroSix = () => {
return (
<section className="py-16 bg-gradient-to-b from-background to-muted">
<div className="container px-4 mx-auto">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="text-center mb-12"
>
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-4">
Our Sacred Commitment
</h2>
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
Certified Excellence in Rudraksha - Nepal&apos;s Premier ISO 9001:2015
Accredited Organization
</p>
</motion.div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-8">
{guranteeData.map((item, index) => (
<motion.div
key={item.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: index * 0.1 }}
className="flex flex-col items-center text-center"
>
<div className="relative w-24 h-24 mb-4">
<Image
src={item.imageUrl || "/placeholder.svg"}
alt={item.title}
layout="fill"
objectFit="contain"
className="rounded-full bg-primary/10 p-4"
/>
</div>
<h3 className="text-sm font-medium text-foreground uppercase tracking-wide">
{item.title}
</h3>
</motion.div>
))}
</div>
</div>
</section>
);
};
export default HeroSix;

View File

@@ -0,0 +1,100 @@
"use client";
import React, { useState, useEffect } from "react";
const CountdownUnit = ({ value, label }) => (
<div className="flex flex-col items-center mr-2 sm:mr-4">
<div className="text-2xl sm:text-xl md:text-xl font-bold mb-1 sm:mb-2 w-[50px] flex justify-center px-2 sm:px-4 py-1 sm:py-2 rounded bg-gradient-to-r from-[#96724f] to-yellow-700">
{value !== undefined ? value : "0"}{" "}
{/* Display '0' if value is undefined */}
</div>
<div className="text-xs sm:text-sm uppercase">{label}</div>
</div>
);
const Countdown = ({ targetDate }) => {
const [timeLeft, setTimeLeft] = useState(null); // Start with null
useEffect(() => {
const calculateTimeLeft = () => {
const difference = +new Date(targetDate) - +new Date();
let timeLeft = {};
if (difference > 0) {
timeLeft = {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60),
};
}
return timeLeft;
};
const timer = setInterval(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
// Initial calculation
setTimeLeft(calculateTimeLeft());
return () => clearInterval(timer);
}, [targetDate]);
const timeUnits = [
{ key: "days", label: "Days" },
{ key: "hours", label: "Hours" },
{ key: "minutes", label: "Min" },
{ key: "seconds", label: "Sec" },
];
return (
<div className="flex text-white">
{timeLeft &&
timeUnits.map(({ key, label }) => (
<CountdownUnit key={key} value={timeLeft[key]} label={label} />
))}
</div>
);
};
const HeroTwo = () => {
return (
<div className="w-full h-[70vh] mx-auto relative flex justify-center items-center sm:my-14 my-9">
<div
className="mx-auto h-[90%] max-w-7xl bg-cover bg-center bg-no-repeat flex flex-col sm:flex-row justify-center sm:justify-end items-center relative"
style={{ backgroundImage: `url('/diwali.jpg')` }}
>
<div className="absolute inset-0 bg-black opacity-20"></div>
<div className="flex flex-col sm:flex-row justify-between items-center w-full relative z-10 px-4 sm:px-8">
{/* left count down */}
<div className="w-full sm:w-1/2 flex flex-col items-center sm:items-start mb-8 sm:mb-0">
<h1 className="text-xl sm:text-2xl text-white mb-2 sm:mb-4">
SHOP BEFORE
</h1>
<Countdown targetDate="2024-30-26T00:00:00" />
</div>
{/* right banner text content */}
<div className="w-full sm:w-[45%] text-zinc-50 p-4 rounded text-center sm:text-left">
<h1 className="text-3xl sm:text-4xl md:text-5xl font-bold text-white my-3">
Celebrate Diwali with Early Access
</h1>
<p className="my-4 text-sm sm:text-base md:text-lg">
Place your orders by September 26th to receive your items in time
for Navaratri. Dive into the festive season with our exclusive
products!
</p>
<h2 className="mb-3 text-sm sm:text-base">
GUARANTEED DELIVERY BEFORE NAVARATRI
</h2>
<button className="px-3 py-2 text-lg sm:text-xl bg-gradient-to-r from-[#96724f] to-yellow-700">
Shop Now
</button>
</div>
</div>
</div>
</div>
);
};
export default HeroTwo;

View File

@@ -0,0 +1,11 @@
import React from 'react'
const Instasection = () => {
return (
<div className='h-[70vh]'>
</div>
)
}
export default Instasection

19
components/maps/Maps.jsx Normal file
View File

@@ -0,0 +1,19 @@
import React from "react";
function EmbeddedMap() {
return (
<div>
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3532.190474419073!2d85.346992!3d27.7114047!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x39eb19799cd5cd4b%3A0xe7f3187c31bc262!2sGupta%20Rudraksha%20and%20Moti%20Mala%20Bhandar!5e0!3m2!1sen!2sin!4v1738441367350!5m2!1sen!2sin"
width="100%"
height="450"
style={{ border: 0 }}
allowFullScreen=""
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
></iframe>
</div>
);
}
export default EmbeddedMap;

View File

@@ -0,0 +1,75 @@
import Image from "next/image";
import Link from "next/link";
import React from "react";
const ExplorePooja = () => {
const poojaServices = [
{
imgUrl: "/online-pooja/rudraksha-prana-pratishtha-pooja-246.webp",
title: "Rudraksha Prana Pratishtha Pooja",
price: "Rs. 25,500.00",
},
{
imgUrl: "/online-pooja/maha-mrityunjaya-pooja-397.webp",
title: "Maha Mrityunjaya Pooja",
price: "Rs. 17,000.00",
},
{
imgUrl: "/online-pooja/maha-shivaratri-pooja-at-pashupatinath-437.webp",
title: "Maha Shivaratri Pooja at Pashupatinath",
price: "Rs. 25,700.00",
},
{
imgUrl: "/online-pooja/karya-siddhi-ganesh-pooja-672.webp",
title: "Karya Siddhi Ganesh Pooja",
price: "Rs. 59,700.00",
},
{
imgUrl: "/online-pooja/lagu-rudri-path-12-brahmin-273.webp",
title: "Lagu Rudri Path (12 Brahmin)",
price: "Rs. 102,200.00",
},
{
imgUrl: "/online-pooja/navagraha-shanti-pooja-817.webp",
title: "Navagraha Shanti Pooja",
price: "Rs. 17,000.00",
},
{
imgUrl: "/online-pooja/rudra-abishek-pooja-778.webp",
title: "Rudra Abishek Pooja",
price: "Rs. 68,100.00",
},
{
imgUrl: "/online-pooja/laxmi-narayan-pooja-222.webp",
title: "Laxmi Narayan Pooja",
price: "Rs. 42,600.00",
},
{
imgUrl: "/online-pooja/lagu-rudri-path-12-brahmin-273.webp",
title: "Pooja Subscription",
price:
"Rs. 42,600.00",
},
];
return (
<div className="min-h-[60vh]">
<h1 className="sm:text-5xl text-2xl py-6 text-center">Explore Pooja</h1>
<div className=" flex justify-center items-center p-4 flex-wrap gap-6">
{poojaServices.map((item,i) => {
return (
<div key={i}>
<div className="h-[300px] w-[300px] bg-slate-100">
<Link href={`/products/${item.title}`} ><Image height={300} width={300} alt='images' className='h-full w-full' src={item.imgUrl} /></Link>
</div>
<h2 className="my-2">{item.title}</h2>
<h2>{item.price}</h2>
</div>
);
})}
</div>
</div>
);
};
export default ExplorePooja;

View File

@@ -0,0 +1,85 @@
import React from "react";
import {
Card,
CardHeader,
CardContent,
CardFooter,
} from "@/components/ui/card";
const SubscriptionCard = ({ title, price, description, features, isDaily }) => (
<div
className={`sm:w-[40%] w-full sm:p-7 ${
isDaily ? "bg-[#B48D4F] text-white" : "bg-[#F9F5EF] text-zinc-800"
}`}
>
<CardHeader>
<h2 className="text-2xl font-bold sm:text-4xl sm:pb-3">{title}</h2>
<p className="text-2xl font-semibold">{price}</p>
</CardHeader>
<CardContent>
<p className="mb-4 py-3">{description}</p>
<ul className="list-disc pl-5">
{features.map((feature, index) => (
<li key={index} className="mb-2 sm:mb-6">
{feature}
</li>
))}
</ul>
</CardContent>
<CardFooter>
<button
className={`${
isDaily ? "bg-black text-white" : "bg-[#B48D4F] "
}text-zinc-50 px-4 py-3 `}
>
Subscribe
</button>
</CardFooter>
</div>
);
const PoojaSubscription = () => (
<>
<h1 className="text-2xl sm:text-5xl text-center sm:pt-16">
Pooja Subscription
</h1>
<p className="sm:text-lg text-center pt-2 sm:pb-14 pb-4">
Experience divine blessings at your doorstep. Subscribe to our Pooja
services for spiritual harmony.
</p>
<div className="flex sm:flex-row flex-col justify-center sm:space-x-8">
<SubscriptionCard
title="Daily Subscription"
price="Rs. 4,400.00"
description="A certified Pundit will perform a Rudrabhishek and Chandi Path every day at the premises of Lord Pashupatinath temple for you and your family members!"
features={[
"Pooja Performed every day",
"High-quality Video Shared everyday",
"Includes 2 certified Pundits",
"Brahman Bhoojan (meal) included",
"New Material used every day",
"Prasad Shared every month",
"Special requests accepted if applicable",
]}
isDaily={true}
/>
<SubscriptionCard
title="Monthly Subscription"
price="Rs. 9,500.00"
description="A certified Pundit will perform a Rudrabhishek every month at the premises of Lord Pashupatinath temple for you and your family members!"
features={[
"A Rudraksha Expert to answer your questions and provide Rudraksha consultation",
"Pooja Performed every month",
"High-quality Video Shared monthly",
"Includes 1 certified Pundits",
"Brahman Bhoojan (meal) included",
"New Material used every month",
]}
isDaily={false}
/>
</div>
</>
);
export default PoojaSubscription;

View File

@@ -0,0 +1,138 @@
import React, { useState, useEffect } from "react";
import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
import axios from "axios";
import authAxios from "@/utils/axios";
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
const EXCHANGE_RATE_KEY = "exchange_rate_cache";
const PaymentComponent = ({ amount, onSuccess }) => {
const [error, setError] = useState(null);
const [isProcessing, setIsProcessing] = useState(false);
const [usdAmount, setUsdAmount] = useState(null);
useEffect(() => {
const fetchExchangeRate = async () => {
try {
const cachedData = localStorage.getItem(EXCHANGE_RATE_KEY);
if (cachedData) {
const { rate, timestamp } = JSON.parse(cachedData);
if (Date.now() - timestamp < CACHE_DURATION) {
setUsdAmount((amount * rate).toFixed(2));
return;
}
}
const response = await axios.get("https://apilayer.net/api/live", {
params: {
access_key: "9bcb30907dee1cda9866f7b49f0f8def",
currencies: "USD",
source: "INR",
format: 1,
},
});
if (response.data.success) {
const rate = response.data.quotes.INRUSD;
localStorage.setItem(
EXCHANGE_RATE_KEY,
JSON.stringify({
rate,
timestamp: Date.now(),
})
);
setUsdAmount((amount * rate).toFixed(2));
} else {
throw new Error("Failed to fetch exchange rate");
}
} catch (err) {
setError("Currency conversion failed. Please try again later.");
console.error("Exchange rate error:", err);
}
};
fetchExchangeRate();
}, [amount]);
const handleApprove = async (data, actions) => {
try {
setIsProcessing(true);
const order = await actions.order.capture();
onSuccess?.(order);
} catch (err) {
setError("Payment failed. Please try again.");
console.error("Payment error:", err);
} finally {
setIsProcessing(false);
}
};
if (!usdAmount) {
return <div className="text-center p-4">Loading exchange rates...</div>;
}
return (
<div className="max-w-md mx-auto">
{error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
{error}
</div>
)}
<PayPalScriptProvider
options={{
"client-id": process.env.NEXT_PUBLIC_CLIENT_ID,
}}
>
<PayPalButtons
style={{
layout: "horizontal",
label: "checkout",
tagline: false,
fundingicons: true,
}}
disabled={isProcessing}
className="w-full"
createOrder={(data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
value: usdAmount,
currency_code: "USD",
},
},
],
application_context: {
shipping_preference: "GET_FROM_FILE",
},
});
}}
onShippingChange={(data, actions) => {
const allowedCountries = ["IN", "MY", "NP"];
const shippingCountry = data.shipping_address.country_code;
if (!allowedCountries.includes(shippingCountry)) {
return actions.reject().then(() => {
setError(
"Shipping is only available for India, Malaysia, and Nepal. Please update your address."
);
});
}
return actions.resolve();
}}
onApprove={handleApprove}
onError={(err) => {
setError("Payment failed. Please try again.");
}}
/>
<p className="mt-4 text-sm text-gray-600 text-center">
Note: We only ship to addresses in India, Malaysia, and Nepal.
</p>
</PayPalScriptProvider>
</div>
);
};
export default PaymentComponent;

View File

@@ -0,0 +1,152 @@
"use client";
import React, { useState } from "react";
import { ChevronRight, Gem } from "lucide-react";
import authAxios from "@/utils/axios";
import Image from "next/image";
const PremiumBanner = () => {
const [formData, setFormData] = useState({
first_name: "",
last_name: "",
email: "",
phone_number: "",
});
const [message, setMessage] = useState("");
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await authAxios.post(
"/consultation/booking/create/",
formData
);
if (response.status === 201) {
setFormData({
first_name: "",
last_name: "",
email: "",
phone_number: "",
});
setMessage("Consultation experts will contact you shortly.");
setTimeout(() => {
setMessage("");
}, 5000);
} else {
setMessage("An error occurred. Please try again.");
}
} catch (error) {
console.error("Error submitting form:", error);
setMessage("An error occurred. Please try again.");
}
};
return (
<div className="min-h-screen bg-white p-8 flex items-center justify-center">
<div className="max-w-6xl w-full bg-white shadow-lg rounded-xl overflow-hidden p-12">
<div className="grid md:grid-cols-2 gap-8">
{/* Left: Form Section */}
<div className="bg-[#EDE8E0] p-14 flex flex-col justify-center rounded-lg">
<h2 className="text-4xl font-serif text-center text-[#AC8C6B]">
Book a Free Consultation
</h2>
<p className="text-center text-gray-600 text-sm mt-2">
Get expert guidance tailored to your needs.
</p>
<form onSubmit={handleSubmit} className="space-y-5 mt-6">
<input
type="text"
name="first_name"
placeholder="First Name"
value={formData.first_name}
onChange={handleInputChange}
className="w-full p-4 border rounded-md focus:ring-[#AC8C6B] focus:border-[#AC8C6B]"
required
/>
<input
type="text"
name="last_name"
placeholder="Last Name"
value={formData.last_name}
onChange={handleInputChange}
className="w-full p-4 border rounded-md focus:ring-[#AC8C6B] focus:border-[#AC8C6B]"
required
/>
<input
type="email"
name="email"
placeholder="Email"
value={formData.email}
onChange={handleInputChange}
className="w-full p-4 border rounded-md focus:ring-[#AC8C6B] focus:border-[#AC8C6B]"
required
/>
<input
type="text"
name="phone_number"
placeholder="Phone Number"
value={formData.phone_number}
onChange={handleInputChange}
className="w-full p-4 border rounded-md focus:ring-[#AC8C6B] focus:border-[#AC8C6B]"
required
/>
{message && (
<p className="text-green-700 bg-green-100 py-2 text-center rounded-md">
{message}
</p>
)}
<button
type="submit"
className="w-full bg-[#AC874C] text-white font-semibold py-4 rounded-md hover:bg-[#96724f] transition"
>
Request Consultation
</button>
</form>
</div>
{/* Right: Benefits & App Download */}
<div className="p-14 flex flex-col justify-center">
<h2 className="text-4xl font-serif text-[#AC8C6B] text-center">
Why Choose Our Consultation?
</h2>
<p className="text-center text-gray-600 text-sm mt-2">
Gain expert insights and personalized guidance.
</p>
<ul className="mt-6 space-y-4 text-gray-700 text-lg">
<li className="flex items-center">
<ChevronRight className="text-[#AC8C6B] mr-2" />
Expert guidance from experienced professionals
</li>
<li className="flex items-center">
<ChevronRight className="text-[#AC8C6B] mr-2" />
Tailored advice for your specific needs
</li>
<li className="flex items-center">
<ChevronRight className="text-[#AC8C6B] mr-2" />
Unlock clarity and direction in life
</li>
<li className="flex items-center">
<ChevronRight className="text-[#AC8C6B] mr-2" />
Free initial text-based consultation
</li>
</ul>
</div>
</div>
</div>
</div>
);
};
export default PremiumBanner;

View File

@@ -0,0 +1,115 @@
"use client";
import React, { useState } from "react";
import { ChevronRight } from "lucide-react";
import Image from "next/image";
const PremiumBannerLast = () => {
const [selectedService, setSelectedService] = useState(0);
const services = [
{
title: "Expert Guidance",
description:
"Consultation provides access to expert advice and guidance from professionals who have in-depth knowledge and experience in their respective fields. We can offer valuable insights, strategies, and solutions tailored to your specific needs.",
imageUrl: ["/expert_guidance_1.jpg", "/expert_guidance_2.jpg"],
},
{
title: "Mantras For You",
description:
"Rudraksha experts can recommend specific mantras that align with your spiritual goals and intentions. Mantras are considered powerful tools for spiritual growth, and the right mantra can enhance the effectiveness of your Rudraksha.",
imageUrl: ["/mantra_1.jpg", "/mantra_2.jpg"],
},
{
title: "Your Birth Chart",
description:
"Rudraksha experts may also have knowledge of Vedic astrology. By analyzing your birth chart, they can provide insights into the planetary influences on your life and suggest Rudraksha combinations that may help balance and harmonize these influences.",
imageUrl: ["/birth_chart_1.jpg", "/birth_chart2.jpg"],
},
{
title: "Your Family Birth Chart",
description:
"Understanding the birth charts of family members can offer a holistic view of the energy dynamics within the family. Rudraksha experts can provide guidance on selecting Rudraksha beads that complement the energy of the entire family, fostering a harmonious environment.",
imageUrl: ["/family_chart1.jpg", "/family_chart_2.jpg"],
},
{
title: "Pooja Service Recommendation",
description:
"Rudraksha experts may recommend specific pooja services or rituals based on your spiritual needs and challenges. These rituals can be tailored to address specific concerns and promote positive energy flow in your life.",
imageUrl: ["/pooja_1.jpg", "/pooja_2.jpg"],
},
{
title: "Client Confidentiality",
description:
"Rudraksha experts, like other spiritual and holistic practitioners, typically uphold a strong code of client confidentiality. This ensures that personal and sensitive information shared during consultations is kept private and secure.",
imageUrl: ["/confidentiality_1.jpg", "/client_confidentiality_2.jpg"],
},
];
const handleServiceClick = (index) => {
setSelectedService(index);
};
return (
<div className="min-h-screen bg-slate-50 p-4">
<h1 className="sm:text-5xl sm:mt-24 text-2xl font-serif text-center tracking-wide mb-12">
Perks of Consulting an Expert
</h1>
<div className="grid sm:grid-cols-3 gap-8">
<div className="flex flex-col gap-4 sm:pl-10">
{services.map((service, index) => (
<div
key={index}
className="cursor-pointer"
onClick={() => handleServiceClick(index)}
>
<h2
className={`text-xl ${
selectedService === index ? "text-yellow-700" : ""
} hover:translate-x-4 hover:font-semibold hover:text-yellow-700 transition-all flex items-center`}
>
{selectedService === index ? (
<ChevronRight className="mr-2" size={20} />
) : (
""
)}
{service.title}
</h2>
</div>
))}
</div>
<div className="sm:col-span-2">
{selectedService !== null && (
<div className="bg-white p-6">
<div className="flex flex-col-reverse sm:flex-row gap-6">
<div className="flex flex-col gap-3 justify-start items-start sm:w-1/2">
<p className="mb-4 mt-2 text-[1.05rem]">
{services[selectedService].description}
</p>
<a href="#form">
<button className="px-5 font-semibold text-white bg-[#C19A5B] py-4">
Book now
</button>
</a>
</div>
<div className="flex gap-4 sm:w-1/2">
{services[selectedService].imageUrl.map((url, index) => (
<Image
key={index}
src={url}
alt={`${services[selectedService].title} - ${index + 1}`}
width={230}
height={350}
className="sm:w-[230px] sm:h-[350px] w-[130px] h-[250px] object-cover"
/>
))}
</div>
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default PremiumBannerLast;

View File

@@ -0,0 +1,21 @@
'use client'
import { FaArrowRightLong } from "react-icons/fa6";
import { FaWhatsapp } from "react-icons/fa";
import { useRouter } from "next/navigation";
const PremiumBannerOne = () => {
const router = useRouter()
return (
<div className="h-[65vh] bg-[url('/consultation_banner_1.webp')] ">
<div className="flex flex-col justify-start sm:w-3/4 p-4 sm:pl-52 sm:pt-28 ">
<h1 className="sm:text-5xl text-3xl sm:text-left text-center mb-5 tracking-wider sm:w-3/4 font-serif">Personalized Rudraksha Consultation for Your Sacred Journey</h1>
<h3 className="sm:text-xl sm:text-left text-center text-zinc-800 sm:w-3/4">Whether you seek clarity on selecting the right Rudraksha for your spiritual goals or a deeper understanding of the sacred beads, our consultations are crafted to provide you with the wisdom and direction you seek .</h3>
<div className="mt-6 flex gap-6 ">
<button onClick={()=> router.push('/products/premium-rudraksha-consultation-astrology')} className="bg-[#b68d40] sm:py-2 p-2 sm:px-5 font-bold text-white sm:text-xl justify-center sm:whitespace-nowrap flex items-center sm:gap-3">Book a consultation <FaArrowRightLong className="sm:my-3" size={26}/></button>
</div>
</div>
</div>
)
}
export default PremiumBannerOne;

View File

@@ -0,0 +1,24 @@
import React from "react";
const PremiumBannerTwo = () => {
return (
<div className="min-h-[60vh] mx-auto">
<h2 className="text-center sm:text-5xl mt-3 text-3xl font-serif sm:mt-16 tracking-wider mb-11">
Three Generations of Expertise
</h2>
<iframe
width="800"
className="mx-auto sm:h-[350px] h-[160px] mb-5 w-[300px] sm:w-[600px]"
height="450"
src="https://www.youtube.com/embed/_drMO01Mjtc"
title="Everything you need to know about Rudraksh | Keerthi History with Sukritya from Gupta Rudraksha"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
</div>
);
};
export default PremiumBannerTwo;

View File

@@ -0,0 +1,26 @@
import { categoriesForPremiumThree } from '@/utils'
import React from 'react'
const PremuimBannerThree = () => {
return (
<div className='min-h-[75vh]'>
<h2 className="text-center sm:text-5xl mt-3 font-[500] text-zinc-800 text-3xl font-serif sm:pt-20 pt-7 tracking-wide mb-11">
Who Should Book A Consultation?
</h2>
<div className="container mx-auto px-4">
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
{categoriesForPremiumThree.map((category, index) => (
<div key={index} className=" p-4 flex flex-col items-center text-center ">
<h2 className=' rounded-full h-20 w-20 bg-gradient-to-b from-[#E7DBC8] to-pink-50 flex items-center justify-center'>{category.logo}</h2>
<h3 className=" sm:text-lg text-sm font-semibold">{category.title}</h3>
<p className="mt-2 text-xs sm:text-[0.96rem] text-gray-600">{category.description}</p>
</div>
))}
</div>
</div>
</div>
)
}
export default PremuimBannerThree

View File

@@ -0,0 +1,39 @@
"use client";
import React, { useEffect, useState } from 'react'
import './privacy.css'
const PrivacyPolicy = () => {
const [htmlContent, setHtmlContent] = useState("");
const [loading,setLoading] = useState(false)
const fetchdata = async () => {
setLoading(true);
try {
const response = await fetch("/api/privacy-policy", {
method: "GET",
});
const resData = await response.json();
setHtmlContent(resData.data);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchdata();
}, []);
return (
<div className="privacy-policy-container">
{loading ? (
<div className="loading-message">Loading content, please wait...</div>
) : htmlContent ? (
<div dangerouslySetInnerHTML={{ __html: htmlContent }} />
) : (
<div className="no-content-message">No content available</div>
)}
</div>
)
}
export default PrivacyPolicy

View File

@@ -0,0 +1,60 @@
/* Styles for the refund policy container */
.privacy-policy-container {
margin: 0 auto;
padding: 20px;
max-width: 800px;
line-height: 1.6;
font-family: 'Arial', sans-serif;
}
/* General headings */
.privacy-policy-container h1 {
font-size: 2.5rem;
font-weight: bold;
margin-bottom: 20px;
text-align: center;
}
.privacy-policy-container h2 {
font-size: 1.75rem;
font-weight: 600;
margin-top: 30px;
margin-bottom: 15px;
color: #333;
}
/* Paragraph and text content */
.privacy-policy-container p {
font-size: 1rem;
margin-bottom: 15px;
color: #555;
}
/* Lists */
.privacy-policy-container ul {
padding-left: 20px;
margin-bottom: 20px;
}
.privacy-policy-container ul li {
margin-bottom: 10px;
font-size: 1rem;
}
/* Additional spacing and margins */
.privacy-policy-container .mt-5 {
margin-top: 1.5rem;
}
.privacy-policy-container .mb-5 {
margin-bottom: 1.5rem;
}
/* Add borders or backgrounds as needed */
.privacy-policy-container {
background-color: #f9f9f9;
border-radius: 10px;
padding: 25px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

View File

@@ -0,0 +1,128 @@
import React from "react";
import Image from "next/image";
const ProductGallery = () => {
const galleryImg = [
{
id: 1,
src: "/gallery1.jpg",
alt: "Gallery image 1",
text: "All Rudraksha",
},
{
id: 2,
src: "/gallery3.jpg",
alt: "Gallery image 2",
text: "Siddha Mala",
},
{
id: 3,
src: "/gallery2.jpg",
alt: "Gallery image 3",
text: "Murti & Yantra",
},
{
id: 4,
src: "/gallery4.png",
alt: "Gallery image 4",
text: "Rudraksha Combination",
},
{ id: 5, src: "/gallery5.webp", alt: "Gallery image 5", text: "Japa Mala" },
{
id: 6,
src: "/gallery6.jpg",
alt: "Gallery image 6",
text: "Kantha Mala",
},
{ id: 7, src: "/gallery7.webp", alt: "Gallery image 7", text: "Shaligram" },
];
const ImageWithOverlay = ({ src, alt, text, className }) => (
<div className={`relative overflow-hidden shadow-lg group ${className}`}>
<Image
src={src}
alt={alt}
layout="fill"
objectFit="cover"
className="transition-transform duration-300 group-hover:scale-110 "
/>
<div className="absolute inset-0 bg-black bg-opacity-50 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-center justify-center">
<p className="text-white text-lg font-semibold">{text}</p>
</div>
</div>
);
return (
<div className="min-h-screen bg-gray-100 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-8xl mx-auto">
<div className="text-center mb-12">
<h1 className="font-serif text-5xl text-slate-800 mb-4">
Product Categories
</h1>
<h2 className="text-xl text-slate-700">
Discover the Essence: Explore our Diverse Product Categories
</h2>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-3">
{/* Left column */}
<div className="grid grid-rows-2 gap-3">
<ImageWithOverlay
src={galleryImg[2].src}
alt={galleryImg[2].alt}
text={galleryImg[2].text}
className="h-[300px] cursor-pointer"
/>
<div className="grid grid-cols-2 gap-3 ">
<ImageWithOverlay
src={galleryImg[3].src}
alt={galleryImg[3].alt}
text={galleryImg[3].text}
className="h-[200px] cursor-pointer"
/>
<ImageWithOverlay
src={galleryImg[4].src}
alt={galleryImg[4].alt}
text={galleryImg[4].text}
className="h-[200px]"
/>
</div>
</div>
{/* Middle column */}
<ImageWithOverlay
src={galleryImg[1].src}
alt={galleryImg[1].alt}
text={galleryImg[1].text}
className="h-[520px]"
/>
{/* Right column */}
<div className="grid grid-rows-2 gap-3">
<ImageWithOverlay
src={galleryImg[0].src}
alt={galleryImg[0].alt}
text={galleryImg[0].text}
className="h-[300px]"
/>
<div className="grid grid-cols-2 gap-3">
<ImageWithOverlay
src={galleryImg[5].src}
alt={galleryImg[5].alt}
text={galleryImg[5].text}
className="h-[200px]"
/>
<ImageWithOverlay
src={galleryImg[6].src}
alt={galleryImg[6].alt}
text={galleryImg[6].text}
className="h-[200px]"
/>
</div>
</div>
</div>
</div>
</div>
);
};
export default ProductGallery;

View File

@@ -0,0 +1,53 @@
import React from "react";
import Image from "next/image";
const SecondGallery = () => {
return (
<div className="bg-[#f9f3f5c8] flex flex-col sm:flex-row justify-center items-center text-[#896C42] p-6 sm:p-12">
{/* Left Image */}
<div className="w-full sm:w-1/3 flex justify-center items-center p-4">
<Image
src="/product_swami.jpeg"
alt="Gupta Rudraksha"
width={300}
height={300}
className="rounded-lg shadow-lg"
/>
</div>
{/* Right content */}
<div className="w-full sm:w-1/3 flex flex-col justify-center items-center text-center p-4 sm:p-8">
<h2 className="text-3xl sm:text-4xl mb-5 font-serif tracking-wide">
Nepal&#39;s 1st & only
<span className="text-4xl sm:text-6xl block my-5 tracking-wider">
ISO Certified
</span>
Rudraksha Organization
</h2>
<p className="text-zinc-800 text-lg sm:text-xl mb-5 sm:w-3/4">
Explore the largest collection of authentic Gupta Rudraksha energized
as per our vedic process. For nearly 3+ generations Gupta Rudraksha
has been the pioneer of Rudraksha and Shaligram and has supported
millions of devotees attain spiritual and professional goals.
</p>
<h2 className="text-xl sm:text-2xl sm:w-3/4">
Gupta Rudraksha - The Only Vendor in the World To 100% Lifetime Money
Back Authenticity Guarantee.
</h2>
</div>
{/* Right Image */}
<div className="w-full sm:w-1/3 flex justify-center items-center p-4">
<Image
src="/temple.jpeg"
alt="Gupta Rudraksha Collection"
width={300}
height={300}
className="rounded-lg shadow-lg"
/>
</div>
</div>
);
};
export default SecondGallery;

View File

@@ -0,0 +1,94 @@
"use client";
import React, { useContext, useState } from "react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { ChevronLeft, ChevronRight } from "lucide-react";
import ProductContext from "@/app/contexts/productContext";
import { backendUrl } from "@/utils/axios";
import Image from "next/image";
const ProductGallery = ({ productId }) => {
const { products } = useContext(ProductContext);
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const nextImage = () => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % productImages.length);
};
const prevImage = () => {
setCurrentImageIndex(
(prevIndex) =>
(prevIndex - 1 + productImages.length) % productImages.length
);
};
const product = products?.find((pr) => pr.id == productId);
if (!product) {
return null;
}
const productImages = product?.images?.map((img) => img.image) || [];
return (
<div className="flex flex-col md:flex-row gap-4 p-4 sm:w-[70%] ">
<div className="hidden md:flex flex-col gap-2">
{productImages?.map((src, index) => (
<Image
key={index}
src={`${backendUrl}${src}`}
alt={`Thumbnail ${index + 1}`}
width={160} // Width of w-40 (160px)
height={128} // Height of h-32 (128px)
className="object-cover cursor-pointer border border-gray-300 hover:border-blue-500"
onClick={() => setCurrentImageIndex(index)}
/>
))}
</div>
<div className="flex-grow h-full">
<Card className="p-4 h-[380px] sm:h-[80vh]">
{/* Main image with carousel controls */}
<div className="relative mb-4 h-full">
<Image
src={`${backendUrl}${productImages[currentImageIndex]}`}
alt="Main product"
width={500}
height={500}
className="object-cover w-full h-full"
/>
<Button
className="absolute top-1/2 left-2 transform -translate-y-1/2 md:hidden"
onClick={prevImage}
variant="ghost"
>
<ChevronLeft />
</Button>
<Button
className="absolute top-1/2 right-2 transform -translate-y-1/2 md:hidden"
onClick={nextImage}
variant="ghost"
>
<ChevronRight />
</Button>
</div>
</Card>
<div className="my-6">
<div className="flex gap-3">
<h3 className="p-1 px-2 rounded-3xl border text-xs border-yellow-700">
A+ Grade
</h3>
<h3 className="p-1 px-2 rounded-3xl border text-xs border-yellow-700">
IRL Certified
</h3>
<h3 className="p-1 px-2 rounded-3xl border text-xs border-yellow-700">
Expert Rating
</h3>
</div>
<h2 className="mt-3">Note: Free Shipping on order above $ 300</h2>
<h2 className="my-1">100% Secured Payment</h2>
<h2>Authenticity Guaranteed</h2>
</div>
</div>
</div>
);
};
export default ProductGallery;

View File

@@ -0,0 +1,207 @@
"use client";
import React, { useContext, useState } from "react";
import { Plus, Minus } from "lucide-react";
import ProductContext from "@/app/contexts/productContext";
import { backendUrl } from "@/utils/axios";
import { useCurrency } from "@/app/contexts/currencyContext";
import Link from "next/link";
import Image from "next/image";
function ProductDetails({ productId }) {
const [quantity, setQuantity] = useState(1);
const [selectedSize, setSelectedSize] = useState(null);
const [selectedDesign, setSelectedDesign] = useState(null);
const [termsAccepted, setTermsAccepted] = useState(false);
const { products, cartFn } = useContext(ProductContext);
const { formatPrice, isLoading } = useCurrency();
const product = products?.find((pr) => pr.id == productId);
React.useEffect(() => {
if (product && product.variants?.length > 0) {
setSelectedSize(product.variants[0]?.size?.size_name || "");
setSelectedDesign(product.design_associations?.[0]?.design?.id || "");
}
}, [product]);
if (!product) return null;
const hasVariants = product.variants?.length > 0;
const hasDesigns = product.design_associations?.length > 0;
const selectedVariant = hasVariants
? product.variants.find((v) => v.size.size_name === selectedSize)
: null;
const currentPrice = selectedVariant?.price || product.price || 0;
const designPrice = hasDesigns
? product.design_associations.find((d) => d.design.id === selectedDesign)
?.design.design_price || 0
: 0;
const totalPrice = currentPrice + designPrice;
return (
<div className="max-w-xl p-6 space-y-6">
<div className="flex justify-between items-start">
<h1 className="text-2xl font-semibold">{product.product_name}</h1>
</div>
{hasVariants ? (
<div className="flex items-center">
<span className="text-2xl text-[#C17A0F]">
{isLoading ? (
<span>Loading...</span>
) : (
<span>{formatPrice(totalPrice)}</span>
)}
</span>
<span className="ml-2 text-sm">INR</span>
</div>
) : (
<div className="text-2xl text-[#C17A0F]">Price on request</div>
)}
<div className="space-y-4">
{hasVariants && (
<div>
<h3 className="text-sm mb-2">Select Size</h3>
<div className="flex space-x-4">
{product.variants.map((variant) => (
<button
key={variant.size.id}
className={`px-4 py-2 border rounded ${
selectedSize === variant.size.size_name
? "border-[#C17A0F]"
: "border-gray-300"
}`}
onClick={() => setSelectedSize(variant.size.size_name)}
>
{variant.size.size_name}
</button>
))}
</div>
</div>
)}
{hasDesigns && (
<div>
<h3 className="text-sm mb-2">Select Your Design</h3>
<div className="grid grid-cols-4 gap-4">
{product.design_associations.map((design) => (
<button
key={design.id}
className={`p-2 border rounded text-center ${
selectedDesign === design.design.id
? "border-[#C17A0F]"
: "border-gray-300"
}`}
onClick={() => setSelectedDesign(design.design.id)}
>
<div className="h-12 w-12 mx-auto mb-2 bg-gray-200">
<Image
src={`${backendUrl}${design.design.design_icon}`}
alt={design.design.design_name}
width={48}
height={48}
className="w-full h-full object-cover rounded-full"
/>
</div>
<div className="text-sm">{design.design.design_name}</div>
<div className="text-sm text-gray-500">
{isLoading ? (
<span>Loading...</span>
) : (
<span>{formatPrice(design.design.design_price)}</span>
)}
</div>
</button>
))}
</div>
</div>
)}
<div>
{product?.product_category?.category_name && (
<h3 className="text-sm mb-2">
Category: {product.product_category.category_name}
</h3>
)}
{product?.product_subcategory?.subcategory_name && (
<p className="text-sm">
Subcategory: {product.product_subcategory.subcategory_name}
</p>
)}
</div>
{hasVariants && (
<>
<div className="flex items-center justify-between border rounded-md p-2 w-32">
<button
onClick={() => setQuantity(Math.max(1, quantity - 1))}
className="p-2"
>
<Minus className="w-4 h-4" />
</button>
<span>{quantity}</span>
<button
onClick={() => setQuantity(quantity + 1)}
className="p-2"
disabled={quantity >= selectedVariant?.stock}
>
<Plus className="w-4 h-4" />
</button>
</div>
<div className="text-sm">
Stock:{" "}
{selectedVariant?.stock > 0 ? "available" : "Not Available"}
</div>
</>
)}
<div className="text-sm">
<input
type="checkbox"
className="mr-2"
checked={termsAccepted}
onChange={(e) => setTermsAccepted(e.target.checked)}
/>
<span>I agree with the </span>
<Link href="/policies/terms-of-services" className="text-blue-600">
terms of services
</Link>
<span> and </span>
<Link href="/policies/refund-policy" className="text-blue-600">
return And Cancellation policy
</Link>
</div>
{hasVariants && selectedVariant?.stock > 0 ? (
<button
onClick={() => cartFn(selectedVariant.id, selectedDesign, quantity)}
disabled={!termsAccepted}
className={`w-full py-3 rounded-md ${
termsAccepted
? "bg-[#C17A0F] text-white cursor-pointer"
: "bg-gray-300 text-gray-500 cursor-not-allowed"
}`}
>
ADD TO CART
</button>
) : (
<button className="w-full bg-[#C17A0F] text-white py-3 rounded-md">
REQUEST PRICE
</button>
)}
<div className="mt-8 border-t pt-6">
<h2 className="text-xl font-semibold mb-4">Product Description</h2>
<div
dangerouslySetInnerHTML={{ __html: product.description }}
className="text-sm prose prose-sm max-w-none"
/>
</div>
</div>
</div>
);
}
export default ProductDetails;

View File

@@ -0,0 +1,63 @@
"use client";
import React, { useContext } from "react";
import Image from "next/image";
import Link from "next/link";
import { productsCards } from "@/utils";
import ProductContext from "@/app/contexts/productContext";
import { backendUrl } from "@/utils/axios";
const RelatedProductCards = ({ productId }) => {
const { products } = useContext(ProductContext);
if (!products) {
return null;
}
const product = products?.find((pr) => pr.id == productId);
const relatedProducts = products?.filter(
(prod) => prod.product_category.id == product.id && prod.id != productId
);
if (relatedProducts.length == 0) {
return null;
}
return (
<div className="container mx-auto min-h-[70vh] px-4 py-8 max-w-8xl ">
<div className="text-center mb-12">
<h1 className="font-serif capitalize tracking-wide font-semibold text-5xl text-slate-800 mb-4">
You may also like
</h1>
</div>
<div className="overflow-x-auto sm:pl-[400px] hide-navbar gap-5 flex items-center justify-center">
{relatedProducts.map((product) => (
<Link href={`/products/${product.id}`} key={product.id}>
<div
key={product.id}
className="relative bg-[#EDE8E0] overflow-hidden sm:h-[350px] sm:w-[300px] "
>
<div className="absolute top-0 left-0 bg-[#C19A5B] text-white py-1 px-3 rounded-br-lg z-10">
Exclusive
</div>
<div className="sm:h-[300px] h-[200px] w-[200px] sm:w-[300px] flex items-center justify-center overflow-hidden">
<Image
src={`${backendUrl}${product?.images[0]?.image}`}
alt={`Logo for ${product.title}`}
width={300}
height={300}
className="w-full h-full object-cover hover:scale-125 transition-transform ease-in-out duration-300"
/>
</div>
<div className="p-4 ">
<h3 className="text-center text-[1rem] uppercase text-gray-800">
{product.title}
</h3>
</div>
</div>
</Link>
))}
</div>
</div>
);
};
export default RelatedProductCards;

View File

@@ -0,0 +1,49 @@
import React from 'react';
const RelatedVideos = () => {
return (
<>
<h1 className='sm:text-5xl text-2xl my-7 text-zinc-800 font-semibold text-center '>Videos of Related Products</h1>
<div className='flex min-h-[30vh] gap-8 overflow-x-auto p-4 hide-navbar'>
<iframe
className='w-[400px] h-[200px] sm:h-[200px] sm:w-[800px]'
src="https://www.youtube.com/embed/6BdXUaqEkkw"
title="Powerful Surya (Sun) Mantra from Veda and Purana | Surya Beej Mantra 11 Times each | Beej Mantra"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
<iframe
className='w-[400px] h-[200px] sm:h-[200px] sm:w-[800px]'
src="https://www.youtube.com/embed/-iAAhrVtllk"
title="Powerful Shukra (Venus) Mantra | Vedic Puranic and Beej Mantra | 11 Times Each | Shukra Mantra"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
<iframe
className='w-[400px] h-[200px] sm:h-[200px] sm:w-[800px]'
src="https://www.youtube.com/embed/0zX7RyTYFxo"
title="Powerful Mars Mangal Mantra | Vedic, Puranic and Beej | Chanted 11 times Powerful Mantra"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
<iframe
className='w-[400px] h-[200px] sm:h-[200px] sm:w-[800px]'
src="https://www.youtube.com/embed/MLapeBFvk9s"
title="Powerful Brihaspati (Guru) Jupiter Mantra | Vedic, Puranic & Beej Mantra | Chanted 11 Times each"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
</div>
</>
);
};
export default RelatedVideos;

View File

@@ -0,0 +1,136 @@
"use client";
import React from "react";
const RefundPolicy = () => {
return (
<div className="bg-white min-h-screen">
<div className="text-gray-800 p-4 sm:p-8 max-w-4xl w-full sm:w-4/6 lg:w-2/6 mx-auto my-8">
<h1 className="text-3xl sm:text-5xl font-emilys text-center mb-8">
Return and Cancellation Policy
</h1>
<p className="text-justify text-base sm:text-lg mb-6">
At <strong>Gupta Rudraksha and Beads</strong>, we are committed to
providing you with a divine and satisfying shopping experience for all
your sacred needs, including Rudraksha beads, Shaligrams, and Japa
Malas. Our policy ensures your peace of mind and convenience.
</p>
<hr className="my-6" />
<h2 className="text-xl sm:text-2xl font-semibold mb-4 font-emilys">
Returns and Exchanges
</h2>
<ul className="list-disc list-inside space-y-3 mb-6">
<li>
<strong>Eligibility:</strong> If you are not completely satisfied
with your purchase, you may return or exchange the item within{" "}
<strong>10 days of delivery</strong>. To qualify:
<ul className="list-disc list-inside pl-4 sm:pl-6">
<li>The item must be unused and in its original condition.</li>
<li>
It should include the original packaging and proof of purchase.
</li>
</ul>
</li>
<li>
<strong>Process:</strong> To initiate a return or exchange, please
email us at <strong>nepali.rudrakshabeads@gmail.com</strong> with
your order details. Our team will guide you through the process
promptly.
</li>
<li>
<strong>Refunds:</strong>
<ul className="list-disc list-inside pl-4 sm:pl-6">
<li>
Once we receive and inspect the returned item, we will notify
you of the approval or rejection of your refund.
</li>
<li>
If approved, the refund will be processed to your original
payment method within <strong>7-10 business days</strong>.
</li>
</ul>
</li>
</ul>
<hr className="my-6" />
<h2 className="text-xl sm:text-2xl font-semibold font-emilys mb-4">
Order Cancellations
</h2>
<ul className="list-disc list-inside space-y-3 mb-6">
<li>
<strong>Cancellation Window:</strong> You can cancel your order
within <strong>24 hours of placing it</strong> by emailing us at{" "}
<strong>nepali.rudrakshabeads@gmail.com</strong>.
</li>
<li>
<strong>After 24 Hours:</strong> If the order has already been
processed or shipped, cancellations will not be accepted, but you
may proceed with a return after delivery (refer to the Returns
policy).
</li>
</ul>
<hr className="my-6" />
<h2 className="text-xl sm:text-2xl font-semibold font-emilys mb-4">
Non-Returnable Items
</h2>
<ul className="list-disc list-inside space-y-3 mb-6">
<li>Customized or personalized products.</li>
<li>Items damaged due to mishandling after delivery.</li>
</ul>
<p className="text-base sm:text-lg mb-6">
For more clarity, feel free to contact us before purchasing.
</p>
<hr className="my-6" />
<h2 className="text-xl sm:text-2xl font-semibold font-emilys mb-4">
Shipping Costs
</h2>
<ul className="list-disc list-inside space-y-3 mb-6">
<li>
<strong>Returns:</strong> Customers are responsible for the shipping
costs associated with returning items. Shipping fees are
non-refundable.
</li>
<li>
<strong>Exchanges:</strong> If you receive a defective or incorrect
item, <strong>Gupta Rudraksha and Beads</strong> will cover the
shipping costs for the return and replacement.
</li>
</ul>
<hr className="my-6" />
<h2 className="text-xl sm:text-2xl font-semibold font-emilys mb-4">
Contact Us
</h2>
<p className="text-base sm:text-lg mb-6">
Your satisfaction is our utmost priority. For any queries or
assistance regarding returns, exchanges, or cancellations, please
contact us at:
</p>
<p className="text-base sm:text-lg mb-6">
📧 <strong>nepali.rudrakshabeads@gmail.com</strong>
</p>
<p className="text-base sm:text-lg mb-6">
We are here to ensure your experience with{" "}
<strong>Gupta Rudraksha and Beads</strong> is as spiritual and
fulfilling as the sacred items you purchase.
</p>
<hr className="my-6" />
<p className="text-sm text-gray-600 italic">
*Note: This policy is subject to updates without prior notice. Please
review it periodically for any changes.*
</p>
</div>
</div>
);
};
export default RefundPolicy;

View File

@@ -0,0 +1,60 @@
/* Styles for the refund policy container */
.refund-policy-container {
margin: 0 auto;
padding: 20px;
max-width: 800px;
line-height: 1.6;
font-family: 'Arial', sans-serif;
}
/* General headings */
.refund-policy-container h1 {
font-size: 2.5rem;
font-weight: bold;
margin-bottom: 20px;
text-align: center;
}
.refund-policy-container h2 {
font-size: 1.75rem;
font-weight: 600;
margin-top: 30px;
margin-bottom: 15px;
color: #333;
}
/* Paragraph and text content */
.refund-policy-container p {
font-size: 1rem;
margin-bottom: 15px;
color: #555;
}
/* Lists */
.refund-policy-container ul {
padding-left: 20px;
margin-bottom: 20px;
}
.refund-policy-container ul li {
margin-bottom: 10px;
font-size: 1rem;
}
/* Additional spacing and margins */
.refund-policy-container .mt-5 {
margin-top: 1.5rem;
}
.refund-policy-container .mb-5 {
margin-bottom: 1.5rem;
}
/* Add borders or backgrounds as needed */
.refund-policy-container {
background-color: #f9f9f9;
border-radius: 10px;
padding: 25px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

View File

@@ -0,0 +1,149 @@
import React, { useState, useContext, useRef, useEffect } from "react";
import { Search } from "lucide-react";
import Link from "next/link";
import ProductContext from "@/app/contexts/productContext";
import { backendUrl } from "@/utils/axios";
import Image from "next/image";
const SearchComponent = ({ isScrolled }) => {
const [searchTerm, setSearchTerm] = useState("");
const [showSuggestions, setShowSuggestions] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);
const { products, category } = useContext(ProductContext);
const searchRef = useRef(null);
const filteredProducts = products
?.filter((product) =>
product.product_name.toLowerCase().includes(searchTerm.toLowerCase())
)
.slice(0, 5);
const filteredCategories = category
?.filter((category) =>
category.category_name.toLowerCase().includes(searchTerm.toLowerCase())
)
.slice(0, 3);
useEffect(() => {
const handleClickOutside = (event) => {
if (searchRef.current && !searchRef.current.contains(event.target)) {
setShowSuggestions(false);
if (isScrolled) setIsExpanded(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [isScrolled]);
const handleSearchChange = (e) => {
setSearchTerm(e.target.value);
setShowSuggestions(true);
};
const SearchInput = () => (
<div className="flex items-center border bg-white">
<input
type="text"
value={searchTerm}
onChange={handleSearchChange}
onFocus={() => setShowSuggestions(true)}
placeholder="Search products..."
className="p-2 outline-none w-full"
/>
<Search size={20} className="mx-2" />
</div>
);
const Suggestions = () => {
if (!showSuggestions || !searchTerm) return null;
const hasResults =
filteredCategories?.length > 0 || filteredProducts?.length > 0;
return (
<div className="absolute z-50 bg-white shadow-lg w-full mt-2 rounded-md overflow-hidden">
{!hasResults && searchTerm && (
<div className="p-4 text-center text-gray-500">No results found</div>
)}
{filteredCategories?.length > 0 && (
<div className="border-b">
<div className="p-2 bg-gray-50 text-sm font-medium">Categories</div>
{filteredCategories.map((category) => (
<Link
key={category.id}
href={`/collections/${category.id}`}
className="block p-2 hover:bg-gray-50"
onClick={() => {
setShowSuggestions(false);
setIsExpanded(false);
}}
>
{category.category_name}
</Link>
))}
</div>
)}
{filteredProducts?.length > 0 && (
<div>
<div className="p-2 bg-gray-50 text-sm font-medium">Products</div>
{filteredProducts.map((product) => (
<Link
key={product.id}
href={`/products/${product.id}`}
className="block p-2 hover:bg-gray-50"
onClick={() => {
setShowSuggestions(false);
setIsExpanded(false);
}}
>
<div className="flex items-center gap-2">
{product.images?.[0] && (
<Image
src={`${backendUrl}${product.images[0].image}`}
alt={product.product_name}
width={32}
height={32}
className="object-cover"
/>
)}
<span>{product.product_name}</span>
</div>
</Link>
))}
</div>
)}
</div>
);
};
return (
<div ref={searchRef} className="relative">
{isScrolled ? (
<>
<button
onClick={() => setIsExpanded(!isExpanded)}
className="cursor-pointer"
>
<Search size={20} />
</button>
{isExpanded && (
<div className="absolute right-0 top-12 bg-white shadow-lg w-72 p-4">
<SearchInput />
<Suggestions />
</div>
)}
</>
) : (
<div className="w-64">
<SearchInput />
<Suggestions />
</div>
)}
</div>
);
};
export default SearchComponent;

View File

@@ -0,0 +1,63 @@
import Image from "next/image";
import Link from "next/link";
import React from "react";
const ListOfShaligram = () => {
const shaligrams = [
{
title: "Buddha Shaligram",
imageUrl: "/shaligram/buddha-shaligram-829.webp",
},
{
title: "Matsya Shaligram",
imageUrl: "/shaligram/matsya-shaligram-614.webp",
},
{
title: "Narsimha Shaligram",
imageUrl: "/shaligram/narasimha-shaligram-977.webp",
},
{
title: "Parashurama Shaligram",
imageUrl: "/shaligram/parashurama-shaligram-855.webp",
},
{
title: "Rama Shaligram",
imageUrl: "/shaligram/rama-shaligram-313.webp",
},
{
title: "Vamana Shaligram",
imageUrl: "/shaligram/vamana-shaligram-750.webp",
},
];
return (
<div className="p-4">
<h1 className="sm:text-5xl font-serif text-zinc-800 mt-10 text-center py-8">
Vishnu Dashavatar Shaligrams
</h1>
<div className="flex flex-wrap gap-7 max-w-6xl mx-auto">
{shaligrams.map((item, index) => (
<>
<div key={index} className="flex flex-col ">
<Link href={`/products/${item.title}`}>
<div className="bg-[#dfdbdf] p-4 sm:w-[320px] w-[150px] h-[200px] sm:h-[280px]">
<Image
src={item.imageUrl}
alt={item.title}
width={320}
height={260}
className="w-full sm:h-[260px] object-cover rounded"
/>
</div>
</Link>
<h3 className="sm:text-xl w- font-semibold mb-2">{item.title}</h3>
</div>
</>
))}
</div>
</div>
);
};
export default ListOfShaligram;

View File

@@ -0,0 +1,91 @@
import React from "react";
const ShippingPolicy = () => {
return (
<div className="flex justify-center items-center min-h-screen bg-gray-50">
<div className="max-w-4xl bg-white p-8 shadow-lg rounded-lg">
<h1 className="text-4xl font-bold text-center mb-6 text-zinc-900">
Gupta Rudraksha Shipping Policy
</h1>
<p className="text-lg mb-4">
Welcome to Gupta Rudraksha, where we are committed to providing our
customers with an exceptional shopping experience. Our dedication
extends beyond just offering high-quality Rudraksha beads and
accessories; we ensure that every part of your journey with us,
especially shipping, is handled with care and precision.
</p>
<h2 className="text-2xl font-semibold mb-4 underline">
Our Commitment to Fast & Secure Delivery
</h2>
<p className="text-lg mb-4">
We understand that receiving your products safely and promptly is
crucial. To achieve this, Gupta Rudraksha has partnered with leading
global delivery services, renowned for their efficiency and
reliability. Our logistics partners are carefully selected to uphold
our high standards of delivery, ensuring that every package reaches
its destination in perfect condition.
</p>
<h2 className="text-2xl font-semibold mb-4 underline">
Defined Shipping Timelines
</h2>
<p className="text-lg mb-4">
We strive to make our delivery process as transparent and predictable
as possible. Our shipping timelines are specifically designed to
inform you of when to expect your order:
</p>
<ul className="list-disc list-inside mb-4">
<li className="text-lg">Minimum Delivery Time: 5 days</li>
<li className="text-lg">Maximum Delivery Time: 10 days</li>
</ul>
<p className="text-lg mb-4">
This accounts for any unforeseen circumstances that may affect transit
times, including geographic distance, customs clearances for
international orders, and carrier operational delays.
</p>
<h2 className="text-2xl font-semibold mb-4 underline">
Tracking Your Order
</h2>
<p className="text-lg mb-4">
Once your order is dispatched, you will receive a tracking number that
allows you to follow the progress of your shipment. This service is
part of our commitment to provide you with peace of mind from the
moment you complete your purchase until your package is safely
delivered.
</p>
<h2 className="text-2xl font-semibold mb-4 underline">
Customer Support
</h2>
<p className="text-lg">
Should you have any questions about your order&apos;s shipping status or
our shipping practices, our customer service team is here to assist
you. We pride ourselves on our responsive and helpful customer support
that is ready to solve any issue and answer any query.
</p>
<p className="text-lg mt-6">
We appreciate your trust in Gupta Rudraksha, and we pledge to
continually optimize our shipping practices to enhance your overall
experience with us.
</p>
<h2 className="text-2xl font-semibold mb-4 underline">
Delivery Services Used:
</h2>
<p className="text-lg mt-6">
Note: Gupta Rudraksha only uses the expedited shipping options and
ensures the fastest delivery using any of the above courier services
based on their estimated delivery date. BlueDart is used for
deliveries all over India.
</p>
</div>
</div>
);
};
export default ShippingPolicy;

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { ShoppingBag } from 'lucide-react';
import Link from 'next/link';
const EmptyCart = () => {
return (
<div className="w-full bg-white">
<div className="w-full px-4 md:px-8 max-w-[1600px] mx-auto font-['Inter']">
<h1 className="text-center text-2xl font-medium mb-12 tracking-wide">
SHOPPING CART
</h1>
<div className="flex flex-col items-center justify-center py-16 space-y-6">
<div className="relative">
<div className="w-24 h-24 rounded-full bg-gray-50 flex items-center justify-center">
<ShoppingBag size={48} className="text-[#c19a5b]" />
</div>
</div>
<div className="text-center space-y-2">
<h2 className="text-xl font-medium text-gray-900">Your cart is empty</h2>
<p className="text-gray-500">Looks like you haven&apos;t added any items to your cart yet</p>
</div>
<Link
href='/pages/buy-rudraksha'
className="bg-[#c19a5b] hover:bg-[#ab885b] text-white px-8 py-3 font-medium transition-colors"
>
Continue Shopping
</Link>
</div>
</div>
</div>
);
};
export default EmptyCart;

View File

@@ -0,0 +1,245 @@
"use client";
import React, { useContext, useEffect, useState } from "react";
import { Trash2, Plus } from "lucide-react";
import authAxios, { backendUrl } from "@/utils/axios";
import ProductContext from "@/app/contexts/productContext";
import EmptyCart from "./emptyCart";
import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
import axios from "axios";
import { useRouter } from "next/navigation";
import PaymentComponent from "../payment/paymentComponent";
import { useCurrency } from "@/app/contexts/currencyContext";
import Link from "next/link";
import Image from "next/image";
import toast from "react-hot-toast";
const ShoppingCart = () => {
const [cartItems, setCartItems] = useState(null);
const [error, setError] = useState(null);
const router = useRouter();
const { cartFn } = useContext(ProductContext);
const { formatPrice } = useCurrency();
const getCart = async () => {
const response = await authAxios.get("/orders/cart/");
setCartItems(response.data);
};
useEffect(() => {
getCart();
}, []);
const handleQuantityChange = async (variantId, designId, quantityChange) => {
const response = await cartFn(variantId, designId, quantityChange);
console.log(response)
if (response?.status == 200) {
setCartItems((prev) => {
if (!prev) return prev;
const updatedItems = prev[0].items.map((item) => {
if (item.variant.id === variantId && item?.design?.id === designId) {
const updatedQuantity = item.quantity + quantityChange;
const updatedTotalPrice =
(item.variant.price + (item?.design?.design_price || 0)) *
updatedQuantity;
if (updatedQuantity <= 0) {
return null;
}
return {
...item,
quantity: updatedQuantity,
total_price: updatedTotalPrice,
};
}
return item;
});
const filteredItems = updatedItems.filter((item) => item !== null);
return [
{
...prev[0],
items: filteredItems,
total_amount: filteredItems.reduce(
(sum, item) => sum + item.total_price,
0
),
},
];
});
}
};
if (!cartItems) {
return null;
}
if (!cartItems[0]?.items?.length) {
return <EmptyCart />;
}
const handlePaymentSuccess = async (order) => {
console.log("Payment SuccessFul", order);
const response = await authAxios.post("/orders/payment/", {
orderId: order.id,
payer_mail: order.payer.email_address,
address: order.purchase_units[0].shipping.address,
name: order.purchase_units[0].shipping.name.full_name,
cartId: cartItems[0].id,
});
router.push('/accounts/profile/orders')
toast.success('You Order Is Successfull!')
console.log(response);
};
return (
<div className="w-full bg-white">
<div className="w-full px-4 md:px-8 max-w-[1600px] mx-auto font-['Inter']">
<h1 className="text-center text-2xl font-medium mb-12 tracking-wide">
SHOPPING CART
</h1>
<div className="space-y-6 relative">
<div className="hidden lg:grid lg:grid-cols-[1fr,auto,120px,auto,50px] lg:gap-8 text-sm text-gray-500 mb-4 pr-2">
<div />
<div className="w-[140px] text-right">Price</div>
<div className="text-center">Quantity</div>
<div className="w-[140px] text-right">Total</div>
<div />
</div>
{cartItems[0]?.items?.map((item) => (
<div className="relative" key={item.id}>
<div className="flex flex-col lg:flex-row lg:items-center">
<div className="flex items-start gap-4 mb-4 lg:mb-0 lg:flex-1">
<Image
src={item.variant?.product?.images[0]?.image}
alt="Siddha Mala"
width={80}
height={80}
className="object-cover bg-gray-100"
/>
<div className="space-y-1">
<h3 className="font-medium">
{item.variant.product.product_name}
</h3>
{item.variant.size?.size_name && (
<p className="text-sm text-gray-600">
Size: {item.variant.size.size_name}
</p>
)}
{item?.design?.design_name && (
<p className="text-sm text-gray-600">
Your Design: {item.design.design_name}
</p>
)}
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-[140px,120px,140px,50px] lg:gap-8 items-center">
<span className="text-gray-900 text-right">
{formatPrice(
item.variant.price + (item.design?.design_price || 0)
)}
</span>
<div className="flex items-center bg-gray-50 px-2 justify-center">
{item.quantity > 1 && (
<button
onClick={() =>
handleQuantityChange(
item.variant.id,
item?.design?.id,
-1
)
}
className="px-2 py-2 text-[#c19a5b] hover:text-[#ab885b]"
>
-
</button>
)}
<span className="px-3 py-2">{item.quantity}</span>
<button
onClick={() =>
handleQuantityChange(
item.variant.id,
item?.design?.id,
+1
)
}
className="px-2 py-2 text-[#c19a5b] hover:text-[#ab885b]"
>
+
</button>
</div>
<span className="text-gray-900 text-right">
{formatPrice(item.total_price)}
</span>
<button className="text-[#c19a5b] hover:text-[#ab885b] justify-self-center">
<Trash2
size={18}
onClick={() =>
handleQuantityChange(
item.variant.id,
item.design.id,
-item.quantity
)
}
/>
</button>
</div>
</div>
<div className="h-px w-full bg-gradient-to-r from-transparent via-gray-200 to-transparent my-6" />
</div>
))}
</div>
<div className="flex flex-col sm:flex-row gap-4 sm:gap-8 mt-8">
<button className="text-[#c19a5b] hover:text-[#ab885b] font-medium order-2 sm:order-1">
CONTINUE SHOPPING
</button>
<button className="text-[#c19a5b] hover:text-[#ab885b] sm:ml-auto font-medium order-1 sm:order-2">
CLEAR SHOPPING CART
</button>
</div>
<div className="flex justify-center ml-96 mr-96">
<div className="space-y-4 w-full max-w-md mx-auto lg:max-w-none">
<div className="flex justify-between">
<span>SUBTOTAL</span>
<span>{formatPrice(cartItems[0].total_amount)}</span>
</div>
<div className="flex justify-between font-medium">
<span>GRAND TOTAL</span>
<span className="text-[#c19a5b]">
{formatPrice(cartItems[0].total_amount)}
</span>
</div>
<label className="flex items-center gap-2">
<input type="checkbox" className="accent-[#c19a5b]" />
<span className="text-sm">
I agree with the{" "}
<Link
href="/policies/terms-of-services"
className="text-blue-600"
>
terms of services
</Link>{" "}
and{" "}
<Link href="/policies/refund-policy" className="text-blue-600">
return And Cancellation policy.
</Link>
</span>
</label>
<PaymentComponent
amount={cartItems[0].total_amount}
onSuccess={handlePaymentSuccess}
/>
</div>
</div>
</div>
</div>
);
};
export default ShoppingCart;

View File

@@ -0,0 +1,69 @@
"use client";
import Link from "next/link";
import React, { useContext } from "react";
import { backendUrl } from "@/utils/axios";
import Image from "next/image";
import { useCurrency } from "@/app/contexts/currencyContext";
import ProductContext from "@/app/contexts/productContext";
export default function ExploreSiddhaMala({ params }) {
const { products, category } = useContext(ProductContext);
const { formatPrice, isLoading } = useCurrency();
const filteredProducts = products?.filter(
(product) => product.product_category?.id == params.id
);
const selectedCategory = category?.find((cat) => cat.id == params.id);
return (
<section className="py-16 bg-gray-50">
<div className="container mx-auto px-4">
<h2 className="text-4xl font-bold text-center text-gray-800 mb-12">
Explore{" "}
{selectedCategory ? selectedCategory.category_name : "Products"}
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8">
{filteredProducts?.map((product) => (
<div
key={product.id}
className="bg-white shadow-lg rounded-lg overflow-hidden transition-transform transform hover:scale-105"
>
<Link href={`/products/${product.id}`}>
<div className="relative w-full h-64 bg-gray-200">
<Image
src={`${backendUrl}${product?.images[0]?.image}`}
alt={product.product_name}
layout="fill"
objectFit="cover"
className="rounded-t-lg"
/>
</div>
</Link>
<div className="p-5">
<h3 className="text-lg font-semibold text-gray-900 mb-2 truncate">
{product.product_name}
</h3>
{product.variants?.length > 0 ? (
<p className="text-lg font-bold text-green-600">
{isLoading
? "Loading..."
: formatPrice(
Math.min(
...product.variants.map((variant) => variant.price)
)
)}
</p>
) : (
<p className="text-md font-medium text-gray-500">
Price on request
</p>
)}
</div>
</div>
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,56 @@
import React from "react";
const SiddhaThree = () => {
return (
<div className="bg-[#F5F1EB] min-h-screen py-12 px-6 sm:px-12">
<h1 className="sm:pt-14 pb-10 font-serif mt-4 sm:text-6xl text-3xl text-zinc-800 text-center">
Design Available
</h1>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-4 gap-8">
{[
{
title: "Loose Beads/Red Thread",
description:
"Loose beads provide flexibility in crafting your own unique Rudraksha accessories. Ideal for those who wish to design custom malas or incorporate Rudraksha beads into existing jewelry pieces.",
image: "/sidhi-mala/1.webp",
},
{
title: "Silver Capped",
description:
"Silver-capped Rudraksha beads add an elegant touch to your spiritual accessories. The silver caps not only enhance the aesthetics but also provide additional durability.",
image: "/sidhi-mala/2_01d4b37c-ade7-44a1-8847-b63ca7945b5b.webp",
},
{
title: "Silver Chain",
description:
"A Rudraksha chain with silver links combines the sacred energy of Rudraksha with the elegance of silver. The chain design allows for a more versatile and adjustable accessory, suitable for daily wear.",
image: "/sidhi-mala/3_4bb67323-1af4-4167-9f11-34cdab60e320.webp",
},
{
title: "Rudraksha Chain",
description:
"A Rudraksha chain with silver links combines the sacred energy of Rudraksha with the elegance of silver. The chain design allows for a more versatile and adjustable accessory, suitable for daily wear.",
image: "/sidhi-mala/4_b5f14d83-0ef5-4e47-8e96-d36db882aadc.webp",
},
].map((item, index) => (
<div
key={index}
className="relative text-white flex flex-col justify-end h-64 sm:h-80 bg-cover bg-center bg-no-repeat w-full p-6 rounded-lg shadow-lg hover:shadow-xl transition-shadow duration-300"
style={{ backgroundImage: `url(${item.image})` }}
>
<div className="bg-black bg-opacity-50 p-4 rounded-lg">
<h1 className="sm:text-2xl text-lg font-bold mb-2">
{item.title}
</h1>
<h3 className="sm:text-sm text-xs leading-relaxed">
{item.description}
</h3>
</div>
</div>
))}
</div>
</div>
);
};
export default SiddhaThree;

View File

@@ -0,0 +1,65 @@
"use client";
import { useContext } from "react";
import Image from "next/image";
import { motion } from "framer-motion";
import ProductContext from "@/app/contexts/productContext";
import { Button } from "@/components/ui/button";
const cleanHTML = (html) => {
if (!html) return "";
return html.replace(/style="[^"]*color:[^;]*;?"/gi, "");
};
const CategoryHero = ({ params }) => {
const { category } = useContext(ProductContext);
const selectedCategory = category?.find((cat) => cat.id == params.id);
// Fallback values
const fallbackImage = "/placeholder-image.jpg";
const fallbackDescription =
"Explore our curated collection of spiritual items designed to enhance your journey of self-discovery and inner peace.";
const fallbackCategoryName = "Spiritual Essentials";
return (
<section className="relative h-[50vh] flex items-center justify-center overflow-hidden">
<div className="absolute inset-0 z-0">
<Image
src="/sidhi-mala/Artboard_1_bf5ccd46-7152-4355-82a8-9e9f27c1bfc2.jpg"
alt="Category Background"
layout="fill"
objectFit="cover"
quality={100}
priority
className="brightness-75"
/>
</div>
<div className="relative z-10 text-center px-6 md:px-12 max-w-3xl">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="text-4xl md:text-6xl font-bold text-white mb-4 drop-shadow-lg"
>
{selectedCategory?.category_name || fallbackCategoryName}
</motion.h1>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.2 }}
className="text-lg md:text-xl text-gray-200 drop-shadow-md"
dangerouslySetInnerHTML={{
__html: cleanHTML(
selectedCategory?.descriptions || fallbackDescription
),
}}
/>
</div>
</section>
);
};
export default CategoryHero;

View File

@@ -0,0 +1,86 @@
"use client";
import React from "react";
import Image from "next/image";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";
const categories = [
{ title: "Spirituality", image: "/one-two.jpg" },
{ title: "Meditation", image: "/gallery1.jpg" },
{ title: "Wellness", image: "/pooja_image.webp" },
];
const BannerSlider = () => {
return (
<section className="relative h-fit bg-gradient-to-br from-yellow-800 to-yellow-700 overflow-hidden">
{/* Background image */}
<Image
src="/herothree.jpg"
alt="Background"
layout="fill"
objectFit="cover"
className="mix-blend-overlay opacity-30"
/>
<div className="container mx-auto px-4 py-16 relative z-10">
<div className="flex flex-col lg:flex-row items-center justify-between gap-12">
{/* Text content */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="lg:w-1/3 text-center lg:text-left"
>
<h2 className="text-2xl font-medium text-primary-foreground mb-4">
Discover Your Path
</h2>
<h1 className="text-4xl lg:text-5xl font-bold text-white mb-6">
Astrology-Guided Personal Growth
</h1>
<p className="text-lg text-primary-foreground/80 mb-8">
Unlock your potential with our expert-led consultations and sacred
Rudraksha beads.
</p>
<a
href="#consultation"
className="inline-flex items-center gap-2 bg-white text-primary px-6 py-3 rounded-full hover:bg-primary-foreground hover:text-primary transition-colors"
>
Book a Consultation
<ArrowRight className="w-4 h-4" />
</a>
</motion.div>
{/* Static Cards */}
<motion.div
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="lg:w-2/3 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
>
{categories.map((category, index) => (
<div
key={index}
className="relative aspect-square rounded-lg overflow-hidden group"
>
<Image
src={category.image || "/placeholder.svg"}
alt={category.title}
layout="fill"
objectFit="cover"
className="transition-transform duration-300 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent flex items-end p-4">
<h3 className="text-white text-lg font-medium">
{category.title}
</h3>
</div>
</div>
))}
</motion.div>
</div>
</div>
</section>
);
};
export default BannerSlider;

View File

@@ -0,0 +1,109 @@
"use client";
import React, { useContext } from "react";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import Link from "next/link";
import ProductContext from "@/app/contexts/productContext";
import { backendUrl } from "@/utils/axios";
import Image from "next/image";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";
const EnhancedSlider = () => {
const { category, products } = useContext(ProductContext);
const selectedCategories = category?.slice(0, 2);
const categorizedProducts = selectedCategories?.map((cat) => ({
category: cat,
products: products
?.filter((product) => product.product_category?.id === cat.id)
.slice(0, 3),
}));
return (
<section className="bg-gradient-to-b from-background to-secondary/10 py-16 md:py-24">
<div className="container mx-auto px-4">
{categorizedProducts?.map((catData, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: index * 0.2 }}
className="mb-20 last:mb-0"
>
<div className="flex flex-col md:flex-row items-center justify-between mb-8">
<div className="text-center md:text-left mb-6 md:mb-0">
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-4">
Best-Selling {catData.category?.category_name}
</h2>
<Link
href={`/category/${catData.category?.id}`}
className="inline-flex items-center text-primary hover:text-primary/80 transition-colors"
>
<span className="text-lg font-medium">
Explore Collection
</span>
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
</div>
</div>
<Carousel
opts={{
align: "start",
}}
className="w-full"
>
<CarouselContent className="-ml-2 md:-ml-4">
{catData.products?.map((product, idx) => (
<CarouselItem
key={idx}
className="pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3"
>
<Link href={`/products/${product.id}`}>
<motion.div
whileHover={{ y: -5 }}
className="group rounded-lg overflow-hidden bg-card shadow-lg transition-shadow hover:shadow-xl"
>
<div className="aspect-square relative overflow-hidden">
<Image
src={`${backendUrl}${
product.images[0]?.image || "/placeholder.jpg"
}`}
alt={product.product_name}
layout="fill"
objectFit="cover"
className="transition-transform duration-300 group-hover:scale-110"
/>
</div>
<div className="p-4">
<h3 className="text-lg font-semibold text-foreground group-hover:text-primary transition-colors">
{product.product_name}
</h3>
<p className="text-sm text-muted-foreground mt-2">
{product.short_description ||
"Discover more about this product"}
</p>
</div>
</motion.div>
</Link>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious className="hidden md:flex -left-4 bg-background/50 hover:bg-background text-foreground" />
<CarouselNext className="hidden md:flex -right-4 bg-background/50 hover:bg-background text-foreground" />
</Carousel>
</motion.div>
))}
</div>
</section>
);
};
export default EnhancedSlider;

View File

@@ -0,0 +1,51 @@
import React, { useContext } from "react";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import Link from "next/link";
import Image from "next/image";
const CategorySlider = ({ categoryData, products }) => {
return (
<div className="w-full sm:w-[70%] p-4">
<h2 className="capitalize font-serif text-2xl sm:text-4xl font-bold mb-4 sm:mb-7">
Top Selling {categoryData?.category_name}
</h2>
<Carousel className="w-full max-w-full sm:max-w-[90%]">
<CarouselContent className="-ml-1">
{products?.slice(0, 3).map((product, index) => (
<CarouselItem
key={index}
className="pl-3 sm:basis-1/2 lg:basis-1/3"
>
<Link href={`/products/${product.product_name}`}>
<div className="p-1">
<div className="bg-white shadow-md hover:shadow-xl">
<div className="flex aspect-square items-center justify-center p-8">
<Image
src={product.images[0]?.image || "/placeholder.jpg"}
alt={product.product_name}
className="hover:scale-105 object-cover object-center transition-all ease-in duration-300" // Tailwind styling
/>
</div>
</div>
<h2 className="mt-3 text-center text-lg sm:text-xl font-medium">
{product.product_name}
</h2>
</div>
</Link>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious className="text-black hidden sm:flex" />
<CarouselNext className="text-black hover:bg-[#C19A5B] hidden sm:flex" />
</Carousel>
</div>
);
};
export default CategorySlider;

View File

@@ -0,0 +1,67 @@
import Link from 'next/link';
import React from 'react';
const TermsOfService = () => {
return (
<div className='bg-white '>
<div className="container mx-auto p-4 max-w-2xl">
<h1 className="text-5xl text-center font-emilys mb-6">Terms of Service</h1>
<section className="mb-6">
<p>Welcome to <strong>Gupta Rudraksha and Beads</strong>. By accessing or using our website, you agree to comply with and be bound by the following terms and conditions. Please review them carefully before engaging with our services.</p>
<hr className="my-4" />
<h2 className="text-lg font-semibold">1. <strong>Acceptance of Terms</strong></h2>
<p>By accessing our website, you acknowledge that you have read, understood, and agree to be bound by these Terms of Service, along with our <Link href='/policies/privacy-policy' className="text-blue-600">Privacy Policy</Link> and <Link href="/policies/refund-policy" className="text-blue-600">Return and Cancellation Policy</Link>.</p>
<h2 className="text-lg font-semibold">2. <strong>Use of Our Website</strong></h2>
<ul className="list-disc ml-6">
<li><strong>Eligibility:</strong> You must be at least 18 years old to use our website. By using our site, you represent that you meet this age requirement.</li>
<li><strong>Account Responsibility:</strong> If you create an account, you are responsible for maintaining the confidentiality of your account information and for all activities that occur under your account.</li>
</ul>
<h2 className="text-lg font-semibold">3. <strong>Product Information</strong></h2>
<p>We strive to provide accurate descriptions of our products, including Rudraksha beads, Shaligrams, and Japa Malas. However, we do not warrant that product descriptions or other content are entirely accurate, complete, or error-free. If a product offered by us is not as described, your sole remedy is to return it in unused condition, in accordance with our <Link href="/policies/refund-policy" className="text-blue-600">Return and Cancellation Policy</Link>.</p>
<h2 className="text-lg font-semibold">4. <strong>Pricing and Payment</strong></h2>
<ul className="list-disc ml-6">
<li><strong>Pricing:</strong> All prices are listed in [Currency] and are subject to change without notice. We are not responsible for typographical errors in pricing.</li>
<li><strong>Payment:</strong> We accept [list of payment methods]. Payment must be received before your order is processed and shipped.</li>
</ul>
<h2 className="text-lg font-semibold">5. <strong>Shipping and Delivery</strong></h2>
<ul className="list-disc ml-6">
<li><strong>Shipping:</strong> We offer shipping to various locations. Shipping costs and delivery times are specified during the checkout process.</li>
<li><strong>Delivery:</strong> Delivery times are estimates and not guaranteed. We are not liable for delays caused by carriers or unforeseen circumstances.</li>
</ul>
<h2 className="text-lg font-semibold">6. <strong>Intellectual Property</strong></h2>
<p>All content on our website, including text, graphics, logos, images, and software, is the property of <strong>Gupta Rudraksha and Beads</strong> or its content suppliers and is protected by applicable intellectual property laws. Unauthorized use of any content is prohibited.</p>
<h2 className="text-lg font-semibold">7. <strong>Limitation of Liability</strong></h2>
<p>To the fullest extent permitted by law, <strong>Gupta Rudraksha and Beads</strong> shall not be liable for any indirect, incidental, special, or consequential damages arising from the use of our website or products.</p>
<h2 className="text-lg font-semibold">8. <strong>Governing Law</strong></h2>
<p>These terms are governed by and construed in accordance with the laws of [Your Jurisdiction], without regard to its conflict of law principles.</p>
<h2 className="text-lg font-semibold">9. <strong>Changes to Terms</strong></h2>
<p>We reserve the right to modify these Terms of Service at any time. Changes will be effective immediately upon posting on our website. Your continued use of the site constitutes your acceptance of any revised terms.</p>
<h2 className="text-lg font-semibold">10. <strong>Contact Information</strong></h2>
<p>For any questions or concerns regarding these Terms of Service, please contact us at:</p>
<address>
<strong>Gupta Rudraksha and Beads</strong><br />
Email: <a href="mailto:nepali.rudrakshabeads@gmail.com" className="text-blue-600">nepali.rudrakshabeads@gmail.com</a>
</address>
<hr className="my-4" />
<p className="text-sm">*Note: This document is subject to change without prior notice. Please review it periodically for any updates.*</p>
</section>
</div>
</div>
);
};
export default TermsOfService;

View File

@@ -0,0 +1,27 @@
"use client";
import React from "react";
import { useState, useEffect } from "react";
import "./termsService.css";
const TermsPage = () => {
const [termsdata, setTermsdata] = useState(null);
const fetchdata = async () => {
const dataObj = await fetch("/api/terms-of-service");
const response = await dataObj.json();
setTermsdata(response.data);
};
useEffect(() => {
fetchdata();
}, []);
return (
<div className="sm:max-w-6xl sm:p-0 p-3 mx-auto">
<div
className="termspage"
dangerouslySetInnerHTML={{ __html: termsdata }}
/>
</div>
);
};
export default TermsPage;

View File

@@ -0,0 +1,63 @@
.termspage {
max-width: 900px;
margin: 30px auto;
padding: 20px;
background-color: #fff;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
.termspage .heading {
font-size: 2rem;
font-weight: 700;
}
.termspage h1,
h2 {
color: #333;
font-weight: bold;
}
.termspage h1 {
font-size: 28px;
margin-bottom: 10px;
text-align: center;
padding-bottom: 20px;
border-bottom: 1px solid #e0e0e0;
}
.termspage h2 {
font-size: 22px;
margin-top: 20px;
margin-bottom: 15px;
}
.termspage p {
color: #555;
font-size: 16px;
margin-bottom: 15px;
text-align: justify;
}
.termspage a {
color: #007bff;
text-decoration: none;
}
.termspage a:hover {
text-decoration: underline;
}
.termspage ul {
padding-left: 20px;
}
.termspage li {
margin-bottom: 10px;
line-height: 1.5;
}
.termspage hr {
border: 0;
border-top: 1px solid #e0e0e0;
margin: 30px 0;
}

View File

@@ -0,0 +1,119 @@
'use client'
import React from "react";
import { Star } from "lucide-react";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
import { testimonials } from "@/utils";
import Image from "next/image";
import { motion } from "framer-motion";
const TestimonialCard = ({ testimonial }) => (
<motion.div
whileHover={{ y: -5 }}
transition={{ type: "spring", stiffness: 300 }}
>
<Card className="h-full bg-card shadow-lg hover:shadow-xl transition-shadow duration-300 rounded-lg overflow-hidden border-none">
<CardContent className="p-6 flex flex-col justify-between h-full">
<div>
<div className="flex justify-between items-center mb-4">
<div className="flex">
{[...Array(5)].map((_, i) => (
<Star
key={i}
size={18}
className={
i < testimonial.rating ? "text-yellow-400" : "text-gray-300"
}
fill={i < testimonial.rating ? "currentColor" : "none"}
/>
))}
</div>
<span className="text-sm text-muted-foreground">
{testimonial.daysAgo} days ago
</span>
</div>
<p className="text-foreground text-lg leading-relaxed mb-6">
&quot;{testimonial.review}&quot;
</p>
</div>
<div className="flex items-center">
<div className="relative w-12 h-12 mr-4">
<Image
src={testimonial.profileImg || "/placeholder.svg"}
alt={testimonial.name}
layout="fill"
objectFit="cover"
className="rounded-full"
/>
</div>
<div>
<p className="font-semibold text-foreground">{testimonial.name}</p>
<p className="text-sm text-muted-foreground">
{testimonial.location || "Verified Customer"}
</p>
</div>
</div>
</CardContent>
</Card>
</motion.div>
);
const TestimonialCarousel = () => {
return (
<section className="bg-gradient-to-b from-background to-secondary/10 py-20 md:py-32">
<div className="container mx-auto px-4">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="text-center mb-12"
>
<h2 className="text-3xl md:text-5xl font-bold text-foreground mb-4">
Transformative Experiences with Gupta Rudraksha
</h2>
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
Discover how our sacred beads have touched lives -
<a
href="#all-testimonials"
className="text-primary hover:underline"
>
See All Testimonials
</a>
</p>
</motion.div>
<Carousel
opts={{
align: "start",
}}
className="w-full"
>
<CarouselContent className="-ml-2 md:-ml-4">
{testimonials.map((testimonial, index) => (
<CarouselItem
key={testimonial.id}
className="pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3"
>
<div className="p-1">
<TestimonialCard testimonial={testimonial} />
</div>
</CarouselItem>
))}
</CarouselContent>
<div className="flex justify-center mt-8">
<CarouselPrevious className="mr-2 bg-primary text-primary-foreground hover:bg-primary/90" />
<CarouselNext className="ml-2 bg-primary text-primary-foreground hover:bg-primary/90" />
</div>
</Carousel>
</div>
</section>
);
};
export default TestimonialCarousel;

View File

@@ -0,0 +1,85 @@
"use client";
import React, { useState } from "react";
const TrackOrder = () => {
const [orderNumber, setOrderNumber] = useState("");
const [countryCode, setCountryCode] = useState("");
const [phoneNumber, setPhoneNumber] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
setCountryCode("");
setOrderNumber("");
setPhoneNumber("");
// Handle form submission here
console.log("Form submitted:", { orderNumber, countryCode, phoneNumber });
};
return (
<div className="max-w-2xl min-h-[60vh] mx-auto p-6">
<h2 className="text-3xl font-bold mb-4">Order Lookup</h2>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label
htmlFor="order-number"
className="block text-lg my-5 font-medium text-gray-700"
>
Order Number *
</label>
<input
type="text"
id="order-number"
name="order-number"
required
className="mt-1 block w-full p-3 border rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
value={orderNumber}
onChange={(e) => setOrderNumber(e.target.value)}
/>
</div>
<div>
<label
htmlFor="contact"
className="block text-lg font-medium my-5 text-gray-700"
>
Email ID or Phone Number *
</label>
<div className="mt-1 flex rounded-md shadow-sm">
<input
type="text"
id="country-code"
name="country-code"
placeholder="+1"
required
className="flex-shrink-0 p-3 border w-16 rounded-l-md border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 "
value={countryCode}
onChange={(e) => setCountryCode(e.target.value)}
/>
<input
type="tel"
id="phone-number"
name="phone-number"
placeholder="Phone number"
required
className="flex-1 rounded-r-md p-3 border border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value)}
/>
</div>
</div>
<div>
<button
type="submit"
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-[#AC8C6B] hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Track
</button>
</div>
</form>
</div>
);
};
export default TrackOrder;

View File

@@ -0,0 +1,43 @@
"use client"
import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDownIcon } from "@radix-ui/react-icons"
import { cn } from "@/lib/utils"
const Accordion = AccordionPrimitive.Root
const AccordionItem = React.forwardRef(({ className, ...props }, ref) => (
<AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
))
AccordionItem.displayName = "AccordionItem"
const AccordionTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}>
{children}
<ChevronDownIcon
className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
))
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
const AccordionContent = React.forwardRef(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
))
AccordionContent.displayName = AccordionPrimitive.Content.displayName
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }

48
components/ui/button.jsx Normal file
View File

@@ -0,0 +1,48 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
(<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props} />)
);
})
Button.displayName = "Button"
export { Button, buttonVariants }

50
components/ui/card.jsx Normal file
View File

@@ -0,0 +1,50 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("rounded-xl border bg-card text-card-foreground shadow", className)}
{...props} />
))
Card.displayName = "Card"
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props} />
))
CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
{...props} />
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props} />
))
CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props} />
))
CardFooter.displayName = "CardFooter"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

194
components/ui/carousel.jsx Normal file
View File

@@ -0,0 +1,194 @@
"use client";
import * as React from "react"
import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons"
import useEmblaCarousel from "embla-carousel-react";
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
const CarouselContext = React.createContext(null)
function useCarousel() {
const context = React.useContext(CarouselContext)
if (!context) {
throw new Error("useCarousel must be used within a <Carousel />")
}
return context
}
const Carousel = React.forwardRef((
{
orientation = "horizontal",
opts,
setApi,
plugins,
className,
children,
...props
},
ref
) => {
const [carouselRef, api] = useEmblaCarousel({
...opts,
axis: orientation === "horizontal" ? "x" : "y",
}, plugins)
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
const [canScrollNext, setCanScrollNext] = React.useState(false)
const onSelect = React.useCallback((api) => {
if (!api) {
return
}
setCanScrollPrev(api.canScrollPrev())
setCanScrollNext(api.canScrollNext())
}, [])
const scrollPrev = React.useCallback(() => {
api?.scrollPrev()
}, [api])
const scrollNext = React.useCallback(() => {
api?.scrollNext()
}, [api])
const handleKeyDown = React.useCallback((event) => {
if (event.key === "ArrowLeft") {
event.preventDefault()
scrollPrev()
} else if (event.key === "ArrowRight") {
event.preventDefault()
scrollNext()
}
}, [scrollPrev, scrollNext])
React.useEffect(() => {
if (!api || !setApi) {
return
}
setApi(api)
}, [api, setApi])
React.useEffect(() => {
if (!api) {
return
}
onSelect(api)
api.on("reInit", onSelect)
api.on("select", onSelect)
return () => {
api?.off("select", onSelect)
};
}, [api, onSelect])
return (
(<CarouselContext.Provider
value={{
carouselRef,
api: api,
opts,
orientation:
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
scrollPrev,
scrollNext,
canScrollPrev,
canScrollNext,
}}>
<div
ref={ref}
onKeyDownCapture={handleKeyDown}
className={cn("relative", className)}
role="region"
aria-roledescription="carousel"
{...props}>
{children}
</div>
</CarouselContext.Provider>)
);
})
Carousel.displayName = "Carousel"
const CarouselContent = React.forwardRef(({ className, ...props }, ref) => {
const { carouselRef, orientation } = useCarousel()
return (
(<div ref={carouselRef} className="overflow-hidden">
<div
ref={ref}
className={cn(
"flex",
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
className
)}
{...props} />
</div>)
);
})
CarouselContent.displayName = "CarouselContent"
const CarouselItem = React.forwardRef(({ className, ...props }, ref) => {
const { orientation } = useCarousel()
return (
(<div
ref={ref}
role="group"
aria-roledescription="slide"
className={cn(
"min-w-0 shrink-0 grow-0 basis-full",
orientation === "horizontal" ? "pl-4" : "pt-4",
className
)}
{...props} />)
);
})
CarouselItem.displayName = "CarouselItem"
const CarouselPrevious = React.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
return (
(<Button
ref={ref}
variant={variant}
size={size}
className={cn("absolute h-8 w-8 rounded-full", orientation === "horizontal"
? "-left-12 top-1/2 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90", className)}
disabled={!canScrollPrev}
onClick={scrollPrev}
{...props}>
<ArrowLeftIcon className="h-4 w-4" />
<span className="sr-only">Previous slide</span>
</Button>)
);
})
CarouselPrevious.displayName = "CarouselPrevious"
const CarouselNext = React.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollNext, canScrollNext } = useCarousel()
return (
(<Button
ref={ref}
variant={variant}
size={size}
className={cn("absolute h-8 w-8 rounded-full", orientation === "horizontal"
? "-right-12 top-1/2 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90", className)}
disabled={!canScrollNext}
onClick={scrollNext}
{...props}>
<ArrowRightIcon className="h-4 w-4" />
<span className="sr-only">Next slide</span>
</Button>)
);
})
CarouselNext.displayName = "CarouselNext"
export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext };

View File

@@ -0,0 +1,157 @@
"use client"
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { cn } from "@/lib/utils"
import { CheckIcon, ChevronRightIcon, DotFilledIcon } from "@radix-ui/react-icons"
const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
const DropdownMenuGroup = DropdownMenuPrimitive.Group
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
const DropdownMenuSub = DropdownMenuPrimitive.Sub
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
inset && "pl-8",
className
)}
{...props}>
{children}
<ChevronRightIcon className="ml-auto" />
</DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props} />
))
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName
const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props} />
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
inset && "pl-8",
className
)}
{...props} />
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => (
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
checked={checked}
{...props}>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName
const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => (
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<DotFilledIcon className="h-2 w-2 fill-current" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
{...props} />
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props} />
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
const DropdownMenuShortcut = ({
className,
...props
}) => {
return (
(<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props} />)
);
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
export {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuGroup,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}

19
components/ui/input.jsx Normal file
View File

@@ -0,0 +1,19 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Input = React.forwardRef(({ className, type, ...props }, ref) => {
return (
(<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
{...props} />)
);
})
Input.displayName = "Input"
export { Input }

View File

@@ -0,0 +1,104 @@
import * as React from "react"
import { ChevronDownIcon } from "@radix-ui/react-icons"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import { cn } from "@/lib/utils"
const NavigationMenu = React.forwardRef(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn(
"relative z-10 flex max-w-max flex-1 items-center justify-center",
className
)}
{...props}>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
))
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
const NavigationMenuList = React.forwardRef(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.List
ref={ref}
className={cn(
"group flex flex-1 list-none items-center justify-center space-x-1",
className
)}
{...props} />
))
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
const NavigationMenuItem = NavigationMenuPrimitive.Item
const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
)
const NavigationMenuTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}>
{children}{" "}
<ChevronDownIcon
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
aria-hidden="true" />
</NavigationMenuPrimitive.Trigger>
))
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
const NavigationMenuContent = React.forwardRef(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
className
)}
{...props} />
))
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
const NavigationMenuLink = NavigationMenuPrimitive.Link
const NavigationMenuViewport = React.forwardRef(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className
)}
ref={ref}
{...props} />
</div>
))
NavigationMenuViewport.displayName =
NavigationMenuPrimitive.Viewport.displayName
const NavigationMenuIndicator = React.forwardRef(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Indicator
ref={ref}
className={cn(
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
className
)}
{...props}>
<div
className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
))
NavigationMenuIndicator.displayName =
NavigationMenuPrimitive.Indicator.displayName
export {
navigationMenuTriggerStyle,
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
}

View File

@@ -0,0 +1,14 @@
import { cn } from "@/lib/utils"
function Skeleton({
className,
...props
}) {
return (
(<div
className={cn("animate-pulse rounded-md bg-primary/10", className)}
{...props} />)
);
}
export { Skeleton }