This commit is contained in:
Meenadeveloper 2025-12-19 17:38:44 +05:30
parent 92ce73f4dd
commit b84898f904
34 changed files with 1013 additions and 160 deletions

35
package-lock.json generated
View File

@ -90,7 +90,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@ -451,7 +450,6 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@ -495,7 +493,6 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@ -1380,7 +1377,6 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz",
"integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/core-downloads-tracker": "^7.3.5",
@ -1514,7 +1510,6 @@
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.5.tgz",
"integrity": "sha512-yPaf5+gY3v80HNkJcPi6WT+r9ebeM4eJzrREXPxMt7pNTV/1eahyODO4fbH3Qvd8irNxDFYn5RQ3idHW55rA6g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/private-theming": "^7.3.5",
@ -2381,8 +2376,7 @@
}
],
"hasInstallScript": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@tsparticles/interaction-external-attract": {
"version": "3.9.1",
@ -3000,7 +2994,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.4.tgz",
"integrity": "sha512-tBFxBp9Nfyy5rsmefN+WXc1JeW/j2BpBHFdLZbEVfs9wn3E3NRFxwV0pJg8M1qQAexFpvz73hJXFofV0ZAu92A==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@ -3050,7 +3043,6 @@
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.181.0.tgz",
"integrity": "sha512-MLF1ks8yRM2k71D7RprFpDb9DOX0p22DbdPqT/uAkc6AtQXjxWCVDjCy23G9t1o8HcQPk7woD2NIyiaWcWPYmA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@dimforge/rapier3d-compat": "~0.12.0",
"@tweenjs/tween.js": "~23.1.3",
@ -3323,7 +3315,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@ -3600,7 +3591,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754",
@ -4020,8 +4010,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/d3-array": {
"version": "3.2.4",
@ -4149,7 +4138,6 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@ -4264,8 +4252,7 @@
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/embla-carousel-react": {
"version": "8.6.0",
@ -4442,7 +4429,6 @@
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@ -6074,7 +6060,6 @@
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.18.0.tgz",
"integrity": "sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.17.8",
"@types/react-reconciler": "^0.26.7",
@ -6157,7 +6142,6 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@ -6753,7 +6737,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@ -6862,7 +6845,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@ -7115,7 +7097,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -7125,7 +7106,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@ -7223,7 +7203,6 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@ -7450,8 +7429,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@ -7681,7 +7659,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@ -7881,7 +7858,6 @@
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz",
"integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@emotion/is-prop-valid": "1.2.2",
"@emotion/unitless": "0.8.1",
@ -8424,7 +8400,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz",
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@ -8577,7 +8552,6 @@
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
"integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.2.0",
@ -8740,7 +8714,6 @@
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
"dev": true,
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}

BIN
src/assets/images/god1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

View File

