commit 12caeee710a3d0e4041c3672b1a9e895320f822c Author: afnaann Date: Wed Feb 19 17:00:55 2025 +0530 chore: setup project for production diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..339030e --- /dev/null +++ b/.gitignore @@ -0,0 +1,57 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ +.env.local +# production +/build + +# misc +.DS_Store +Thumbs.db +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env* +!.env.example # Include example env file + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Tailwind CSS +*.css.map + +# Editor settings and IDE files +.vscode/ +.idea/ + +# Linting and formatting +.eslintcache +.prettier.cache +*.stylelintcache + +# Logs +logs/ +*.log + +# Generated files +*.cache diff --git a/README.md b/README.md new file mode 100644 index 0000000..0dc9ea2 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/app/NavigationWrapper.jsx b/app/NavigationWrapper.jsx new file mode 100644 index 0000000..ce67531 --- /dev/null +++ b/app/NavigationWrapper.jsx @@ -0,0 +1,21 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import TopBanner from "@/components/header/TopBanner"; +import Navbar from "@/components/header/Navbar"; + +export default function NavigationWrapper() { + const pathname = usePathname(); + + const isAuthPage = + pathname === "/accounts/login" || pathname === "/accounts/register"; + + if (isAuthPage) return null; + + return ( + <> + {/* */} + + + ); +} diff --git a/app/WrapperFooter.jsx b/app/WrapperFooter.jsx new file mode 100644 index 0000000..a61cc95 --- /dev/null +++ b/app/WrapperFooter.jsx @@ -0,0 +1,20 @@ +'use client' +import Footer from '@/components/footer/Footer' +import { usePathname } from 'next/navigation' +import React from 'react' + + +const WrapperFooter = () => { + + const pathname = usePathname() + const isLogin = pathname === '/accounts/login' + if(isLogin) return null; + + return ( +
+
+
+ ) +} + +export default WrapperFooter diff --git a/app/accounts/login/page.jsx b/app/accounts/login/page.jsx new file mode 100644 index 0000000..68a1695 --- /dev/null +++ b/app/accounts/login/page.jsx @@ -0,0 +1,155 @@ +"use client"; + +import MainContext from "@/app/contexts/mainContext"; +import Image from "next/image"; +import React, { useContext, useState } from "react"; + +const LoginSignup = () => { + const [isLogin, setIsLogin] = useState(true); + const { loginUser, registerUser } = useContext(MainContext); + const [formData, setFormData] = useState({ + email: "", + password: "", + confirmPassword: "", + }); + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData((prevData) => ({ + ...prevData, + [name]: value, + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + if (isLogin) { + loginUser(formData); + } else { + registerUser(formData); + } + }; + + const toggleMode = () => { + setIsLogin(!isLogin); + setFormData({ email: "", password: "", confirmPassword: "" }); + }; + + return ( +
+ {/* Left section with video */} +
+ +
+ + {/* Right section with login/signup form */} +
+
+
+ logo +

{`${ + isLogin ? "Login" : "Sign up" + }`}

+
+
+
+
+ + +
+
+ + +
+ {!isLogin && ( +
+ + +
+ )} +
+ +
+ +
+
+
+

+ Manage subscriptions +

+

or

+

+ Continue with google +

+ +
+
+
+
+ ); +}; + +export default LoginSignup; diff --git a/app/accounts/profile/addresses/[id]/page.jsx b/app/accounts/profile/addresses/[id]/page.jsx new file mode 100644 index 0000000..08ba5be --- /dev/null +++ b/app/accounts/profile/addresses/[id]/page.jsx @@ -0,0 +1,204 @@ +'use client' +import { useState, useEffect } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import authAxios from '@/utils/axios'; + +const EditAddress = () => { + const { id } = useParams(); + const router = useRouter(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const [formData, setFormData] = useState({ + first_name: '', + last_name: '', + company: '', + address: '', + apartment: '', + city: '', + country: '', + zipcode: '', + phone: '' + }); + + useEffect(() => { + const fetchAddress = async () => { + try { + const response = await authAxios.get(`/account/addresses/${id}/`); + setFormData(response.data); + } catch (err) { + setError('Failed to fetch address details'); + console.error(err); + } + }; + + if (id) { + fetchAddress(); + } + }, [id]); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + setError(''); + + try { + await authAxios.put(`/account/addresses/${id}/`, formData); + router.push('/accounts/profile/addresses'); + } catch (err) { + setError(err.response?.data?.message || 'Failed to update address'); + } finally { + setLoading(false); + } + }; + + return ( +
+

Edit Address

+ {error &&
{error}
} +
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+
+ +
+ + +
+
+
+ ); +}; + +export default EditAddress; \ No newline at end of file diff --git a/app/accounts/profile/addresses/page.jsx b/app/accounts/profile/addresses/page.jsx new file mode 100644 index 0000000..836b511 --- /dev/null +++ b/app/accounts/profile/addresses/page.jsx @@ -0,0 +1,16 @@ +'use client' +import Addresses from '@/components/accounts/addresses'; + +import React from 'react'; + +const Page = () => { + + return ( +
+ + {/* */} +
+ ); +}; + +export default Page; diff --git a/app/accounts/profile/change-password/page.jsx b/app/accounts/profile/change-password/page.jsx new file mode 100644 index 0000000..f1b5007 --- /dev/null +++ b/app/accounts/profile/change-password/page.jsx @@ -0,0 +1,113 @@ +'use client' +import React, { useState } from "react"; +import axios from "axios"; +import authAxios from "@/utils/axios"; + +const ChangePassword = () => { + const [oldPassword, setOldPassword] = useState(""); + const [newPassword, setNewPassword] = useState(""); + const [confirmNewPassword, setConfirmNewPassword] = useState(""); + const [error, setError] = useState(""); + const [success, setSuccess] = useState(""); + + const handleSubmit = async (e) => { + e.preventDefault(); + + + if (!oldPassword || !newPassword || !confirmNewPassword) { + setError("All fields are required."); + return; + } + + + if (newPassword !== confirmNewPassword) { + setError("New passwords do not match."); + return; + } + + + setError(""); + + try { + + const response = await authAxios.post( + "/account/change-password/", + { + old_password: oldPassword, + new_password: newPassword, + confirm_new_password: confirmNewPassword, + } + ); + + if (response.data.status) { + setSuccess("Password updated successfully."); + } else { + setError(response.data.message || "Something went wrong."); + } + } catch (err) { + setError("Failed to change password. Please try again."); + } + }; + + return ( +
+

+ Change Password +

+
+
+ + setOldPassword(e.target.value)} + /> + + + setNewPassword(e.target.value)} + /> + + + setConfirmNewPassword(e.target.value)} + /> + + {error && ( +
+

{error}

+
+ )} + + {success && ( +
+

{success}

+
+ )} + + +
+
+
+ ); +}; + +export default ChangePassword; diff --git a/app/accounts/profile/edit-profile/page.jsx b/app/accounts/profile/edit-profile/page.jsx new file mode 100644 index 0000000..3d0022d --- /dev/null +++ b/app/accounts/profile/edit-profile/page.jsx @@ -0,0 +1,12 @@ +import EditProfile from '@/components/accounts/editProfile' +import React from 'react' + +const page = () => { + return ( +
+ +
+ ) +} + +export default page diff --git a/app/accounts/profile/layout.jsx b/app/accounts/profile/layout.jsx new file mode 100644 index 0000000..f438131 --- /dev/null +++ b/app/accounts/profile/layout.jsx @@ -0,0 +1,20 @@ +import AccountSidebar from "@/components/accounts/AccountSidebar"; +import Link from "next/link"; + +export const metadata = { + title: "Accounts", +}; + +export default function layout({ children }) { + return ( +
+
+ {/* Sidebar - flex row on mobile, column on desktop */} + + + {/* Main content */} +
{children}
+
+
+ ); +} diff --git a/app/accounts/profile/new-address/page.jsx b/app/accounts/profile/new-address/page.jsx new file mode 100644 index 0000000..d1d6f3b --- /dev/null +++ b/app/accounts/profile/new-address/page.jsx @@ -0,0 +1,12 @@ +import AddNewAddress from '@/components/accounts/AddNewAddress' +import React from 'react' + +const page = () => { + return ( +
+ {/* */} +
+ ) +} + +export default page diff --git a/app/accounts/profile/orders/page.jsx b/app/accounts/profile/orders/page.jsx new file mode 100644 index 0000000..31b0c54 --- /dev/null +++ b/app/accounts/profile/orders/page.jsx @@ -0,0 +1,120 @@ +"use client"; +import { useCurrency } from "@/app/contexts/currencyContext"; +import authAxios, { backendUrl } from "@/utils/axios"; +import { ShoppingBag } from "lucide-react"; +import Image from "next/image"; +import { useState, useEffect } from "react"; + +const OrdersPage = () => { + const [orders, setOrders] = useState([]); + const [loading, setLoading] = useState(true); + const { isLoading, formatPrice } = useCurrency(); + + useEffect(() => { + const fetchOrders = async () => { + try { + const response = await authAxios.get("/orders/my-orders"); + setOrders(response.data); + } catch (error) { + console.error("Error fetching orders:", error); + } finally { + setLoading(false); + } + }; + fetchOrders(); + }, []); + + if (loading) { + return ( +
+ Loading... +
+ ); + } + + if (!orders.length) { + return ( +
+

+ Orders +

+
+

+ + You don't have any orders yet +

+
+
+ ); + } + + return ( +
+

+ Orders +

+
+ {orders.map((order) => ( +
+
+ Order #{order.order_number} + + {order.status} + +
+ +
+ {order.items.map((item) => ( +
+ {item.variant.product.product_name} +
+

+ {item.variant.product.product_name} +

+

+ Size: {item.variant.size.size_name} + {item.design && ` • Design: ${item.design.design_name}`} +

+

+ Quantity: {item.quantity} +

+
+
+ ))} +
+ +
+
+ {new Date(order.created_at).toLocaleDateString()} +
+
+ Total:{" "} + {isLoading ? ( + Loading... + ) : ( + {formatPrice(order.total_amount)} + )} +
+
+
+ ))} +
+
+ ); +}; + +export default OrdersPage; diff --git a/app/accounts/profile/page.jsx b/app/accounts/profile/page.jsx new file mode 100644 index 0000000..5571834 --- /dev/null +++ b/app/accounts/profile/page.jsx @@ -0,0 +1,151 @@ +"use client"; +import React, { useState, useEffect } from "react"; +import axios from "axios"; +import authAxios from "@/utils/axios"; +import { useRouter } from "next/navigation"; +import Image from "next/image"; + +export default function ProfilePage() { + const [profileData, setProfileData] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); + const router = useRouter(); + useEffect(() => { + const fetchProfileData = async () => { + try { + const response = await authAxios.get("/account/profile/"); + setProfileData(response.data); + setIsLoading(false); + } catch (error) { + console.error("Error fetching profile data", error); + setIsError(true); + setIsLoading(false); + } + }; + + fetchProfileData(); + }, []); + + const getDisplayValue = (value) => { + return value ? value : "Not set up"; + }; + + if (isLoading) { + return
Loading...
; + } + + if (isError) { + return
Error loading profile data. Please try again later.
; + } + + return ( +
+
+
+ All Orders{" "} +

+ {profileData.orders || 0} +

+
+
+ Addresses{" "} +

+ {profileData.addresses || 0} +

+
+
+

Profile information

+
+
+
+ +

+ {getDisplayValue(profileData.first_name)} +

+
+
+ +

+ {getDisplayValue(profileData.last_name)} +

+
+
+ +

+ {getDisplayValue(profileData.birth_day)} +

+
+
+ +

+ {getDisplayValue(profileData.gender)} +

+
+
+ +

Contact methods

+
+
+ +

+ {getDisplayValue(profileData.email)} +

+
+
+ +

+ {getDisplayValue(profileData.phone)} +

+
+
+ +

Other Info

+
+ + {profileData.profile_pic ? ( + Profile Picture + ) : ( +

Not set up

+ )} +
+ +

Other Info

+
+ +

+ {getDisplayValue(profileData.accepts_marketing)} +

+
+ + +
+
+ ); +} diff --git a/app/api/blog/route.js b/app/api/blog/route.js new file mode 100644 index 0000000..9d06926 --- /dev/null +++ b/app/api/blog/route.js @@ -0,0 +1,109 @@ +import { NextResponse } from "next/server"; + +export async function GET() { + return NextResponse.json({ + blogdata: ` +
+

Dhanteras and Rudraksha: Bridging Prosperity and Spirituality

+ +
+

+ Dhanteras, the first day of Diwali festival, marks a unique + celebration of wealth and prosperity in Hindu tradition. As the name + suggests - 'Dhan' meaning wealth and 'Teras' referring to the 13th + day of the lunar fortnight - this auspicious occasion holds deep + significance for those seeking financial blessings. +

+
+ +
+

The Significance of Dhanteras in Hindu Tradition

+

+ Dhanteras is the worship of Dhanvantari. Dhanvantari, according to + Hindu traditions, emerged during Samudra Manthana, holding a pot + full of amrita (a nectar bestowing immortality) in one hand and the + sacred text about Ayurveda in the other hand. He is considered to be + the physician of the devas and also an avatar of Vishnu. +

+

+ Another popular tale involves a young prince whose death by snake + bite was predicted on his wedding night. His clever wife placed a + heap of gold and silver coins at the entrance of their chamber, + lighting lamps all around, and Yama, the God of Death, was + distracted and left without taking the prince's life. +

+
+ +
+

Introduction to Rudraksha and Its Power

+

+ The word 'Rudraksha' is a combination of two Sanskrit terms - + 'Rudra', another name for Lord Shiva, and 'Aksha', meaning teardrop. + Legend has it that Lord Shiva's tears of compassion sprouted into + Rudraksha trees, symbolizing spiritual protection. +

+
+ +
+

Recommended Rudraksha Beads for Dhanteras

+
    +
  • + 2 Mukhi Rudraksha: Enhances harmony in + relationships and emotional balance. +
  • +
  • + 7 Mukhi Rudraksha: Attracts financial prosperity + and good fortune. +
  • +
  • + 8 Mukhi Rudraksha: Removes obstacles and ensures + success in career and business. +
  • +
  • + 9 Mukhi Rudraksha: Provides protection from + negativity and boosts courage. +
  • +
+
+ +
+

How to Use Rudraksha on Dhanteras for Maximum Benefits

+

+ Incorporating Rudraksha into your Dhanteras celebrations can amplify + the festival’s auspicious energies. +

+
    +
  • + Cleansing Ceremony: Purify the beads by dipping + them in milk and Gangajal. +
  • +
  • + Energizing: Chant "Om Namah Shivaya" 108 times + while holding your Rudraksha mala. +
  • +
  • + Offering to Deities: Offer your Rudraksha to the + family deity during the Dhanteras puja. +
  • +
+
+ +
+

Conclusion

+

+ Dhanteras, with its focus on prosperity and new beginnings, provides + the perfect backdrop for harnessing the energy of Rudraksha. By + combining the auspicious timing of Dhanteras with the spiritual + potency of Rudraksha, we create a synergy that amplifies our + intentions for growth and protection. +

+

+ May this Dhanteras bring you abundance in all its forms, and may the + power of Rudraksha guide you towards a path of holistic prosperity + and divine protection. +

+
+
+ `, + }); +} diff --git a/app/api/privacy-policy/route.js b/app/api/privacy-policy/route.js new file mode 100644 index 0000000..cacc09d --- /dev/null +++ b/app/api/privacy-policy/route.js @@ -0,0 +1,52 @@ +import { NextResponse } from "next/server"; + +export function GET() { + return NextResponse.json({ + data: ` +

Last Updated: July 10, 2023

+ +

Introduction

+

Gupta Rudraksha ("we," "us," "our") values the trust you place in us when you use our app, and this Privacy Policy outlines our commitment to protecting your privacy. This Privacy Policy describes the types of personal information we collect, how we use the information, the circumstances under which we share the information, and the steps we take to protect the information.

+ +

Information We Collect

+

Personal Information:

+

We may collect personal information about you through various methods, such as when you use our app, interact with our social media channels, participate in our promotions or events, or engage with us for inquiries. The personal information we collect may include contact details (name, postal address, email address, and mobile or other phone number), date of birth, gender, and any other information you willingly provide.

+ +

Usage Information:

+

When you interact with our app, we may collect certain information about your usage, including details about how our app is accessed and used, information about your device, IP address, location information (if you have enabled location-based services), and information collected through cookies and other tracking technologies.

+ +

How We Use The Information

+

We use the information we collect for various purposes, including to:

+
    +
  • Respond to your inquiries and fulfill your requests for our products and services.
  • +
  • Send you crucial information about our app, changes to our terms, conditions, and policies, and/or other administrative information.
  • +
  • Send you marketing communications that we believe might be of interest to you, including information about our products, services, and promotions.
  • +
  • Permit you to participate in events, contests, and similar promotions.
  • +
  • Analyze and enhance our business operations, such as improving our app, identifying usage trends, conducting data analysis, audits, fraud monitoring, and prevention.
  • +
+ +

Information We Share

+

We do not sell or otherwise disclose personal information about you, except as described in this Privacy Policy. We may share your personal information with:

+
    +
  • Service providers who perform services on our behalf based on our instructions. We do not authorize these service providers to use or disclose the information except as necessary to perform services on our behalf or comply with legal requirements.
  • +
  • Other third parties, such as law enforcement or other government entities, if required by law or if we believe disclosure is necessary or appropriate to protect the rights, property, or safety of us, our customers, or others.
  • +
  • Other third parties with your express consent.
  • +
+ +

Protection Of Your Information

+

We use a variety of administrative, physical, and technical security measures designed to protect your personal information. Despite our efforts, no security measures are perfect or impenetrable, and no method of data transmission can be guaranteed against any interception or other type of misuse. We will continue to enhance security procedures as new technologies and procedures become available.

+ +

Your Rights and Choices

+

We strive to provide you with choices regarding the personal information you provide to us. You may opt out of receiving our marketing emails by following the opt-out instructions provided in those emails. You can also review, update, and correct your personal information held by us by contacting us directly.

+ +

Updates To Our Privacy Policy

+

We may occasionally update this Privacy Policy, and we encourage you to periodically review it to stay informed about how we are protecting your information. We will post any changes on this page, and if the changes are significant, we will provide a more prominent notice.

+ +

How To Contact Us

+

If you have any questions or comments about this Privacy Policy, or if you would like us to update information we have about you or your preferences, please contact us by email at contact@nepalirudraksha.com.

+ +

Your privacy is of utmost importance to us. We commit to safeguarding your personal information in accordance with legal obligations. By using our app, you are accepting the practices outlined in this Privacy Policy. If you do not agree to the terms of this Privacy Policy, please refrain from using our app.

+ + `, + }); +} diff --git a/app/api/refund-policy/route.js b/app/api/refund-policy/route.js new file mode 100644 index 0000000..25ce2ba --- /dev/null +++ b/app/api/refund-policy/route.js @@ -0,0 +1,73 @@ +import { NextResponse } from "next/server"; + +export function GET(params) { + return NextResponse.json({ + data: ` +

Refund policy

+

At Gupta Rudraksha, we recognize the profound spiritual significance of Rudraksha. We are committed to providing our customers with authentic Gupta Rudraksha of the highest quality. With a heritage that spans three generations, we uphold stringent standards of authenticity and excellence.

+ + + +

General Refund and Return Conditions:

+
  • Refunds: Gupta Rudraksha offers refunds for items returned within 7 days of purchase, provided they remain in their original condition and are not energized, damaged, manipulated, or altered in any visible manner.
  • + +
  • Non-Returnable Items: Premium Energization (Prana Pratistha) orders are non-returnable due to the specific energization for individual or family use. + +
  • Inspection and Processing: Refunds undergo a thorough examination and may take up to 3 months to process.
  • + +
  • Lifetime Buyback Guarantee: Applicable if the Rudraksha is proven unauthentic by a verified lab, reinforcing your trust in our products. Customers bear the cost of verification.
  • + +
  • Custom Products: Customized products cannot be returned or refunded.
  • + + + +

    Specific Return Policy:

    +
  • Final Sales: All sales through our website, in-store, or via sales representatives are considered final.
  • + +
  • Damaged Goods: Returns for goods damaged during shipping or due to shipment errors are accepted if reported within 12 hours of delivery. These are subject to a 20% service fee. Customers are responsible for payment processing fees charged by third-party providers.
  • + +
  • Return Review Period: Return requests are reviewed within 30 days of sale. Exceptions may be made based on mutual agreement.
  • + + + +

    Additional Provisions for Accessories:

    +
  • Free Replacement/Repair: For Rudraksha chain, silver chain, silver design, and other accessories, we offer free replacement or repair for 1 month.
  • + +
  • Discounted Servicing: Discounted repair and servicing are available for 12 months.
  • + +
  • Post-Warranty Service Cost: After the 12-month period, customers are liable for repair and servicing costs.
  • + +
  • Flat-Rate Repair Service: Customers can opt to visit our Nepal location for repairs at a flat service fee of $50 (material costs excluded).
  • + + + +Additional Refund Conditions: +
  • Authenticity Refund: 100% refund eligibility if items are proven unauthentic by a verified third-party lab, with lab fees borne by the customer.
  • + +
  • Lost Items: Full refunds for items lost during delivery, except in cases of natural disasters or unforeseeable circumstances.
  • + +
  • Order Delay: Full refunds for delays over 20 days in order processing, unless the delay is communicated or unknown to Gupta Rudraksha.
  • + +
  • Refund Request Window: Refund requests are reviewed and potentially accepted within 7 Days of the order date.
  • + +
  • To process a refund, items must be returned with the Original Product Certificate, Invoice (original or copy), packaging, documentation, lab certificates, discount coupons, etc. We recommend using our managed reverse courier service to ensure the safe delivery of returns. Customers opting to send parcels independently assume responsibility for loss or damage during transit.
  • + + + +

    +

    Return Address:

    +

    Gupta Rudraksha

    +

    Dakshinamurti Marg, Pashupati -08

    +

    Kathmandu, Nepal

    +

    Phone: +9779801059764

    + + + + +

    Note:

    +

    Customers are responsible for shipment fees unless specified otherwise.

    + +

    We are dedicated to upholding the sacredness of Rudraksha beads and encourage their respectful handling. Our Return and Refund Policy ensures transparency, fairness, and customer satisfaction. For any inquiries or concerns, please contact us directly.

    + `, + }); +} diff --git a/app/api/terms-of-service/route.js b/app/api/terms-of-service/route.js new file mode 100644 index 0000000..4c24f78 --- /dev/null +++ b/app/api/terms-of-service/route.js @@ -0,0 +1,55 @@ +import { NextResponse } from "next/server"; + +export async function GET(params) { + return NextResponse.json({ + data: ` +

    Terms of Service

    + +

    OVERVIEW

    +

    This website is operated by Gupta Rudraksha. Throughout the site, the terms “we”, “us” and “our” refer to Gupta Rudraksha. Gupta Rudraksha offers this website, including all information, tools, and services available from this site to you, the user, conditioned upon your acceptance of all terms, conditions, policies, and notices stated here.

    + +

    By visiting our site and/or purchasing something from us, you engage in our “Service” and agree to be bound by the following terms and conditions (“Terms of Service”, “Terms”), including those additional terms and conditions and policies referenced herein and/or available by hyperlink. These Terms of Service apply to all users of the site, including without limitation users who are browsers, vendors, customers, merchants, and/or contributors of content.

    + +

    Please read these Terms of Service carefully before accessing or using our website. By accessing or using any part of the site, you agree to be bound by these Terms of Service. If you do not agree to all the terms and conditions of this agreement, then you may not access the website or use any services. If these Terms of Service are considered an offer, acceptance is expressly limited to these Terms of Service.

    + +

    Any new features or tools which are added to the current store shall also be subject to the Terms of Service. You can review the most current version of the Terms of Service at any time on this page. We reserve the right to update, change or replace any part of these Terms of Service by posting updates and/or changes to our website. It is your responsibility to check this page periodically for changes. Your continued use of or access to the website following the posting of any changes constitutes acceptance of those changes.

    + +

    Our store is hosted on Shopify Inc. They provide us with the online e-commerce platform that allows us to sell our products and services to you.

    + +

    SECTION 1 - ONLINE STORE TERMS

    +

    By agreeing to these Terms of Service, you represent that you are at least the age of majority in your state or province of residence, or that you are the age of majority in your state or province of residence and you have given us your consent to allow any of your minor dependents to use this site. You may not use our products for any illegal or unauthorized purpose nor may you, in the use of the Service, violate any laws in your jurisdiction (including but not limited to copyright laws). You must not transmit any worms or viruses or any code of a destructive nature. A breach or violation of any of the Terms will result in an immediate termination of your Services.

    + +

    SECTION 2 - GENERAL CONDITIONS

    +

    We reserve the right to refuse service to anyone for any reason at any time. You understand that your content (not including credit card information), may be transferred unencrypted and involve (a) transmissions over various networks; and (b) changes to conform and adapt to technical requirements of connecting networks or devices. Credit card information is always encrypted during transfer over networks. You agree not to reproduce, duplicate, copy, sell, resell or exploit any portion of the Service, use of the Service, or access to the Service or any contact on the website through which the service is provided, without express written permission by us. The headings used in this agreement are included for convenience only and will not limit or otherwise affect these Terms.

    + +

    SECTION 3 - ACCURACY, COMPLETENESS AND TIMELINESS OF INFORMATION

    +

    We are not responsible if information made available on this site is not accurate, complete or current. The material on this site is provided for general information only and should not be relied upon or used as the sole basis for making decisions without consulting primary, more accurate, more complete or more timely sources of information. Any reliance on the material on this site is at your own risk. This site may contain certain historical information. Historical information, necessarily, is not current and is provided for your reference only. We reserve the right to modify the contents of this site at any time, but we have no obligation to update any information on our site. You agree that it is your responsibility to monitor changes to our site.

    + +

    SECTION 4 - MODIFICATIONS TO THE SERVICE AND PRICES

    +

    Prices for our products are subject to change without notice. We reserve the right at any time to modify or discontinue the Service (or any part or content thereof) without notice at any time. We shall not be liable to you or to any third-party for any modification, price change, suspension or discontinuance of the Service.

    + +

    SECTION 5 - PRODUCTS OR SERVICES (if applicable)

    +

    Certain products or services may be available exclusively online through the website. These products or services may have limited quantities and are subject to return or exchange only according to our Return Policy. We have made every effort to display as accurately as possible the colors and images of our products that appear at the store. We cannot guarantee that your computer monitor's display of any color will be accurate. We reserve the right, but are not obligated, to limit the sales of our products or Services to any person, geographic region or jurisdiction. We may exercise this right on a case-by-case basis. We reserve the right to limit the quantities of any products or services that we offer. All descriptions of products or product pricing are subject to change at any time without notice, at the sole discretion of us. We reserve the right to discontinue any product at any time. Any offer for any product or service made on this site is void where prohibited. We do not warrant that the quality of any products, services, information, or other material purchased or obtained by you will meet your expectations, or that any errors in the Service will be corrected.

    + +

    SECTION 6 - ACCURACY OF BILLING AND ACCOUNT INFORMATION

    +

    We reserve the right to refuse any order you place with us. We may, in our sole discretion, limit or cancel quantities purchased per person, per household or per order. These restrictions may include orders placed by or under the same customer account, the same credit card, and/or orders that use the same billing and/or shipping address. In the event that we make a change to or cancel an order, we may attempt to notify you by contacting the e‑mail and/or billing address/phone number provided at the time the order was made. We reserve the right to limit or prohibit orders that, in our sole judgment, appear to be placed by dealers, resellers or distributors.

    + +

    You agree to provide current, complete and accurate purchase and account information for all purchases made at our store. You agree to promptly update your account and other information, including your email address and credit card numbers and expiration dates, so that we can complete your transactions and contact you as needed.

    + +

    For more detail, please review our Returns Policy.

    + +

    SECTION 7 - OPTIONAL TOOLS

    +

    We may provide you with access to third-party tools over which we neither monitor nor have any control nor input. You acknowledge and agree that we provide access to such tools ”as is” and “as available” without any warranties, representations or conditions of any kind and without any endorsement. We shall have no liability whatsoever arising from or relating to your use of optional third-party tools. Any use by you of optional tools offered through the site is entirely at your own risk and discretion and you should ensure that you are familiar with and approve of the terms on which tools are provided by the relevant third-party provider(s). We may also, in the future, offer new services and/or features through the website (including the release of new tools and resources). Such new features and/or services shall also be subject to these Terms of Service.

    + +

    SECTION 8 - THIRD-PARTY LINKS

    +

    Certain content, products, and services available via our Service may include materials from third-parties. Third-party links on this site may direct you to third-party websites that are not affiliated with us. We are not responsible for examining or evaluating the content or accuracy and we do not warrant and will not have any liability or responsibility for any third-party materials or websites, or for any other materials, products, or services of third-parties. We are not liable for any harm or damages related to the purchase or use of goods, services, resources, content, or any other transactions made in connection with any third-party websites. Please review carefully the third-party's policies and practices and make sure you understand them before you engage in any transaction. Complaints, claims, concerns, or questions regarding third-party products should be directed to the third-party.

    + +

    SECTION 9 - USER COMMENTS, FEEDBACK AND OTHER SUBMISSIONS

    +

    If, at our request, you send certain specific submissions (for example contest entries) or without a request from us you send creative ideas, suggestions, proposals, plans, or other materials, whether online, by email, by postal mail, or otherwise (collectively, 'comments'), you agree that we may, at any time, without restriction, edit, copy, publish, distribute, translate and otherwise use in any medium any comments that you forward to us. We are and shall be under no obligation (1) to maintain any comments in confidence; (2) to pay compensation for any comments; or (3) to respond to any comments.

    + +

    We may, but have no obligation to, monitor, edit or remove content that we determine in our sole discretion are unlawful, offensive, threatening, lib + + + `, + }); +} diff --git a/app/blogs/blog/[blog-id]/page.jsx b/app/blogs/blog/[blog-id]/page.jsx new file mode 100644 index 0000000..f60351e --- /dev/null +++ b/app/blogs/blog/[blog-id]/page.jsx @@ -0,0 +1,13 @@ +import SingleBlog from '@/components/blog/SingleBlog' +import Image from 'next/image' +import React from 'react' + +const page = () => { + return ( +

    + +
    + ) +} + +export default page diff --git a/app/blogs/blog/page.jsx b/app/blogs/blog/page.jsx new file mode 100644 index 0000000..c55f901 --- /dev/null +++ b/app/blogs/blog/page.jsx @@ -0,0 +1,16 @@ +import BlogHome from '@/components/blog/BlogHome' +import React from 'react' + +export const metadata ={ + title: 'Blogs', +} + +const page = () => { + return ( +
    + +
    + ) +} + +export default page diff --git a/app/collections/[id]/page.jsx b/app/collections/[id]/page.jsx new file mode 100644 index 0000000..0448c15 --- /dev/null +++ b/app/collections/[id]/page.jsx @@ -0,0 +1,23 @@ +import FaqCard from '@/components/common-components/FaqCard' +import ExploreSiddhaMala from '@/components/siddha-mala/ExploreSiddhamala' +import SiddhaThree from '@/components/siddha-mala/SiddhaThree' +import CategoryHero from '@/components/siddha-mala/categoryHero' + + +export const metadata = { + title: 'Buy Gupta Siddha mala(1 to 14 mukhi) 100% X-Ray Certified Authentic', + description: "Generated by create next app", +} + + +const Page = ({params}) => { + return ( +
    + + + +
    + ) +} + +export default Page diff --git a/app/collections/online-pooja/page.jsx b/app/collections/online-pooja/page.jsx new file mode 100644 index 0000000..4fc12af --- /dev/null +++ b/app/collections/online-pooja/page.jsx @@ -0,0 +1,21 @@ +import BuyRudrakshaOne from '@/components/buy-rudraksha/BuyRudrakshaOne' +import ExplorePooja from '@/components/online-pooja/ExplorePooja' +import PoojaSubscription from '@/components/online-pooja/PoojaSubscription' +import React from 'react' + +export const metadata={ + title: 'Online Pooja Services by Certified Hindu Priests | Gupta Rudraksha', +} + + +const page = () => { + return ( +
    + + + +
    + ) +} + +export default page diff --git a/app/collections/shaligram/page.jsx b/app/collections/shaligram/page.jsx new file mode 100644 index 0000000..6982919 --- /dev/null +++ b/app/collections/shaligram/page.jsx @@ -0,0 +1,14 @@ +import BuyRudrakshaOne from '@/components/buy-rudraksha/BuyRudrakshaOne' +import ListOfShaligram from '@/components/shaligram/ListOfShaligram' +import React from 'react' + +const page = () => { + return ( +
    + + +
    + ) +} + +export default page diff --git a/app/contexts/currencyContext.js b/app/contexts/currencyContext.js new file mode 100644 index 0000000..71c03e8 --- /dev/null +++ b/app/contexts/currencyContext.js @@ -0,0 +1,150 @@ +"use client"; +import React, { createContext, useContext, useState, useEffect } from "react"; + +const CurrencyContext = createContext(); + +export const SUPPORTED_CURRENCIES = { + INR: { symbol: "₹", name: "Indian Rupee", country: "India" }, + MYR: { symbol: "RM", name: "Malaysian Ringgit", country: "Malaysia" }, + NPR: { symbol: "रू", name: "Nepalese Rupee", country: "Nepal" }, +}; + +export const CurrencyProvider = ({ children }) => { + const [selectedCurrency, setSelectedCurrency] = useState("INR"); + const [exchangeRates, setExchangeRates] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + const fetchExchangeRates = async () => { + try { + setIsLoading(true); + setError(null); + + const cachedData = localStorage.getItem("exchangeRates"); + const cached = cachedData ? JSON.parse(cachedData) : null; + + if ( + cached && + new Date().getTime() - cached.timestamp < 24 * 60 * 60 * 1000 + ) { + setExchangeRates(cached.rates); + setIsLoading(false); + return; + } + + const currencies = Object.keys(SUPPORTED_CURRENCIES) + .filter((key) => key !== "INR") + .join(","); + + const response = await fetch( + `https://apilayer.net/api/live?access_key=9bcb30907dee1cda9866f7b49f0f8def¤cies=${currencies}&source=INR&format=1` + ); + + if (!response.ok) { + throw new Error("Failed to fetch exchange rates"); + } + + const data = await response.json(); + if (!data.success) { + throw new Error(data.error?.info || "API request failed"); + } + + const rates = Object.keys(SUPPORTED_CURRENCIES).reduce( + (acc, currency) => { + if (currency === "INR") { + acc[currency] = 1; + } else { + const rate = data.quotes?.[`INR${currency}`]; + acc[currency] = rate || null; + } + return acc; + }, + {} + ); + + const ratesData = { + rates, + timestamp: data.timestamp * 1000, + }; + + localStorage.setItem("exchangeRates", JSON.stringify(ratesData)); + setExchangeRates(rates); + } catch (err) { + setError("Error fetching exchange rates"); + console.error("Exchange rate fetch error:", err); + } finally { + setIsLoading(false); + } + }; + + const convertPrice = (price) => { + if (!price || typeof price !== "number") return price; + if (!exchangeRates || !exchangeRates[selectedCurrency]) return price; + if (selectedCurrency === "INR") return price; + + try { + const rate = exchangeRates[selectedCurrency]; + return rate ? Number((price * rate).toFixed(2)) : price; + } catch (err) { + console.error("Price conversion error:", err); + return price; + } + }; + + const formatPrice = (price) => { + const convertedPrice = convertPrice(price); + + if (typeof convertedPrice !== "number") + return `${SUPPORTED_CURRENCIES[selectedCurrency].symbol}0.00`; + + try { + return new Intl.NumberFormat(getLocaleFromCurrency(selectedCurrency), { + style: "currency", + currency: selectedCurrency, + }).format(convertedPrice); + } catch (err) { + return `${ + SUPPORTED_CURRENCIES[selectedCurrency].symbol + }${convertedPrice.toFixed(2)}`; + } + }; + + const getLocaleFromCurrency = (currency) => { + const localeMap = { + INR: "en-IN", + MYR: "ms-MY", + NPR: "ne-NP", + }; + return localeMap[currency] || "en-US"; + }; + + useEffect(() => { + fetchExchangeRates(); + const interval = setInterval(fetchExchangeRates, 24 * 60 * 60 * 1000); + return () => clearInterval(interval); + }, []); + + const value = { + selectedCurrency, + setSelectedCurrency, + convertPrice, + formatPrice, + isLoading, + error, + SUPPORTED_CURRENCIES, + refreshRates: fetchExchangeRates, + }; + + return ( + + {children} + + ); +}; +export const useCurrency = () => { + const context = useContext(CurrencyContext); + if (!context) { + throw new Error('useCurrency must be used within a CurrencyProvider'); + } + return context; + }; \ No newline at end of file diff --git a/app/contexts/mainContext.js b/app/contexts/mainContext.js new file mode 100644 index 0000000..071e708 --- /dev/null +++ b/app/contexts/mainContext.js @@ -0,0 +1,92 @@ +'use client' +import axios from "axios"; +import { createContext, useState } from "react"; +import { useRouter } from "next/navigation"; +import toast from "react-hot-toast"; + + + + +const MainContext = createContext() + +export const ContextProvider = ({ children }) => { + const router = useRouter() + const [token, setToken] = useState(() => { + if (typeof window !== 'undefined' && localStorage.getItem('token')) { + return localStorage.getItem('token'); + } + return null; + }); + const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL; + + + const loginUser = async (credentials) => { + try { + const response = await axios.post(`${backendUrl}/account/login/`, credentials); + console.log("Login Successful:", response.data); + setToken(response.data.token) + localStorage.setItem('token',response.data.token) + toast.success('Login Successful'); + router.push('/') + + return response.data + } catch (error) { + if (error.response) { + + console.error("Error during login:", error.response.data); + const message = error.response.data.message || "Login failed. Please try again."; + toast.error(message); + } else if (error.request) { + + console.error("No response during login:", error.request); + toast.error("Unable to connect to the server. Please try again later."); + } else { + + console.error("Unexpected error during login:", error.message); + toast.error("An unexpected error occurred. Please try again."); + } + throw error; + } + }; + + const registerUser = async (credentials) => { + try { + const response = await axios.post(`${backendUrl}/account/register/`, credentials); + console.log("Register Successful:", response.data); + setToken(response.data.token) + localStorage.setItem('token',response.data.token) + toast.success('Registration Successful'); + router.push('/') + + return response.data; + } catch (error) { + if (error.response) { + console.error("Error during registration:", error.response.data); + const message = error.response.data.message || "Registration failed. Please try again."; + toast.error(message); + } else if (error.request) { + + console.error("No response during registration:", error.request); + toast.error("Unable to connect to the server. Please try again later."); + } else { + + console.error("Unexpected error during registration:", error.message); + toast.error("An unexpected error occurred. Please try again."); + } + throw error; + } + }; + + return ( + + {children} + + ) +} + +export default MainContext \ No newline at end of file diff --git a/app/contexts/productContext.js b/app/contexts/productContext.js new file mode 100644 index 0000000..2d133e2 --- /dev/null +++ b/app/contexts/productContext.js @@ -0,0 +1,61 @@ +"use client"; + +import authAxios, { backendUrl } from "@/utils/axios"; +import axios from "axios"; +import { createContext, useEffect, useState } from "react"; +import toast from "react-hot-toast"; + +const ProductContext = createContext(); + +export const ProductContextProvider = ({ children }) => { + const [products, setProducts] = useState(null); + const [category, setCategory] = useState(null); + + + const fetchData = async () => { + const response = await axios.get(`${backendUrl}/products/variants/`); + setProducts(response.data) + }; + + const fetchCategory = async () => { + const response = await axios.get(`${backendUrl}/products/category/`); + setCategory(response.data); + + }; + useEffect(() => { + fetchData(); + fetchCategory(); + }, []); + + const cartFn = async (variantId, designId, quantity) => { + + try{ + const response = await authAxios.post('/orders/cart/manage_item/',{ + variant: variantId, + design: designId, + quantity: quantity + }) + toast.success('Modified Cart Successfully!') + return response + } + catch(error){ + if (error?.response.data?.detail) { + toast.error('Please login First!') + } + else { + toast.error(error?.response.data?.error || 'Failed To Modify Cart') + } + return error + } + } + return ( + {children} + ); +}; + +export default ProductContext; diff --git a/app/fonts/GeistMonoVF.woff b/app/fonts/GeistMonoVF.woff new file mode 100644 index 0000000..f2ae185 Binary files /dev/null and b/app/fonts/GeistMonoVF.woff differ diff --git a/app/fonts/GeistVF.woff b/app/fonts/GeistVF.woff new file mode 100644 index 0000000..1b62daa Binary files /dev/null and b/app/fonts/GeistVF.woff differ diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..3a13830 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,87 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@import url('https://fonts.googleapis.com/css2?family=Emilys+Candy&display=swap'); + +@import url('https://fonts.googleapis.com/css2?family=Questrial&display=swap'); +/* bg-[#C19A5B] */ +body { + font-family: 'Questrial', sans-serif; + background-color: white; + +} + + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem + } + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55% + } +} +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +.hide-navbar::-webkit-scrollbar{ + display: none; +} + +.custom-border { + @apply border-[#fcdaa3]; + border-width: 1px; /* Custom border width less than 1px */ +} \ No newline at end of file diff --git a/app/layout.js b/app/layout.js new file mode 100644 index 0000000..e70eb81 --- /dev/null +++ b/app/layout.js @@ -0,0 +1,40 @@ +import { Toaster } from "react-hot-toast"; +import { ContextProvider } from "./contexts/mainContext"; +import "./globals.css"; + +import NavigationWrapper from "./NavigationWrapper"; +import WrapperFooter from "./WrapperFooter"; +import { ProductContextProvider } from "./contexts/productContext"; +import { CurrencyProvider } from "./contexts/currencyContext"; + +export const metadata = { + title: "Gupta Rudraksha", + description: "Powered by Rudraksha", +}; + +export default function RootLayout({ children }) { + return ( + + + + + + + + + + + + + {children} + + + + + + + ); +} diff --git a/app/loading.js b/app/loading.js new file mode 100644 index 0000000..da06d91 --- /dev/null +++ b/app/loading.js @@ -0,0 +1,14 @@ +import { Skeleton } from "@/components/ui/skeleton"; + +export default function loading() { + return ( +
    + {/* +
    + + */} +
    + {/*
    */} +
    + ); +} diff --git a/app/not-found.js b/app/not-found.js new file mode 100644 index 0000000..b9a2344 --- /dev/null +++ b/app/not-found.js @@ -0,0 +1,17 @@ +import Link from 'next/link' +import { headers } from 'next/headers' + +export default async function NotFound() { + const headersList = headers() + const domain = headersList.get('host') + + return ( +
    +

    Not Found:

    +

    Could not find requested resource

    +

    + Back to home +

    +
    + ) +} \ No newline at end of file diff --git a/app/page.js b/app/page.js new file mode 100644 index 0000000..8798a34 --- /dev/null +++ b/app/page.js @@ -0,0 +1,19 @@ +import Hero from "@/components/hero-page/Hero"; +import HeroFour from "@/components/hero-page/HeroFour"; +import HeroSix from "@/components/hero-page/HeroSix"; +import SecondGallery from "@/components/product-category/SecondGallery"; +import BannerSlider from "@/components/sliders/BannerSlider"; +import SliderTwo from "@/components/sliders/SliderTwo"; + +export default function Home() { + return ( + <> + + + + + + + + ); +} diff --git a/app/pages/about-us/page.jsx b/app/pages/about-us/page.jsx new file mode 100644 index 0000000..83acacc --- /dev/null +++ b/app/pages/about-us/page.jsx @@ -0,0 +1,17 @@ +import AboutUsTopBanner from '@/components/about-us/AboutTopBanner' +import AboutUsSecondBanner from '@/components/about-us/AboutUsSecondBanner' +import React from 'react' + +export const metadata= { + title: 'About Gupta Rudraksha; The World Largest Rudraksha Vendor' +} +const page = () => { + return ( +
    + + {/* */} +
    + ) +} + +export default page diff --git a/app/pages/buy-rudraksha/page.jsx b/app/pages/buy-rudraksha/page.jsx new file mode 100644 index 0000000..d2e8ba7 --- /dev/null +++ b/app/pages/buy-rudraksha/page.jsx @@ -0,0 +1,23 @@ +import BuyRudrakshaOne from '@/components/buy-rudraksha/BuyRudrakshaOne' +import PopularRudrakshaCombination from '@/components/buy-rudraksha/PopularRudrakshaCombination' +import ZodiacBasedSign from '@/components/buy-rudraksha/ZodiacBasedSign' +import PremiumBannerOne from '@/components/premium-rudraksha/PremiumBannerOne' +import React from 'react' + +export const metadata = { + title: 'Buy Rudraksha Online | Orginal Gupta Rudraksha', + description: "Generated by create next app", +} + +const page = () => { + return ( +
    + + + + +
    + ) +} + +export default page diff --git a/app/pages/certification-and-guarantee/page.jsx b/app/pages/certification-and-guarantee/page.jsx new file mode 100644 index 0000000..8e4bc6a --- /dev/null +++ b/app/pages/certification-and-guarantee/page.jsx @@ -0,0 +1,21 @@ +import CertificationBannerOne from '@/components/certification/CertificationBannerOne' +import CertificationBannerTwo from '@/components/certification/CertificationBannerTwo' +import CertificationGallerySection from '@/components/certification/CertificationGallery' +import React from 'react' + +export const metadata = { + title: 'Certified Authentic Rudraksha with Lifetime Guarantee', +} + + +const page = () => { + return ( +
    + {/* */} + + +
    + ) +} + +export default page diff --git a/app/pages/contact-us/page.jsx b/app/pages/contact-us/page.jsx new file mode 100644 index 0000000..a037dd4 --- /dev/null +++ b/app/pages/contact-us/page.jsx @@ -0,0 +1,20 @@ +import ContactUs from '@/components/contact-us/ContactUs' +import EmbeddedMap from '@/components/maps/Maps' +import React from 'react' + +export const metadata = { + title:"Contact Us" +} + + + +const Page = () => { + return ( +
    + + +
    + ) +} + +export default Page diff --git a/app/pages/exclusive-rudraksha/page.jsx b/app/pages/exclusive-rudraksha/page.jsx new file mode 100644 index 0000000..c2d111a --- /dev/null +++ b/app/pages/exclusive-rudraksha/page.jsx @@ -0,0 +1,20 @@ +import PopularRudrakshaCombination from '@/components/buy-rudraksha/PopularRudrakshaCombination' +import ExclusiveRudrakshaBanner from '@/components/exclusive-rudraksha/ExclusiveRudrakshaBanner' +import ListofRudrakshaCard from '@/components/exclusive-rudraksha/ListofRudrakshaCard' +import WhyShouldChooseUs from '@/components/exclusive-rudraksha/WhyShouldChooseUs' +import PremiumBannerOne from '@/components/premium-rudraksha/PremiumBannerOne' +import React from 'react' + +const page = () => { + return ( +
    + + + + + +
    + ) +} + +export default page diff --git a/app/pages/payment-information/page.jsx b/app/pages/payment-information/page.jsx new file mode 100644 index 0000000..f97903e --- /dev/null +++ b/app/pages/payment-information/page.jsx @@ -0,0 +1,11 @@ +import React from 'react' + +const Page = () => { + return ( +
    + +
    + ) +} + +export default Page diff --git a/app/pages/rudraksha-combination/page.jsx b/app/pages/rudraksha-combination/page.jsx new file mode 100644 index 0000000..5b1c7dc --- /dev/null +++ b/app/pages/rudraksha-combination/page.jsx @@ -0,0 +1,13 @@ +import PopularRudrakshaCombination from '@/components/buy-rudraksha/PopularRudrakshaCombination' +import React from 'react' + +const Page = () => { + return ( +
    + + +
    + ) +} + +export default Page diff --git a/app/pages/shipping-information/page.jsx b/app/pages/shipping-information/page.jsx new file mode 100644 index 0000000..c1e721e --- /dev/null +++ b/app/pages/shipping-information/page.jsx @@ -0,0 +1,15 @@ +import ShippingPolicy from "@/components/shipping-policy/ShippingPolicy"; +import React from "react"; +export const metadata = { + title: "Shipping Information", +}; + +const Page = () => { + return ( +
    + +
    + ); +}; + +export default Page; diff --git a/app/pages/shopping-cart/page.jsx b/app/pages/shopping-cart/page.jsx new file mode 100644 index 0000000..14842e1 --- /dev/null +++ b/app/pages/shopping-cart/page.jsx @@ -0,0 +1,13 @@ + +import ShoppingCart from "@/components/shopping-cart/shoppingCart"; +import React from "react"; + +const Page = () => { + return ( +
    + +
    + ); +}; + +export default Page; diff --git a/app/pages/track-order/page.jsx b/app/pages/track-order/page.jsx new file mode 100644 index 0000000..263f11d --- /dev/null +++ b/app/pages/track-order/page.jsx @@ -0,0 +1,16 @@ +import TrackOrder from "@/components/track-order/TrackOrder"; +import React from "react"; + +export const metadata = { + title: "Track Order", +}; + +const Page = () => { + return ( +
    + +S
    + ); +}; + +export default Page; diff --git a/app/policies/privacy-policy/page.jsx b/app/policies/privacy-policy/page.jsx new file mode 100644 index 0000000..f3e7fc6 --- /dev/null +++ b/app/policies/privacy-policy/page.jsx @@ -0,0 +1,16 @@ +import PremiumBannerOne from "@/components/premium-rudraksha/PremiumBannerOne"; +import PrivacyPolicy from "@/components/privacy-policy/PrivacyPolicy"; + +export const metadata = { + title: "Privacy Policy", +}; +const Page = () => { + return ( +
    + + +
    + ); +}; + +export default Page; diff --git a/app/policies/refund-policy/page.jsx b/app/policies/refund-policy/page.jsx new file mode 100644 index 0000000..99a300c --- /dev/null +++ b/app/policies/refund-policy/page.jsx @@ -0,0 +1,16 @@ + +import RefundPolicy from "@/components/refund-policy/RefundPolicy"; +import React from "react"; + +export const metadata = { + title: "Refund Policy", +}; +const Page = () => { + return ( +
    + +
    + ); +}; + +export default Page; diff --git a/app/policies/terms-of-services/page.jsx b/app/policies/terms-of-services/page.jsx new file mode 100644 index 0000000..92fd6ab --- /dev/null +++ b/app/policies/terms-of-services/page.jsx @@ -0,0 +1,11 @@ +import TermsOfService from "@/components/terms-services/TermsOfService"; + +const page = () => { + return ( +
    + +
    + ); +}; + +export default page; diff --git a/app/products/[name]/page.jsx b/app/products/[name]/page.jsx new file mode 100644 index 0000000..2ccffdd --- /dev/null +++ b/app/products/[name]/page.jsx @@ -0,0 +1,22 @@ +import AddToCardLeftSection from "@/components/products/AddToCardLeftSection"; +import AddToCardRightSection from "@/components/products/AddToCardRightSection"; +import RelatedProductCards from "@/components/products/RelatedProductCards"; +import RelatedVideos from "@/components/products/RelatedVideos"; +import React from "react"; + +const page = ({ params }) => { + + return ( +
    + +
    + + +
    + + {/* */} +
    + ); +}; + +export default page; diff --git a/app/products/premium-rudraksha-consultation-astrology/page.jsx b/app/products/premium-rudraksha-consultation-astrology/page.jsx new file mode 100644 index 0000000..4ed397f --- /dev/null +++ b/app/products/premium-rudraksha-consultation-astrology/page.jsx @@ -0,0 +1,26 @@ +import PremiumBanner from '@/components/premium-rudraksha/PremiumBanner' +import PremiumBannerLast from '@/components/premium-rudraksha/PremiumBannerLast' +import PremiumBannerOne from '@/components/premium-rudraksha/PremiumBannerOne' +import PremiumBannerTwo from '@/components/premium-rudraksha/PremiumBannerTwo' +import PremuimBannerThree from '@/components/premium-rudraksha/PremuimBannerThree' +import React from 'react' + +export const metadata = { + title: "Premium Rudraksha Consultation Astrology", + description: "Generated by create next app", +}; + + +const Page = () => { + return ( +
    + + + + + +
    + ) +} + +export default Page diff --git a/components.json b/components.json new file mode 100644 index 0000000..3a03f7d --- /dev/null +++ b/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": false, + "tailwind": { + "config": "tailwind.config.js", + "css": "app/globals.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} \ No newline at end of file diff --git a/components/about-us/AboutTopBanner.jsx b/components/about-us/AboutTopBanner.jsx new file mode 100644 index 0000000..06382c0 --- /dev/null +++ b/components/about-us/AboutTopBanner.jsx @@ -0,0 +1,12 @@ +import React from 'react' + +const AboutUsTopBanner = () => { + return ( +
    +

    "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."

    +

    - Late Mr. Balaram Khatiwada (Founding Father, Gupta Rudraksha)

    +
    + ) +} + +export default AboutUsTopBanner diff --git a/components/about-us/AboutUsSecondBanner.jsx b/components/about-us/AboutUsSecondBanner.jsx new file mode 100644 index 0000000..551353f --- /dev/null +++ b/components/about-us/AboutUsSecondBanner.jsx @@ -0,0 +1,137 @@ +import Image from "next/image"; +import React from "react"; + +const AboutUsSecondBanner = () => { + return ( + <> +
    +
    + Random placeholder image +
    +
    +

    1960s

    +

    + Late Mr. Balaram Khatiwada +

    +

    + 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's commitment to authenticity and + his way of treating customers as family members. +

    +

    + Cultural Expansion +

    +

    + 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. +

    +
    +
    + {/* second section */} +
    +
    +

    + 1990s-2000s +

    +

    + Mr. Mukunda Khatiwada's Involvement: +

    +
  • + Mr. Mukunda observes the exploitation of Rudraksha and the spread of + myths about it on the internet. +
  • + +

    + Exploitation and Myths +

    +
  • + 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. +
  • +

    + Leading Online Store +

    +
  • + 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. +
  • +
  • + Gupta Rudraksha becomes the leading online store, the only one based + in Nepal offering Rudraksha energized in the traditional fashion at + Pashupatinath Temple. +
  • +
    +
    + Random placeholder image +
    +
    + {/* third section */} +
    +
    + Random placeholder image +
    +
    +

    + Present +

    +

    Global Reach

    +
  • + Gupta Rudraksha supplies 90% of all Gupta Rudraksha globally. +
  • +
  • + The largest seller of Indra Mala (1-21 Mukhi) in the world. +
  • +
  • + Boasts the largest collection of Gupta Rudraksha and Shaligram + globally. +
  • +

    Clientele

    +
  • + Mr. Mukunda Khatiwada has provided Rudraksha to various celebrities, + business tycoons, yogis, gurus, and individuals from various walks + of life. +
  • +

    + Continued Legacy +

    +
  • + Gupta Rudraksha continues to uphold the values of authenticity, + tradition, and customer-centricity established by Mr. Balaram + Khatiwada.. +
  • +
    +
    + + ); +}; + +export default AboutUsSecondBanner; diff --git a/components/accounts/AccountSidebar.jsx b/components/accounts/AccountSidebar.jsx new file mode 100644 index 0000000..bc6c307 --- /dev/null +++ b/components/accounts/AccountSidebar.jsx @@ -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 ( + + + ); +}; + +export default AccountSidebar; diff --git a/components/accounts/AddNewAddress.jsx b/components/accounts/AddNewAddress.jsx new file mode 100644 index 0000000..9d766d7 --- /dev/null +++ b/components/accounts/AddNewAddress.jsx @@ -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 ( +
    +

    Add a new address

    + {error &&
    {error}
    } +
    +
    +
    + + +
    +
    + + +
    +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +
    + + +
    +
    + +
    + + +
    +
    +
    + ); +}; + +export default AddNewAddress; \ No newline at end of file diff --git a/components/accounts/addresses.jsx b/components/accounts/addresses.jsx new file mode 100644 index 0000000..83da841 --- /dev/null +++ b/components/accounts/addresses.jsx @@ -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 ( +
    +

    Address

    + + +
    + +

    Add new address

    +
    + + + {error &&

    {error}

    } + + {addresses.map((address) => ( +
    +
    + + +
    + +

    {address.first_name} {address.last_name}

    + {address.company &&

    {address.company}

    } +

    + {address.address} + {address.apartment && `, ${address.apartment}`} +

    +

    + {address.city}, {address.country} - {address.zipcode} +

    +

    Phone: {address.phone}

    +
    + ))} +
    + ); +}; + +export default Addresses; \ No newline at end of file diff --git a/components/accounts/editProfile.jsx b/components/accounts/editProfile.jsx new file mode 100644 index 0000000..b16325e --- /dev/null +++ b/components/accounts/editProfile.jsx @@ -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 ( +
    +

    Edit Profile

    +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + setProfile({ ...profile, profile_pic: e.target.files[0] })} + /> +
    +
    + +
    +
    + + +
    +
    +
    + ); +}; + +export default EditProfile; diff --git a/components/blog/BlogHome.jsx b/components/blog/BlogHome.jsx new file mode 100644 index 0000000..16d0653 --- /dev/null +++ b/components/blog/BlogHome.jsx @@ -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 }) => ( +
    +
    + + {title + +
    +
    + +

    {title}

    + +

    + {author} | {date} +

    +

    {excerpt}

    +
    +
    +); + +const PopularArticle = ({ title, author, date }) => ( +
    +

    {title}

    +

    + {author} | {date} +

    +
    +); + +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 ( +
    +

    + Insights from Gupta Rudraksha +

    +

    + Explore our latest articles on the spiritual, cultural, and healing + aspects +

    + {/* top container for one blog card */} + +
    +
    + + images blog + +
    +
    + +

    + Dhanteras Significance and How Rudraksha Brings Prosperity and + Protection +

    + +

    + Gupta Rudraksha | 30 September, 2024 +

    +

    + Dhanteras, the first day of Diwali festival, marks a unique + celebration of wealth and prosperity in Hindu tradition. As the + name suggests - 'Dhan' meaning wealth and + 'Teras' ref +

    +
    +
    +
    +

    Popular Articles

    + {popularArticles.map((article, index) => ( + + ))} +
    +
    + +
    +
    +

    Recent Blogs

    + {currentPosts.map((post, index) => ( + + ))} +
    + {[...Array(Math.ceil(recentBlogPosts.length / postsPerPage))].map( + (_, index) => ( + + ) + )} +
    +
    + +
    +

    Popular Articles

    + {popularArticles.map((article, index) => ( + + ))} +
    +
    +
    + ); +}; + +export default BlogHome; diff --git a/components/blog/SingleBlog.jsx b/components/blog/SingleBlog.jsx new file mode 100644 index 0000000..9e81bbb --- /dev/null +++ b/components/blog/SingleBlog.jsx @@ -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 ( +
    + {/* Blog Image */} +
    + Blog Cover Image +
    + + {/* Blog Content */} +
    + {blogResData ? ( +
    + ) : ( +

    Loading blog content...

    + )} +
    +
    + ); +}; + +export default SingleBlog; diff --git a/components/blog/blog.css b/components/blog/blog.css new file mode 100644 index 0000000..7708291 --- /dev/null +++ b/components/blog/blog.css @@ -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; + } +} diff --git a/components/buy-rudraksha/BuyRudrakshaOne.jsx b/components/buy-rudraksha/BuyRudrakshaOne.jsx new file mode 100644 index 0000000..078926c --- /dev/null +++ b/components/buy-rudraksha/BuyRudrakshaOne.jsx @@ -0,0 +1,35 @@ +import Image from "next/image"; +import React from "react"; + +const BuyRudrakshaOne = () => { + return ( +
    +
    + {" "} +
    +
    +

    Rudraksha

    +

    + 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's Karma and attract prosperity. As + the world'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. +

    +
    +
    + ); +}; + +export default BuyRudrakshaOne; diff --git a/components/buy-rudraksha/PopularRudrakshaCombination.jsx b/components/buy-rudraksha/PopularRudrakshaCombination.jsx new file mode 100644 index 0000000..75359c9 --- /dev/null +++ b/components/buy-rudraksha/PopularRudrakshaCombination.jsx @@ -0,0 +1,55 @@ +import Link from "next/link"; +import React from "react"; + +const PopularRudrakshaCombination = () => { + return ( +
    +

    + Popular Rudraksha Combination +

    +
    +
    +

    + Zodiac Combination +

    + + + +
    + +
    +

    Combination by Goals + and Aspirations

    + + + +
    + +
    +

    Combination for + Maha Dasha

    + + + +
    + +
    +

    Rudraksha Kavach

    + + + +
    +
    +
    + ); +}; + +export default PopularRudrakshaCombination; diff --git a/components/buy-rudraksha/ZodiacBasedSign.jsx b/components/buy-rudraksha/ZodiacBasedSign.jsx new file mode 100644 index 0000000..3d7d3cb --- /dev/null +++ b/components/buy-rudraksha/ZodiacBasedSign.jsx @@ -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 ( +
    +

    + Rudraksha Based On Zodiac Signs +

    + +
    + ); +}; + +export default ZodiacBasedSign; diff --git a/components/buy-rudraksha/ZodiacBasedSignClient.jsx b/components/buy-rudraksha/ZodiacBasedSignClient.jsx new file mode 100644 index 0000000..d3ae5dc --- /dev/null +++ b/components/buy-rudraksha/ZodiacBasedSignClient.jsx @@ -0,0 +1,70 @@ +"use client"; + +import Link from "next/link"; +import React from "react"; + +const ZodiacBasedSignClient = ({ zodiacSigns }) => { + return ( +
    +
    + {zodiacSigns.map((sign) => ( +
    +
    +
    +

    + {sign.name} +

    +
    +
    + + +
    +
    +
    + ))} +
    +
    + ); +}; + +const MiniCard = ({ price, type, mukhi, name }) => ( +
    + + {price !== null ? ( +

    + ${price.toFixed(2)} | {type} +

    + ) : ( +

    + Price not available | {type} +

    + )} + + + {mukhi !== null ? ( +

    + {mukhi} Mukhi {name} +

    + ) : ( +

    + Mukhi not specified | {name} +

    + )} + +
    +); + +export default ZodiacBasedSignClient; diff --git a/components/certification/CertificationBannerOne.jsx b/components/certification/CertificationBannerOne.jsx new file mode 100644 index 0000000..d8c0895 --- /dev/null +++ b/components/certification/CertificationBannerOne.jsx @@ -0,0 +1,9 @@ +import React from "react"; + +const CertificationBannerOne = () => { + return ( +
    + ); +}; + +export default CertificationBannerOne; diff --git a/components/certification/CertificationBannerTwo.jsx b/components/certification/CertificationBannerTwo.jsx new file mode 100644 index 0000000..51f5138 --- /dev/null +++ b/components/certification/CertificationBannerTwo.jsx @@ -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 ( +
    +

    + Gupta Rudraksha Information +

    +
    +
    + {infoItems.map((item, index) => ( +
    handleInfoClick(index)} + > +

    + {selectedInfo === index ? ( + + ) : ( + "" + )} + {item.title} +

    +
    + ))} +
    +
    + {selectedInfo !== null && ( +
    +
    +

    {infoItems[selectedInfo].title}

    +

    + {infoItems[selectedInfo].description} +

    +
    +
    + )} +
    +
    +
    + ) +} + +export default CertificationBannerTwo diff --git a/components/certification/CertificationGallery.jsx b/components/certification/CertificationGallery.jsx new file mode 100644 index 0000000..ae5db05 --- /dev/null +++ b/components/certification/CertificationGallery.jsx @@ -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 ( +
    +

    + Chamber of Commerce +

    + +
    + {images.slice(0, 3).map((src, index) => ( +
    + {`Gallery handleImageClick(index)} + /> +
    + ))} +
    + +
    + Gallery image 5 handleImageClick(4)} + /> +
    + + {selectedImage !== null && ( +
    +
    + {`Gallery + +
    +
    + )} +
    + ); +}; + +export default CertificationGallerySection; diff --git a/components/common-components/FaqCard.jsx b/components/common-components/FaqCard.jsx new file mode 100644 index 0000000..d2e56f4 --- /dev/null +++ b/components/common-components/FaqCard.jsx @@ -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

    Loading FAQs...

    ; + } + + if (error) { + return

    {error}

    ; + } + + if (!faq || faq.length === 0) { + return

    No FAQs available.

    ; + } + + const hasImage = faq.some((item) => item.image !== null); + const imageToShow = hasImage + ? `${backendUrl}${faq.find((item) => item.image !== null).image}` + : DEFAULT_IMAGE; + return ( +
    +

    + Frequently Asked Questions +

    +
    + FAQ Image +
    + {faq.map((item, index) => ( + + + + {item.question} + + + {item.answer} + + + + ))} +
    +
    +
    +

    + Quick Answers to Some Frequently Asked Questions. +

    + + + +
    +
    + ); +}; + +export default FaqCard; diff --git a/components/contact-us/ContactUs.jsx b/components/contact-us/ContactUs.jsx new file mode 100644 index 0000000..96b9dc6 --- /dev/null +++ b/components/contact-us/ContactUs.jsx @@ -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 ( +
    +
    +

    + Contact Us +

    +

    + Empowering Spiritual Connections - Feel Free to Connect with Us - Our + Doorway to Spiritual Assistance +

    +
    + +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +

    + Connecting Souls +

    +

    + Reach Out, Let's Share Spiritual Moments +

    +
    +
    + + +
    + +