@ -174,8 +174,8 @@ const LoginPanel = () => {
const navigate = useNavigate();
const [formData, setFormData] = useState({
emailOrMobile: '',
password: '',
emailOrMobile: 'admin@gmail.com',
password: 'Password@123',
keepLoggedIn: false,
})
@ -222,7 +222,11 @@ const LoginPanel = () => {
setLoading(false)
setSuccessModal(true) // Show success modal
console.log('Form Data:', formData)
localStorage.setItem("token", "dummy-token");
navigate("/dashboard-home");
}, 1500)
}
const handleCloseSuccessModal = () => {

View File

@ -1,4 +1,5 @@
import { Facebook, Instagram, Linkedin, Twitter, Youtube } from 'lucide-react';
import { Facebook, Instagram, Linkedin, Twitter, Youtube } from "lucide-react";
import { Link } from "react-router-dom";
export default function Footer() {
return (
@ -7,15 +8,66 @@ export default function Footer() {
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8 mb-8">
{/* Need Help Section */}
<div>
<h3 className="text-[#A70710] font-bold text-lg mb-4">Need Help?</h3>
<h3 className="text-[#A70710] font-bold text-lg mb-4">
Need Help?
</h3>
<ul className="space-y-2">
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Member Login</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Sign Up</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Partner Search</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">How to Use Thirukalyanam Matrimony App</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Premium Memberships</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Customer Support</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Site Map</a></li>
<li>
<Link to="/login"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Member Login
</Link>
</li>
<li>
<Link
to="/registration"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Sign Up
</Link>
</li>
<li>
<a
href="/matches"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Partner Search
</a>
</li>
{/* <li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
How to Use Thirukalyanam Matrimony App
</a>
</li> */}
{/* <li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Premium Memberships
</a>
</li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Customer Support
</a>
</li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Site Map
</a>
</li> */}
</ul>
</div>
@ -23,22 +75,87 @@ export default function Footer() {
<div>
<h3 className="text-[#A70710] font-bold text-lg mb-4">Company</h3>
<ul className="space-y-2">
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">About Us</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Thirukalyanam Blog</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Careers</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Awards & Recognition</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Contact Us</a></li>
{/* <li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
About Us
</a>
</li> */}
{/* <li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Thirukalyanam Blog
</a>
</li> */}
{/* <li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Careers
</a>
</li> */}
{/* <li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Awards & Recognition
</a>
</li> */}
<li>
<Link
to="/contact"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Contact Us
</Link>
</li>
</ul>
</div>
{/* Privacy & You Section */}
<div>
<h3 className="text-[#A70710] font-bold text-lg mb-4">Privacy & You</h3>
<h3 className="text-[#A70710] font-bold text-lg mb-4">
Privacy & You
</h3>
<ul className="space-y-2">
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Terms of Use</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Privacy Policy</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Be Safe Online</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Report Misuse</a></li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Terms of Use
</a>
</li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Privacy Policy
</a>
</li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Be Safe Online
</a>
</li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Report Misuse
</a>
</li>
</ul>
</div>
@ -46,36 +163,66 @@ export default function Footer() {
<div>
<h3 className="text-[#A70710] font-bold text-lg mb-4">More</h3>
<ul className="space-y-2">
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">VIP Thirukalyanam</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Thirukalyanam Centres</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Success Stories</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Thirukalyanam Live</a></li>
<li><a href="#" className="text-gray-600 hover:text-green-600 transition-colors">Chart Generate</a></li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Be Safe Online
</a>
</li>
<li>
<a
href="#"
className="text-gray-600 hover:text-green-600 transition-colors"
>
Report Misuse
</a>
</li>
</ul>
</div>
{/* Social Media & Apps Section */}
<div>
<h3 className="text-[#A70710] font-bold text-lg mb-4">Find us on:</h3>
<h3 className="text-[#A70710] font-bold text-lg mb-4">
Find us on:
</h3>
<div className="flex gap-3 mb-6">
<a href="#" className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all">
<a
href="#"
className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all"
>
<Facebook className="w-5 h-5 text-gray-700" />
</a>
<a href="#" className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all">
<a
href="#"
className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all"
>
<Instagram className="w-5 h-5 text-gray-700" />
</a>
<a href="#" className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all">
<a
href="#"
className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all"
>
<Linkedin className="w-5 h-5 text-gray-700" />
</a>
<a href="#" className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all">
<a
href="#"
className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all"
>
<Twitter className="w-5 h-5 text-gray-700" />
</a>
<a href="#" className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all">
<a
href="#"
className="bg-white border border-gray-300 p-2 rounded hover:bg-green-50 hover:border-green-500 transition-all"
>
<Youtube className="w-5 h-5 text-gray-700" />
</a>
</div>
<h3 className="text-[#A70710] font-bold text-lg mb-4">Get the Thirukalyanam App</h3>
<h3 className="text-[#A70710] font-bold text-lg mb-4">
Get the Thirukalyanam App
</h3>
<div className="space-y-3">
<a href="#" className="block">
<img
@ -105,11 +252,13 @@ export default function Footer() {
<div className="border-t border-gray-200 pt-6">
<div className="flex flex-col md:flex-row justify-between items-center">
<p className="text-sm text-gray-600 mb-4 md:mb-0">
© 1991-{new Date().getFullYear()} Thirukalyanam, The World's Leading Matchmaking Service
© {new Date().getFullYear()} Thirukalyanam, The World's
Leading Matchmaking Service
</p>
<p className="text-sm text-gray-600">
Passionately created by <span className="text-[#034E08] font-semibold">Amrithaa</span>
Passionately created by{" "}
<span className="text-[#034E08] font-semibold">Amrithaa</span>
</p>
</div>
</div>

View File

@ -18,14 +18,16 @@ import Modal from "@mui/material/Modal";
import Button from "@mui/material/Button";
import LazyImage from "./LazyImage";
import Logo from "../../assets/images/logo.png";
import { useNavigate } from "react-router-dom";
import { useLocation, useNavigate } from "react-router-dom";
import { useState, useRef, useEffect } from "react";
import { useTheme, useMediaQuery, ListItemIcon } from "@mui/material";
import { Home, Users, Heart, MessageCircle, Search, Bell } from "lucide-react";
import { isAuthenticated } from "../../utills/auth";
import userimg from "../../assets/images/bride1.jpg"
const NAV_LINKS = [
{ label: "Home", path: "/" },
// { label: "Home", path: "/" },
{ label: "Matches", path: "/matches" },
// { label: "ProfileCard", path: "/profile-card" },
{ label: "Interest", path: "/interest" },
{ label: "Horoscope", path: "/horoscoper-generate" },
{ label: "Messages", path: "/chat" },
@ -53,17 +55,13 @@ const ACCOUNT_SETTINGS = [
{ label: "Logout", action: "logout" }
];
const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick }) => {
const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick, activeItem }) => {
const [activeIndex, setActiveIndex] = useState(0);
const [indicatorStyle, setIndicatorStyle] = useState({});
const [isAnimating, setIsAnimating] = useState(false);
const navRef = useRef(null);
const buttonRefs = useRef([]);
useEffect(() => {
updateIndicator(activeIndex);
}, []);
const updateIndicator = (index) => {
const button = buttonRefs.current[index];
if (button && navRef.current) {
@ -76,6 +74,23 @@ const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick }) => {
}
};
// sync with activeItem from router
useEffect(() => {
if (!activeItem) return;
const newIndex = items.indexOf(activeItem);
if (newIndex !== -1 && newIndex !== activeIndex) {
setActiveIndex(newIndex);
updateIndicator(newIndex);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeItem, items]);
// initial indicator
useEffect(() => {
updateIndicator(activeIndex);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleClick = (index) => {
if (index === activeIndex || isAnimating) return;
setIsAnimating(true);
@ -85,9 +100,9 @@ const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick }) => {
const navRect = navRef.current.getBoundingClientRect();
const newRect = newButton.getBoundingClientRect();
setIndicatorStyle(prev => ({
setIndicatorStyle((prev) => ({
...prev,
left: newRect.left - navRect.left + newRect.width / 2 - 18,
left: newRect.left - navRect.left + newRect.width / 2 - 18
}));
setTimeout(() => {
@ -103,16 +118,11 @@ const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick }) => {
{items.map((item, index) => (
<button
key={item}
ref={el => buttonRefs.current[index] = el}
ref={(el) => (buttonRefs.current[index] = el)}
onClick={() => handleClick(index)}
className={`cursor-pointer relative uppercase text-sm font-medium transition-all duration-300 pb-2 ${
activeIndex === index ? 'text-black' : 'text-gray-900 hover:text-gray-600'
activeIndex === index ? "text-black" : "text-gray-900 hover:text-gray-600"
}`}
style={{
// textShadow: activeIndex === index
// ? `0 0 10px ${color}, 0 0 20px ${color}, 0 0 30px ${color}`
// : 'none'
}}
>
{item}
</button>
@ -124,7 +134,7 @@ const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick }) => {
left: indicatorStyle.left,
opacity: indicatorStyle.opacity,
backgroundColor: color,
boxShadow: `0 0 10px ${color}, 0 0 20px ${color}, 0 0 30px ${color}, 0 0 40px ${color}`,
boxShadow: `0 0 10px ${color}, 0 0 20px ${color}, 0 0 30px ${color}, 0 0 40px ${color}`
}}
/>
</nav>
@ -132,7 +142,9 @@ const SparkleNavbar = ({ items, color = "#0fec1eff", onItemClick }) => {
};
const ProfileHeader = () => {
const auth = isAuthenticated();
const navigate = useNavigate();
const location = useLocation();
const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false);
const [profileDrawerOpen, setProfileDrawerOpen] = useState(false);
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
@ -145,6 +157,14 @@ const ProfileHeader = () => {
const toggleProfileDrawer = (open) => () => setProfileDrawerOpen(open);
const [selectedItem, setSelectedItem] = useState("Home");
const currentNav = NAV_LINKS.find(link =>
location.pathname.startsWith(link.path)
);
const currentLabel = currentNav?.label ?? NAV_LINKS[0].label;
const handleMenuClick = (item) => {
if (item.action === "delete") {
@ -273,11 +293,11 @@ const ProfileHeader = () => {
<AppBar position="sticky" sx={{ backgroundColor: "#fff" }}>
<Container maxWidth="xl">
<Toolbar disableGutters>
<Box sx={{ display: { xs: "none", md: "flex" }, mr: 1 }}>
<Box onClick={() => navigate("/")} sx={{ display: { xs: "none", md: "flex" }, mr: 1 }}>
<LazyImage
src={Logo}
className="w-full h-[70px] my-2 rounded-lg object-cover cursor-pointer"
onClick={() => navigate("/")}
/>
</Box>
@ -294,6 +314,7 @@ const ProfileHeader = () => {
<LazyImage
src={Logo}
className="w-full h-[50px] rounded-lg object-cover"
/>
</Box>
@ -301,6 +322,7 @@ const ProfileHeader = () => {
<SparkleNavbar
items={NAV_LINKS.map(link => link.label)}
color="#034E08"
activeItem={currentLabel}
onItemClick={(item) => {
setSelectedItem(item);
const link = NAV_LINKS.find(l => l.label === item);
@ -309,13 +331,21 @@ const ProfileHeader = () => {
/>
</Box>
{(auth ? (
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Account Menu">
<IconButton onClick={toggleProfileDrawer(true)}>
<Avatar src="/static/images/avatar/2.jpg" />
<Avatar sx={{width:"50px", height:"50px"}} src={userimg || "/static/images/avatar/2.jpg" }/>
</IconButton>
</Tooltip>
</Box>
):( <button className="ml-1 bg-red-900 text-white px-4 py-2 rounded-md hover:bg-red-800 transition-colors"
onClick={() => navigate("/login")}>Sign In / Sign Up</button>))}
</Toolbar>
</Container>
</AppBar>

View File

@ -1,5 +1,7 @@
import { useNavigate } from "react-router-dom";
import girlchat from "../../assets/images/girlchat.webp"
const AstroChatUI = () => {
const navigate = useNavigate();
return (
<>
@ -26,7 +28,7 @@ const AstroChatUI = () => {
<div>
<h1 className="text-3xl font-bold">
<span className="text-gray-900">Astro</span>
<span className="text-[#A70710]">FreeChart</span>
<span className="text-[#A70710]">Horoscope</span>
</h1>
</div>
</div>
@ -70,8 +72,10 @@ const AstroChatUI = () => {
</div>
{/* CTA Button */}
<button className="relative z-[99] w-[fit-content] bg-[#034E08] hover:bg-[#A70710] text-white font-bold text-[16px] py-4 px-6 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105">
Download AstroFreeChart
<button onClick={()=>{
navigate("/horoscoper-generate")
}} className="relative z-[99] w-[fit-content] bg-[#034E08] hover:bg-[#A70710] text-white font-bold text-[16px] py-4 px-6 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105">
Upload Horoscope
</button>
{/* Girl Image - Positioned at bottom right */}

View File

@ -6,27 +6,34 @@ import { motion } from 'framer-motion';
import { Crown, Bookmark, User, Briefcase, MapPin, X, Send, ChevronLeft, ChevronRight } from 'lucide-react';
import { useRef } from "react";
import LazyImage from "../common/LazyImage";
import weddingImg1 from "../../assets/images/wedding6.jpeg";
import weddingImg2 from "../../assets/images/wedding8.jpg";
import weddingImg3 from "../../assets/images/wedding7.jpg";
const articleData = [
{
title: "Marriage is not just finding the right partner, it's creating a lifetime of moments together Find someone who understands your heart and walks with you in every season.",
img: "https://images.unsplash.com/photo-1519744792095-2f2205e87b6f?ixlib=rb-4.0.3&auto=format&fit=crop&w=900&q=80"
img: weddingImg1,
},
{
title: "Top 10 Qualities for a Happy Marriage, A perfect match begins with trust, respect, and shared dreams",
img: "https://images.unsplash.com/photo-1519744792095-2f2205e87b6f?ixlib=rb-4.0.3&auto=format&fit=crop&w=900&q=80"
img: weddingImg2
},
{
title: "Expert Tips for a Strong Relationship, A perfect match begins with trust, respect, and shared dreams",
img: "https://images.unsplash.com/photo-1519744792095-2f2205e87b6f?ixlib=rb-4.0.3&auto=format&fit=crop&w=900&q=80"
img: weddingImg3
},
{
title: "How to Build Trust in Marriage, A perfect match begins with trust, respect, and shared dreams",
img: "https://images.unsplash.com/photo-1519744792095-2f2205e87b6f?ixlib=rb-4.0.3&auto=format&fit=crop&w=900&q=80"
img: weddingImg1
},
{
title: "Communication Secrets for Couples, A perfect match begins with trust, respect, and shared dreams,A perfect match begins with trust, respect, and shared dreams.A perfect match begins with trust, respect, and shared dreams.A perfect match begins with trust, respect, and shared dreams,Real relationships are built on honesty, compassion, and understanding.,Real relationships are built on honesty, compassion, and understanding.",
img: "https://images.unsplash.com/photo-1482849297070-f4fae2173efe?ixlib=rb-4.0.3&auto=format&fit=crop&w=900&q=80"
img: weddingImg1
}
];

View File

@ -1,6 +1,8 @@
import { useNavigate } from "react-router-dom";
import membershipgirl from "../../assets/images/membership.avif";
const PaidMemberCard = () => {
const navigate = useNavigate();
return (
<>
@ -41,7 +43,9 @@ const PaidMemberCard = () => {
</ul>
{/* Button */}
<button className="mt-6 bg-[#034E08] hover:bg-[#A70710] text-white font-semibold py-3 px-6 rounded-full text-lg transition-all">
<button onClick={()=>{
navigate("/subscription-plan")
}} className="mt-6 bg-[#034E08] hover:bg-[#A70710] text-white font-semibold py-3 px-6 rounded-full text-lg transition-all">
See membership plans
</button>
</div>

View File

@ -21,6 +21,7 @@ const ProfileCompletion = () => {
bgColor: "bg-green-50",
iconColor: "text-green-600",
borderColor: "border-green-200",
url:"/profile-edit"
},
{
id: 2,
@ -29,6 +30,7 @@ const ProfileCompletion = () => {
bgColor: "bg-purple-50",
iconColor: "text-purple-600",
borderColor: "border-purple-200",
url:"/horoscoper-generate"
},
{
id: 3,
@ -37,6 +39,7 @@ const ProfileCompletion = () => {
bgColor: "bg-red-50",
iconColor: "text-red-600",
borderColor: "border-red-200",
url:"/profile-edit"
},
];
@ -130,7 +133,10 @@ const ProfileCompletion = () => {
{cards.map((card, index) => (
<div className=" border border-1 border-red-50 bg-white rounded-3xl hover:bg-red-50 hover:border-2
<div
onClick={() => navigate(card.url)}
className=" border border-1 border-red-50 bg-white rounded-3xl hover:bg-red-50 hover:border-2
flex flex-col items-center space-x-2 h-32 justify-center transition-colors duration-500
cursor-pointer ">
{/* Icon Container */}

View File

@ -3,6 +3,9 @@ import { motion } from 'framer-motion';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
import { Play, X, Heart, Share2, Eye, ChevronLeft, ChevronRight } from 'lucide-react';
import weddingImg1 from "../../assets/images/wedding6.jpeg";
import weddingImg2 from "../../assets/images/wedding8.jpg";
import weddingImg3 from "../../assets/images/wedding6.jpeg";
// Import Swiper styles
import 'swiper/css';
@ -18,7 +21,7 @@ const VideoSwiperGallery = () => {
{
id: 1,
title: 'Priya & Rahul - Wedding Story',
thumbnail: 'https://images.unsplash.com/photo-1519741497674-611481863552?w=600&h=400&fit=crop',
thumbnail: weddingImg1,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
views: '2.4K',
likes: '142',
@ -27,7 +30,7 @@ const VideoSwiperGallery = () => {
{
id: 2,
title: 'Aisha - Profile Introduction',
thumbnail: 'https://images.unsplash.com/photo-1606216794079-e48e3e2a3f6a?w=600&h=400&fit=crop',
thumbnail: weddingImg2,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
views: '1.8K',
likes: '98',
@ -36,7 +39,7 @@ const VideoSwiperGallery = () => {
{
id: 3,
title: 'Rohan - Life Journey',
thumbnail: 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?w=600&h=400&fit=crop',
thumbnail: weddingImg3,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4',
views: '3.2K',
likes: '256',
@ -45,7 +48,7 @@ const VideoSwiperGallery = () => {
{
id: 4,
title: 'Divya - Family Values',
thumbnail: 'https://images.unsplash.com/photo-1522673607200-164d1b6ce486?w=600&h=400&fit=crop',
thumbnail: weddingImg1,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4',
views: '1.5K',
likes: '87',
@ -54,7 +57,7 @@ const VideoSwiperGallery = () => {
{
id: 5,
title: 'Karthik & Meera - First Meet',
thumbnail: 'https://images.unsplash.com/photo-1583939003579-730e3918a45a?w=600&h=400&fit=crop',
thumbnail: weddingImg2,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4',
views: '4.1K',
likes: '312',
@ -63,7 +66,7 @@ const VideoSwiperGallery = () => {
{
id: 6,
title: 'Sneha - Hobbies & Interests',
thumbnail: 'https://images.unsplash.com/photo-1465495976277-4387d4b0b4c6?w=600&h=400&fit=crop',
thumbnail: weddingImg3,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4',
views: '2.7K',
likes: '178',
@ -72,7 +75,7 @@ const VideoSwiperGallery = () => {
{
id: 7,
title: 'Arjun - Career & Dreams',
thumbnail: 'https://images.unsplash.com/photo-1492691527719-9d1e07e534b4?w=600&h=400&fit=crop',
thumbnail: weddingImg1,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4',
views: '1.9K',
likes: '134',
@ -81,7 +84,7 @@ const VideoSwiperGallery = () => {
{
id: 8,
title: 'Lakshmi - Traditional Values',
thumbnail: 'https://images.unsplash.com/photo-1606216794074-735e91aa2c92?w=600&h=400&fit=crop',
thumbnail: weddingImg2,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4',
views: '3.5K',
likes: '267',
@ -90,7 +93,7 @@ const VideoSwiperGallery = () => {
{
id: 9,
title: 'Vikram - Adventure Life',
thumbnail: 'https://images.unsplash.com/photo-1519167758481-83f29da8c4f3?w=600&h=400&fit=crop',
thumbnail: weddingImg3,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
views: '5.2K',
likes: '423',
@ -99,7 +102,7 @@ const VideoSwiperGallery = () => {
{
id: 10,
title: 'Anjali - Creative Journey',
thumbnail: 'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?w=600&h=400&fit=crop',
thumbnail: weddingImg1,
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
views: '3.8K',
likes: '289',
@ -319,7 +322,7 @@ const VideoSwiperGallery = () => {
</div>
{/* View All Button */}
<motion.div
{/* <motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.5 }}
@ -332,7 +335,7 @@ const VideoSwiperGallery = () => {
>
View All Videos
</motion.button>
</motion.div>
</motion.div> */}
</div>
{/* Video Modal */}

View File

@ -0,0 +1,66 @@
import { Swiper, SwiperSlide } from "swiper/react";
import { Autoplay, Pagination, Navigation } from "swiper/modules";
import god1 from "../../assets/images/god1.png";
import god2 from "../../assets/images/perumal.png"
import "swiper/css";
import "swiper/css/pagination";
import "swiper/css/navigation";
import "../../styles/heroSlider.css";
import { useNavigate } from "react-router-dom";
const slides = [
{
image: god1,
title: "Find Your Perfect Life Partner",
description:
"Trusted matches, meaningful connections, lifelong happiness.",
button: "Register Now",
},
{
image: god2,
title: "Where True Love Begins",
description:
"Discover compatible matches made just for you. Start your journey today.",
button: "Register Now",
},
];
const HeroSlider = () => {
const navigate = useNavigate();
return (
<Swiper
modules={[Autoplay, Pagination, Navigation]}
autoplay={{ delay: 6000 }}
pagination={{ clickable: true }}
loop
className="hero-swiper"
>
{slides.map((slide, index) => (
<SwiperSlide key={index}>
<div className="hero-wrapper">
<div className="hero-slide">
{/* Left Image */}
<div className="hero-image">
<img src={slide.image} alt="hero" />
</div>
{/* Right Content */}
<div className="hero-content">
<h2>{slide.title}</h2>
<p>{slide.description}</p>
<button onClick={()=>{
navigate("/registration")
}}>{slide.button}</button>
</div>
</div>
</div>
</SwiperSlide>
))}
</Swiper>
);
};
export default HeroSlider;

View File

@ -0,0 +1,131 @@
import React from "react";
import { Heart, X, Crown, Bookmark } from "lucide-react";
// Import your images
import Profile1 from "../../assets/images/bride1.jpg";
import Profile2 from "../../assets/images/bride2.jpg";
import Profile3 from "../../assets/images/bride3.jpg";
import Profile4 from "../../assets/images/bride4.jpg";
export default function ProfileCardDemo() {
// Sample data for multiple cards with image paths
const profiles = [
{
id: 1,
name: "Jerome Bell",
age: "22 yrs",
height: "5'2\"",
location: "Chennai",
caste: "Brahmin",
zodiac1: "Aries",
zodiac2: "Scorpio",
image: Profile1,
},
{
id: 2,
name: "Neha Singh",
age: "26 yrs",
height: "5'6\"",
location: "Delhi",
caste: "Brahmin",
zodiac1: "Aries",
zodiac2: "Scorpio",
image: Profile2,
},
{
id: 3,
name: "Priya Sharma",
age: "24 yrs",
height: "5'4\"",
location: "Mumbai",
caste: "Brahmin",
zodiac1: "Aries",
zodiac2: "Scorpio",
image: Profile3,
},
{
id: 4,
name: "Kavya Iyer",
age: "23 yrs",
height: "5'3\"",
location: "Bangalore",
caste: "Brahmin",
zodiac1: "Aries",
zodiac2: "Scorpio",
image: Profile4,
},
];
return (
<div className=" flex justify-center items-center py-8 md:px-4">
{/* Grid Container - max-w-[1400px] with 4 columns */}
<div className="w-full max-w-[1200px] grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{profiles.map((profile) => (
<div
key={profile.id}
className="w-full rounded-[28px] overflow-hidden bg-white shadow-2xl"
>
{/* IMAGE SECTION */}
<div className="relative">
<img
src={profile.image}
alt="profile"
className="w-full h-[320px] object-cover"
/>
{/* LEFT ICON (CROWN) */}
<div className="absolute top-4 left-4 w-9 h-9 rounded-full bg-[#8b0000] flex items-center justify-center">
<Crown size={18} color="#fff" />
</div>
{/* RIGHT ICON (SHORTLIST) */}
<div className="absolute top-4 right-4 px-3 py-1.5 rounded-[20px] bg-white flex items-center gap-1.5 text-[13px] font-medium shadow-lg">
<Bookmark size={14} /> Shortlist
</div>
{/* FADE FOR GLASS */}
<div className="absolute bottom-0 left-0 right-0 h-0 bg-gradient-to-t from-white/90 to-transparent" />
</div>
{/* GLASS CONTENT */}
<div className="px-4 py-[12px] -mt-[60px] bg-white/65 backdrop-blur-[25px] rounded-t-[15px] shadow-[0_-10px_30px_rgba(0,0,0,0.15)] relative z-[2]">
<h2 className="text-center text-[22px] font-semibold mb-3.5">
{profile.name}
</h2>
{/* INFO PILLS */}
<div className="flex flex-wrap justify-center gap-2 ">
{[
profile.age,
profile.height,
profile.location,
profile.caste,
profile.zodiac1,
profile.zodiac2,
].map((v, i) => (
<span
key={i}
className="px-3.5 py-1.5 rounded-[20px] bg-white/70 border border-black/8 text-[13px] "
>
{v}
</span>
))}
</div>
{/* ACTION BUTTONS */}
<div className="flex gap-3 mt-[15px] items-center justify-center">
<button className="px-2 py-1 rounded-[20px] border border-red-200 bg-red-50 flex items-center justify-center gap-1.5 cursor-pointer">
<X size={18} /> Decline
</button>
<button className=" px-2 py-1 rounded-[20px] border border-green-200 bg-green-100 text-green-900 flex items-center justify-center gap-1.5 font-medium cursor-pointer">
<Heart size={18} /> Interest
</button>
</div>
</div>
</div>
))}
</div>
</div>
);
}

View File

@ -30,16 +30,16 @@ const LifestyleDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => {
const fields = [
{ name: "diet", label: "Diet", options: ["Veg", "Non-Veg", "Eggetarian"] },
{
name: "drinking",
label: "Drinking Habits",
options: ["No", "Occasionally", "Regularly"],
},
{
name: "smoking",
label: "Smoking Habits",
options: ["No", "Occasionally", "Regularly"],
},
// {
// name: "drinking",
// label: "Drinking Habits",
// options: ["No", "Occasionally", "Regularly"],
// },
// {
// name: "smoking",
// label: "Smoking Habits",
// options: ["No", "Occasionally", "Regularly"],
// },
{
name: "hobbies",
label: "Hobbies & Interests",

View File

@ -299,8 +299,8 @@ const ProfilePreviewPage = () => {
<CardContent sx={{ pt: 1 }}>
{renderField("Diet", lifestyleDetails.diet)}
{renderField("Drinking", lifestyleDetails.drinking)}
{renderField("Smoking", lifestyleDetails.smoking)}
{/* {renderField("Drinking", lifestyleDetails.drinking)}
{renderField("Smoking", lifestyleDetails.smoking)} */}
{renderField("Hobbies", lifestyleDetails.hobbies)}
</CardContent>

21
src/layout/HomeLayout.jsx Normal file
View File

@ -0,0 +1,21 @@
import { Outlet } from "react-router-dom";
import ProfileHeader from "../components/common/ProfileHeader";
import Footer from "../components/common/Footer";
const HomeLayout = () => {
return (
<>
<ProfileHeader/>
{/* <div className=" w-[100%] max-w-[1400px] mx-auto p-2"
style={{
marginBottom:'10px',
}}> */}
<Outlet />
{/* </div> */}
<Footer/>
</>
)
}
export default HomeLayout

View File

@ -0,0 +1,27 @@
import React from 'react'
import ProfileHeader from '../components/common/ProfileHeader'
import Footer from '../components/common/Footer'
import { Navigate, Outlet } from 'react-router-dom'
import { isAuthenticated } from '../utills/auth'
const MatchesLayout = () => {
const auth = isAuthenticated();
return (
<>
<ProfileHeader/>
<div className="page-wrapper w-[100%] max-w-[1400px] mx-auto p-2"
style={{
marginBottom:'10px',
}}>
{/* <Outlet /> */}
{(auth ? <Outlet /> : <Navigate to="/login" replace />)}
</div>
<Footer/>
</>
)
}
export default MatchesLayout

View File

@ -1,21 +1,27 @@
import { Outlet } from "react-router-dom";
import { Navigate, Outlet } from "react-router-dom";
import ProfileHeader from "../components/common/ProfileHeader";
import Footer from "../components/common/Footer";
import { isAuthenticated } from "../utills/auth";
const ProfileLayout = () => {
const auth = isAuthenticated();
return (
<>
<ProfileHeader />
<div className=" w-[100%] max-w-[1400px] mx-auto p-2"
<div
className="page-wrapper w-[100%] max-w-[1400px] mx-auto p-2"
style={{
marginBottom:'10px',
// overflowX:"hidden"
}}>
<Outlet />
marginBottom: "10px",
overflowX: "hidden",
}}
>
{/* <Outlet /> */}
{auth ? <Outlet /> : <Navigate to="/login" replace />}
</div>
<Footer />
</>
)
}
);
};
export default ProfileLayout
export default ProfileLayout;

View File

@ -15,6 +15,7 @@ import wedding12 from "../assets/images/wedding12.avif";
import MatrimonySwipeCards from "../components/common/MatrimonySwipeCards";
import ThreeScrollTrigger from "../components/common/Threemarquee";
import AppQRCode from "../components/landing/AppQRCode";
import HeroSlider from "../components/ui/HeroSlider";
@ -67,7 +68,7 @@ const HomePage = () => {
return (
<div className="">
<div className="relative">
{/* <div className="relative">
<ThreeDMarquee images={images} cols = {4} />
<div
className="absolute bottom-0 left-0 w-full h-[100px] z-9"
@ -77,7 +78,9 @@ const HomePage = () => {
"linear-gradient(to bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,0.6) 40%, rgba(255,255,255,1) 100%)",
}}
/>
</div>
</div> */}
<HeroSlider/>
<AppPromoteSection/>
<div className="w-full bg-white py-8 pt-0">
<AppQRCode/>

View File

@ -6,7 +6,9 @@ const MatchesPage = () => {
<>
<SearchUI/>
<MatchesInterface/>
<style>
</style>
</>
)

39
src/pages/NotFound.jsx Normal file
View File

@ -0,0 +1,39 @@
import { useNavigate } from "react-router-dom";
const NotFound = () => {
const navigate = useNavigate();
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4">
<div className="text-center max-w-md">
<h1 className="text-7xl font-bold text-red-900">404</h1>
<h2 className="mt-4 text-2xl font-semibold text-gray-800">
Page Not Found
</h2>
<p className="mt-2 text-gray-600">
Sorry, the page you are looking for doesnt exist or has been moved.
</p>
<div className="mt-6 flex justify-center gap-4">
<button
onClick={() => navigate(-1)}
className="px-5 py-2 rounded-lg bg-gray-200 hover:bg-gray-300 transition"
>
Go Back
</button>
<button
onClick={() => navigate("/")}
className="px-5 py-2 rounded-lg bg-red-900 text-white hover:bg-red-600 transition"
>
Go Home
</button>
</div>
</div>
</div>
);
};
export default NotFound;

View File

@ -41,8 +41,8 @@ const registrationformSlice = createSlice({
},
lifestyleDetails: {
diet: "",
drinking: "",
smoking: "",
// drinking: "",
// smoking: "",
hobbies: "",
},
partnerPreferences: {
@ -160,8 +160,8 @@ preloadDummyProfile: (state) => {
state.lifestyleDetails = {
...state.lifestyleDetails,
diet: "Veg",
drinking: "No",
smoking: "No",
// drinking: "No",
// smoking: "No",
hobbies: "Reading, Music",
};
state.partnerPreferences = {

View File

@ -5,18 +5,23 @@ import LoginPage from "../pages/auth/LoginPage";
import ForgotPasswordPage from "../pages/auth/ForgotPasswordPage";
import ChangePasswordPage from "../components/auth/ChangePasswordForm";
import ProfileLayout from "../layout/ProfileLayout";
import HomeLayout from "../layout/HomeLayout";
import StepperForm from "../feature/StepperForm";
import NotFound from "../pages/NotFound";
const PublicRoutes = () => {
return (
<>
<Route element={<ProfileLayout />}>
<Route element={<HomeLayout />}>
<Route path="/" element={<HomePage />} />
<Route path="/registration" element={<StepperForm />} />
</Route>
<Route path="/login" element={<LoginPage />} />
<Route path="/forgot-password" element={<ForgotPasswordPage />} />
{/* 404 route MUST be last */}
<Route path="*" element={<NotFound />} />
</>
)
}

View File

@ -19,14 +19,16 @@ import StepperForm from "../feature/StepperForm";
import FilterForm from "../feature/FilterForm";
import ProfilePreviewPage from "../feature/ProfilePreviewPage";
import NotificationPage from "../pages/NotificationPage";
import MatchesLayout from "../layout/MatchesLayout";
import ProfileCardDemo from "../components/ui/ProfileCardDemo";
const UserRoutes = () => {
return (
<>
<Route element={<ProfileLayout />}>
{/* <Route element={<ProfileLayout />}>
<Route path="/registration" element={<StepperForm />} />
</Route>
</Route> */}
<Route element={<ProfileLayout />}>
<Route path="/filter" element={<FilterForm />} />
@ -38,9 +40,12 @@ const UserRoutes = () => {
<Route element={<ProfileLayout />}>
<Route path="/main/dashboard" element={<UserDashboardHome />} />
</Route>
<Route element={<ProfileLayout />}>
<Route element={<MatchesLayout />}>
<Route path="/matches" element={<MatchesPage />} />
</Route>
<Route element={<MatchesLayout />}>
<Route path="/profile-card" element={<ProfileCardDemo />} />
</Route>
<Route element={<ProfileLayout />}>
<Route path="/interest" element={<InterestSendPage />} />

View File

@ -0,0 +1,187 @@
import axios from "axios";
import { API_ENDPOINTS } from "./apiEndpoints";
/**
* Create an Axios instance with the base URL from environment variables
* and default headers for JSON communication.
*/
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_UNICORN_API_BASE_URL ||
"https://www.unicorn.amrithaa.net/backend/api/" ,
headers: {
"Content-Type": "application/json",
},
});
/**
* Create a separate Axios instance for handling multipart file uploads
* while sharing the same base URL and authorization mechanism.
*/
const apiForFiles = axios.create({
baseURL: import.meta.env.VITE_UNICORN_API_BASE_URL,
headers: {
"Content-Type": "multipart/form-data",
},
});
/**
* Set Access Token
*/
export const setAccessToken = (token) => {
if (token) {
localStorage.setItem("access_token", token); // Store token in localStorage
axiosInstance.defaults.headers["Authorization"] = `Bearer ${token}`;
apiForFiles.defaults.headers["Authorization"] = `Bearer ${token}`;
} else {
localStorage.removeItem("access_token");
delete axiosInstance.defaults.headers["Authorization"];
delete apiForFiles.defaults.headers["Authorization"];
}
};
/**
* Add a request interceptor to include the authorization token
* in the request headers if it exists in localStorage.
*/
const addAuthInterceptor = (instance) => {
instance.interceptors.request.use(
(config) => {
const token = localStorage.getItem("access_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
};
/**
* Add a response interceptor to handle global error scenarios,
* such as redirecting to the login page on a 401 Unauthorized error.
*/
const addErrorInterceptor = (instance) => {
instance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response && error.response.status === 401) {
console.error("Unauthorized access - logging out...");
localStorage.removeItem("access_token");
// window.location.href = "/";
navigate("/");
} else if (error.response && error.response.status === 403) {
window.location.href = "/";
// navigate("/");
} else if (error.response && error.response.status === 404) {
console.error("404 Error - Endpoint not found:", error.config?.url);
// Don't redirect for 404, let component handle it
} else if (error.response && error.response.status >= 500) {
console.error("Server error:", error.response?.data);
}
return Promise.reject(error);
}
);
};
// Apply interceptors to both instances
addAuthInterceptor(axiosInstance);
addAuthInterceptor(apiForFiles);
addErrorInterceptor(axiosInstance);
addErrorInterceptor(apiForFiles);
/**
* Clear all user data from the browser: localStorage, sessionStorage, and cookies.
*/
export const clearUserData = () => {
try {
// Clear localStorage
localStorage.clear();
// Clear sessionStorage
sessionStorage.clear();
// Clear cookies
document.cookie.split(";").forEach((cookie) => {
const [name] = cookie.split("=");
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/`;
});
// Remove authorization headers from Axios instances
delete axiosInstance.defaults.headers["Authorization"];
delete apiForFiles.defaults.headers["Authorization"];
console.log("User data cleared from browser.");
// Add redirect to ensure all tabs show login page
// window.location.href = '/';
} catch (error) {
console.error("Error clearing user data:", error);
}
};
export const urlToFile = async (url, filename = "file") => {
try {
// Use your axios instance to request the URL as a Blob
const response = await apiForFiles.get(url, {
responseType: "blob",
});
// Axios header keys are lowercase
const contentType =
response.headers["content-type"] ||
"*"(
// Guess MIME type based on filename extension
filename.toLowerCase().endsWith(".png")
? "image/png"
: filename.toLowerCase().endsWith(".webp")
? "image/webp"
: filename.toLowerCase().endsWith(".jpg") ||
filename.toLowerCase().endsWith(".jpeg")
? "image/jpeg"
: "application/octet-stream"
);
// Create and return a File object from the blob data
return new File([response.data], filename, { type: contentType });
} catch (error) {
console.error("urlToFile axios error:", error);
return null;
}
};
/**
* Get FCM token from localStorage
*/
const getFcmToken = () => {
return localStorage.getItem("fcm_token");
};
/**
* Clear FCM token from localStorage
*/
const clearFcmToken = () => {
localStorage.removeItem("fcm_token");
};
export const logoutAPI = async () => {
console.log("Calling logout API...");
try {
const res = await axiosInstance.post(API_ENDPOINTS.LOGOUT);
return res.data; // assuming API returns { message: "Logout successful" }
} catch (error) {
console.error("Logout API failed:", error);
// even if API fails, still clear local storage
} finally {
console.log("Clearing local storage...");
// always clear local storage
localStorage.removeItem("access_token");
// clearFcmToken();
}
};
// Export both instances
export default axiosInstance;
export { apiForFiles };

70
src/styles/HeroSlider.css Normal file
View File

@ -0,0 +1,70 @@
.hero-swiper {
width: 100%;
height: 100%;
}
.hero-wrapper{
background-image: url("../assets/images/greenbg2.jpg");
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
.hero-slide {
display: flex;
align-items: center;
justify-content: space-between;
padding: 60px;
/* background: #111; */
color: #fff;
min-height: 480px;
width: 100%;
max-width: 1400px;
margin: 0 auto;
}
.hero-image img {
width: 100%;
max-width: 420px;
border-radius: 12px;
}
.hero-content {
max-width: 500px;
}
.hero-content h2 {
font-size: 32px;
margin-bottom: 15px;
}
.hero-content p {
font-size: 16px;
line-height: 1.6;
margin-bottom: 20px;
opacity: 0.8;
}
.hero-content button {
background: #ffcc00;
color: #000;
border: none;
padding: 12px 24px;
font-weight: bold;
cursor: pointer;
border-radius: 6px;
}
/* Responsive */
@media (max-width: 768px) {
.hero-slide {
flex-direction: column;
text-align: center;
padding: 30px;
}
.hero-image img {
max-width: 100%;
margin-bottom: 20px;
}
}

View File

@ -0,0 +1,108 @@
// ErrorBoundary.js - Error boundary component for graceful error handling
import { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log the error details
console.error("ErrorBoundary caught an error:", error, errorInfo);
this.setState({
error: error,
errorInfo: errorInfo,
});
}
render() {
if (this.state.hasError) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="max-w-md w-full bg-white shadow-lg rounded-lg p-6">
<div className="flex items-center mb-4">
<div className="bg-red-100 rounded-full p-2">
<svg
className="w-6 h-6 text-red-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
<h2 className="ml-3 text-lg font-medium text-gray-900">
Something went wrong
</h2>
</div>
<p className="text-gray-600 mb-4">
There was an error with the application. Please try refreshing the
page.
</p>
{/* Show error details in development */}
{process.env.NODE_ENV === "development" && this.state.error && (
<details className="mb-4 text-sm text-gray-500">
<summary className="cursor-pointer font-medium">
Error Details (Development)
</summary>
<div className="mt-2 p-2 bg-gray-100 rounded text-xs overflow-auto">
<strong>Error:</strong> {this.state.error.toString()}
<br />
<strong>Stack:</strong>
<pre className="whitespace-pre-wrap mt-1">
{this.state.errorInfo.componentStack}
</pre>
</div>
</details>
)}
<div className="flex space-x-3">
<button
onClick={() => window.location.reload()}
className="flex-1 bg-blue-600 text-white py-2 px-4 rounded hover:bg-blue-700 transition-colors"
>
Refresh Page
</button>
<button
onClick={() => {
this.setState({
hasError: false,
error: null,
errorInfo: null,
});
}}
className="flex-1 bg-gray-600 text-white py-2 px-4 rounded hover:bg-gray-700 transition-colors"
>
Try Again
</button>
</div>
<div className="mt-4 text-center">
<a href="/" className="text-sm text-blue-600 hover:text-blue-500">
Go to Home Page
</a>
</div>
</div>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;

3
src/utills/auth.js Normal file
View File

@ -0,0 +1,3 @@
export const isAuthenticated = () => {
return !!localStorage.getItem("token");
};