diff --git a/package-lock.json b/package-lock.json index 1fdf00c..d38d8ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,12 @@ "name": "thirukalyanam", "version": "0.0.0", "dependencies": { - "@date-io/date-fns": "^3.2.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@files-ui/react": "^1.2.5", - "@lottiefiles/dotlottie-react": "^0.17.8", "@mui/icons-material": "^7.3.5", "@mui/lab": "^7.0.1-beta.19", "@mui/material": "^7.3.5", - "@mui/styled-engine-sc": "^7.3.5", "@mui/x-date-pickers": "^8.19.0", "@reduxjs/toolkit": "^2.11.0", "@tailwindcss/vite": "^4.1.17", @@ -34,14 +31,11 @@ "react-lazy-load-image-component": "^1.6.3", "react-redux": "^9.2.0", "react-router-dom": "^7.9.6", - "styled-components": "^6.1.19", "swiper": "^12.0.3", "tailwindcss": "^4.1.17" }, "devDependencies": { "@eslint/js": "^9.39.1", - "@types/react": "^19.2.2", - "@types/react-dom": "^19.2.2", "@vitejs/plugin-react": "^5.1.0", "eslint": "^9.39.1", "eslint-plugin-react-hooks": "^7.0.1", @@ -92,6 +86,7 @@ "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", @@ -343,29 +338,6 @@ "node": ">=6.9.0" } }, - "node_modules/@date-io/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@date-io/core/-/core-3.2.0.tgz", - "integrity": "sha512-hqwXvY8/YBsT9RwQITG868ZNb1MVFFkF7W1Ecv4P472j/ZWa7EFcgSmxy8PUElNVZfvhdvfv+a8j6NWJqOX5mA==", - "license": "MIT" - }, - "node_modules/@date-io/date-fns": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-3.2.1.tgz", - "integrity": "sha512-CtXgTOAamkImI+CmbWRNdBi4ljj9xm/tdoPa+eeeiygduzubJTsXp18vYz+Vs/9yLho1zUOXlxpsfsF7PsXSWQ==", - "license": "MIT", - "dependencies": { - "@date-io/core": "^3.2.0" - }, - "peerDependencies": { - "date-fns": "^3.2.0 || ^4.1.0" - }, - "peerDependenciesMeta": { - "date-fns": { - "optional": true - } - } - }, "node_modules/@dimforge/rapier3d-compat": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", @@ -452,6 +424,7 @@ "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,6 +468,7 @@ "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", @@ -1197,6 +1171,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.9.tgz", "integrity": "sha512-3gtUX0e584MYkKBQMgSECMvE1Dwzg+eONefDQ0wxVSe5YMBsZwdN5pL7UapwWBlV8+i8QCztF9TP947tEjZAGA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/component": "0.7.1", "@firebase/logger": "0.5.0", @@ -1263,6 +1238,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.9.tgz", "integrity": "sha512-e5LzqjO69/N2z7XcJeuMzIp4wWnW696dQeaHAUpQvGk89gIWHAIvG6W+mA3UotGW6jBoqdppEJ9DnuwbcBByug==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/app": "0.14.9", "@firebase/component": "0.7.1", @@ -1278,7 +1254,8 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@firebase/auth-compat": { "version": "0.6.3", @@ -1735,6 +1712,7 @@ "integrity": "sha512-/gnejm7MKkVIXnSJGpc9L2CvvvzJvtDPeAEq5jAwgVlf/PeNxot+THx/bpD20wQ8uL5sz0xqgXy1nisOYMU+mw==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" }, @@ -1886,24 +1864,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@lottiefiles/dotlottie-react": { - "version": "0.17.8", - "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-react/-/dotlottie-react-0.17.8.tgz", - "integrity": "sha512-Hk0bISNURSqL7t+H7S5lW2NQVa1hiibnqRRg6kOWZpswBxfQk+/6WBPc9EfuetdoZmiMoDsmcI0HR4I20oTBRg==", - "license": "MIT", - "dependencies": { - "@lottiefiles/dotlottie-web": "0.57.0" - }, - "peerDependencies": { - "react": "^17 || ^18 || ^19" - } - }, - "node_modules/@lottiefiles/dotlottie-web": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-web/-/dotlottie-web-0.57.0.tgz", - "integrity": "sha512-gcgvu9T21YzeY3JjHCZrxftucsxzMH6e9h+8NMv8mbfo1y1M9/jdcsdu40S+pnSLz9/OyiSBQ/EjDsbSOHZy0w==", - "license": "MIT" - }, "node_modules/@mediapipe/tasks-vision": { "version": "0.10.17", "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", @@ -2024,6 +1984,7 @@ "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", @@ -2129,34 +2090,12 @@ } } }, - "node_modules/@mui/styled-engine-sc": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-7.3.5.tgz", - "integrity": "sha512-tm2KcMF9Y4vhi38ITxhTkeGhux/sCB+AuBz2AyjXKOxuZ9iSUsixAKvzeH/HGbQaih8qVF3ocbq95PQZ/bd/gQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.28.4", - "@types/hoist-non-react-statics": "^3.3.7", - "csstype": "^3.1.3", - "hoist-non-react-statics": "^3.3.2", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "styled-components": "^6.0.0" - } - }, "node_modules/@mui/system": { "version": "7.3.5", "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", @@ -3113,7 +3052,8 @@ } ], "hasInstallScript": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@tsparticles/interaction-external-attract": { "version": "3.9.1", @@ -3731,20 +3671,11 @@ "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" } }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, "node_modules/@types/react-reconciler": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", @@ -3780,6 +3711,7 @@ "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", @@ -4052,6 +3984,7 @@ "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" }, @@ -4336,6 +4269,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -4767,7 +4701,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/d3-array": { "version": "3.2.4", @@ -4895,6 +4830,7 @@ "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" @@ -5009,7 +4945,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -5192,6 +5129,7 @@ "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", @@ -6925,6 +6863,7 @@ "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", @@ -7007,6 +6946,7 @@ "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" @@ -7614,6 +7554,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -7722,6 +7663,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -7998,6 +7940,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -8007,6 +7950,7 @@ "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" }, @@ -8104,6 +8048,7 @@ "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" @@ -8330,7 +8275,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -8569,6 +8515,7 @@ "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", @@ -8789,89 +8736,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/styled-components": { - "version": "6.1.19", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", - "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", - "license": "MIT", - "dependencies": { - "@emotion/is-prop-valid": "1.2.2", - "@emotion/unitless": "0.8.1", - "@types/stylis": "4.2.5", - "css-to-react-native": "3.2.0", - "csstype": "3.1.3", - "postcss": "8.4.49", - "shallowequal": "1.1.0", - "stylis": "4.3.2", - "tslib": "2.6.2" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0" - } - }, - "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", - "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", - "license": "MIT", - "dependencies": { - "@emotion/memoize": "^0.8.1" - } - }, - "node_modules/styled-components/node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", - "license": "MIT" - }, - "node_modules/styled-components/node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", - "license": "MIT" - }, - "node_modules/styled-components/node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/styled-components/node_modules/stylis": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", - "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", - "license": "MIT" - }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -9336,6 +9200,7 @@ "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", @@ -9488,6 +9353,7 @@ "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", @@ -9726,6 +9592,7 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index b92c790..1345bf1 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,12 @@ "preview": "vite preview" }, "dependencies": { - "@date-io/date-fns": "^3.2.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@files-ui/react": "^1.2.5", - "@lottiefiles/dotlottie-react": "^0.17.8", "@mui/icons-material": "^7.3.5", "@mui/lab": "^7.0.1-beta.19", "@mui/material": "^7.3.5", - "@mui/styled-engine-sc": "^7.3.5", "@mui/x-date-pickers": "^8.19.0", "@reduxjs/toolkit": "^2.11.0", "@tailwindcss/vite": "^4.1.17", @@ -36,14 +33,11 @@ "react-lazy-load-image-component": "^1.6.3", "react-redux": "^9.2.0", "react-router-dom": "^7.9.6", - "styled-components": "^6.1.19", "swiper": "^12.0.3", "tailwindcss": "^4.1.17" }, "devDependencies": { "@eslint/js": "^9.39.1", - "@types/react": "^19.2.2", - "@types/react-dom": "^19.2.2", "@vitejs/plugin-react": "^5.1.0", "eslint": "^9.39.1", "eslint-plugin-react-hooks": "^7.0.1", diff --git a/src/App.jsx b/src/App.jsx index 8f4099e..0d66047 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,8 +7,18 @@ import { generateToken, listenToMessages } from "./notifications/firebase"; function App() { useEffect(()=>{ - generateToken(); - listenToMessages(); // foreground notifications + const run = () => { + generateToken(); + listenToMessages(); // foreground notifications + }; + + if (typeof window !== "undefined" && "requestIdleCallback" in window) { + const handle = window.requestIdleCallback(run); + return () => window.cancelIdleCallback(handle); + } + + const timeout = setTimeout(run, 800); + return () => clearTimeout(timeout); },[]); return ( diff --git a/src/api/apiEndpoints.js b/src/api/apiEndpoints.js index 0c88e5b..b31f80e 100644 --- a/src/api/apiEndpoints.js +++ b/src/api/apiEndpoints.js @@ -24,5 +24,7 @@ REGISTER_STEP2:"update_educational_details", // educational details updated ap REGSITER_STEP3:"update_family_details", // family details updated api REGISTER_STEP4:"update_lifestyle_details", // lifestyle details updated api REGISTER_STEP5:"update_preferred_details", // partner preference details updated api +PREVIEW_DETAILS: "get_preview_details", +REVIEWS: "reviews", }; diff --git a/src/api/masters.api.js b/src/api/masters.api.js index 6b8926a..c7ea4a6 100644 --- a/src/api/masters.api.js +++ b/src/api/masters.api.js @@ -21,9 +21,10 @@ export const getSubCasteMasters = async (caste_id) => { }; export const getCityMasters = async (state_id) => { - const res = await axiosInstance.get(API_ENDPOINTS.CITY_MASTER, { - params: { state_id }, - }); + const params = Array.isArray(state_id) + ? { state_id: `[${state_id.join(",")}]` } + : { state_id }; + const res = await axiosInstance.get(API_ENDPOINTS.CITY_MASTER, { params }); return res.data; }; @@ -39,6 +40,13 @@ export const getEducationMasters = async () => { return res.data; }; +export const getEducationList = async (study_field_id) => { + const res = await axiosInstance.get(API_ENDPOINTS.EDUCATION_LIST_API, { + params: { study_field_id }, + }); + return res.data; +}; + export const getFamilyMasters = async () => { const res = await axiosInstance.get(API_ENDPOINTS.FAMILY_DETAILS_MASTER); return res.data; diff --git a/src/api/preview.api.js b/src/api/preview.api.js new file mode 100644 index 0000000..64c71b9 --- /dev/null +++ b/src/api/preview.api.js @@ -0,0 +1,7 @@ +import axiosInstance from "./axiosInstance"; +import { API_ENDPOINTS } from "./apiEndpoints"; + +export const getPreviewDetails = async () => { + const res = await axiosInstance.get(API_ENDPOINTS.PREVIEW_DETAILS); + return res.data; +}; diff --git a/src/api/register.api.js b/src/api/register.api.js index 223b1c1..c4f9e86 100644 --- a/src/api/register.api.js +++ b/src/api/register.api.js @@ -31,4 +31,12 @@ export const registerStep3API = async (payload) => { export const registerStep4API = async (payload) => { const res = await axiosInstance.post(API_ENDPOINTS.REGISTER_STEP4, payload); return res.data; -}; \ No newline at end of file +}; + +/** + * STEP 5 – Partner Preferences + */ +export const registerStep5API = async (payload) => { + const res = await axiosInstance.post(API_ENDPOINTS.REGISTER_STEP5, payload); + return res.data; +}; diff --git a/src/api/reviews.api.js b/src/api/reviews.api.js new file mode 100644 index 0000000..d62f0e5 --- /dev/null +++ b/src/api/reviews.api.js @@ -0,0 +1,7 @@ +import axiosInstance from "./axiosInstance"; +import { API_ENDPOINTS } from "./apiEndpoints"; + +export const getReviews = async () => { + const res = await axiosInstance.get(API_ENDPOINTS.REVIEWS); + return res.data; +}; diff --git a/src/api/terms.api.js b/src/api/terms.api.js new file mode 100644 index 0000000..1751ba8 --- /dev/null +++ b/src/api/terms.api.js @@ -0,0 +1,9 @@ +import axiosInstance from "./axiosInstance"; +import { API_ENDPOINTS } from "./apiEndpoints"; + +export const getTermsAndPolicies = async (type) => { + const res = await axiosInstance.get(API_ENDPOINTS.TERMS_AND_POLICIES_PRIVACY, { + params: { type }, + }); + return res.data; +}; diff --git a/src/components/common/ProfileCard.jsx b/src/components/common/ProfileCard.jsx index ec85c27..76f4d5e 100644 --- a/src/components/common/ProfileCard.jsx +++ b/src/components/common/ProfileCard.jsx @@ -1,158 +1,23 @@ -import React, { useState } from "react"; -import { Users, Grid3x3, Heart, Crown, Bookmark } from "lucide-react"; -import LazyImage from "./LazyImage"; -import CakeIcon from "@mui/icons-material/Cake"; -import HeightIcon from "@mui/icons-material/Height"; -import GroupsIcon from "@mui/icons-material/Groups"; -import TempleHinduIcon from "@mui/icons-material/TempleHindu"; -import SchoolIcon from "@mui/icons-material/School"; -import LocationOnIcon from "@mui/icons-material/LocationOn"; -import AccessibilityNewIcon from "@mui/icons-material/AccessibilityNew"; -import { motion } from 'framer-motion'; +import React from "react"; +import ProfileCardItem from "../profiledashboard/ProfileCardItem"; export default function ProfileCard() { - const [isLiked, setIsLiked] = useState(false); + const profile = { + id: 1, + name: "Jerome Bell", + userId: "JB2847593", + age: 22, + height: "5.2", + religion: "Hindu / Agamudiyar/thular", + education: "BCA / Data analyst", + location: "Chennai", + image: + "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=600&h=800&fit=crop&crop=faces,top", + isPremium: true, + }; return ( -
-
- {/* Profile Image Section */} -
- - {/* Premium Badge */} - - - - - - - {/* Shortlist Button */} - - - Shortlist - - - - Profile - - {/* */} - - {/* White Gradient Overlay at bottom of image */} -
- - {/* Profile Info Overlay - positioned at bottom */} -
-

- Jerome bell -

-

- Matrimony ID: JB2847593 -

-
-
- - {/* Stats and Follow Section */} -
-
-
- - - Age : 22 - -
- -
- - - Height: 5.2 - -
-
- -
-
- - - Hindu / Agamudiyar/thular - -
-
- -
-
- - - BCA / Data analyst - -
-
- -
-
- - - Chennai - -
-
- - {/* Action Buttons */} -
- - - - -
-
-
+
+
); } diff --git a/src/components/common/Skeleton.jsx b/src/components/common/Skeleton.jsx new file mode 100644 index 0000000..614a7d8 --- /dev/null +++ b/src/components/common/Skeleton.jsx @@ -0,0 +1,72 @@ +import React, { useEffect } from "react"; + +const STYLE_ID = "skeleton-shimmer-styles"; + +const injectSkeletonStyles = () => { + if (typeof document === "undefined") return; + if (document.getElementById(STYLE_ID)) return; + const style = document.createElement("style"); + style.id = STYLE_ID; + style.textContent = ` + .skeleton-shimmer { + position: relative; + overflow: hidden; + background: #e5e7eb; + } + .skeleton-shimmer::after { + content: ""; + position: absolute; + inset: 0; + transform: translateX(-100%); + background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,0) 100%); + animation: skeleton-shimmer 1.6s infinite; + } + @keyframes skeleton-shimmer { + 100% { transform: translateX(100%); } + } + `; + document.head.appendChild(style); +}; + +export const Skeleton = ({ + width = "100%", + height = 12, + rounded = 6, + className = "", +}) => { + useEffect(() => { + injectSkeletonStyles(); + }, []); + + return ( +
+ ); +}; + +export const SkeletonText = ({ + lines = 3, + gap = 10, + height = 12, + className = "", +}) => { + useEffect(() => { + injectSkeletonStyles(); + }, []); + + return ( +
+ {Array.from({ length: lines }).map((_, idx) => ( + + ))} +
+ ); +}; + +export default Skeleton; diff --git a/src/components/common/Threemarquee.jsx b/src/components/common/Threemarquee.jsx index 7432bfc..e7e801a 100644 --- a/src/components/common/Threemarquee.jsx +++ b/src/components/common/Threemarquee.jsx @@ -1,64 +1,39 @@ import ThreeDScrollTriggerRow, { ThreeDScrollTriggerContainer, } from "../lightswind/ThreeDScrollTrigger"; -import React, { useState } from "react"; - -const reviews = [ - { - name: "Aria Thompson", - company: "CreativePixel Studio", - image: - "https://images.unsplash.com/photo-1517841905240-472988babdf9?auto=format&fit=facearea&w=96&h=96&facepad=2", - review: - "Lightswind UI has completely changed how we design modern interfaces. Every component feels elegant, responsive, and intuitive.", - }, - { - name: "Ethan Rivera", - company: "CodeLoom Technologies", - image: - "https://images.unsplash.com/photo-1465101162946-4377e57745c3?auto=format&fit=facearea&w=96&h=96&facepad=2", - review: - "The customization options in Lightswind UI are unmatched. We built an entire SaaS dashboard in days instead of weeks.", - }, - { - name: "Liam Patel", - company: "NextGen Interfaces", - image: - "https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?auto=format&fit=facearea&w=96&h=96&facepad=2", - review: - "From landing pages to complex dashboards, Lightswind UI makes building visually consistent UIs effortless and fun.", - }, - { - name: "Sarah Mitchell", - company: "DesignFlow Co", - image: - "https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=facearea&w=96&h=96&facepad=2", - review: - "The component library is extensive and well-documented. Saved us months of development time.", - }, - { - name: "James Chen", - company: "TechVision Labs", - image: - "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=facearea&w=96&h=96&facepad=2", - review: - "Outstanding support and continuous updates. Lightswind UI keeps getting better every release.", - }, - { - name: "Emma Davis", - company: "PixelPerfect Studios", - image: - "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=facearea&w=96&h=96&facepad=2", - review: - "Responsive by default and looks amazing on all devices. This is exactly what we needed.", - }, -]; +import React, { memo, useCallback, useMemo, useState } from "react"; +import { useReviews } from "../../hooks/useReviews"; +import { Skeleton } from "./Skeleton"; export default function ThreeScrollTrigger() { - // Split reviews into 2 rows with 3 cards each - const row1 = reviews.slice(0, 3); - const row2 = reviews.slice(3, 6); + const { data, isLoading } = useReviews(); const [paused, setPaused] = useState(false); + const handlePause = useCallback(() => setPaused(true), []); + const handleResume = useCallback(() => setPaused(false), []); + + const reviews = useMemo(() => { + const list = data?.data || []; + if (!Array.isArray(list)) return []; + return list.map((item) => ({ + name: item.name, + company: item.about, + image: item.profile_image, + review: item.content, + rating: item.rating, + })); + }, [data]); + + const row1 = useMemo(() => reviews.slice(0, 3), [reviews]); + const row2 = useMemo(() => reviews.slice(3, 6), [reviews]); + const row3 = useMemo(() => reviews.slice(6, 9), [reviews]); + + if (!isLoading && reviews.length === 0) { + return ( +
+ No reviews available. +
+ ); + } return (
@@ -66,44 +41,75 @@ export default function ThreeScrollTrigger() { {/* Row 1 - 3 Cards scrolling right */}
- {row1.map((rev, idx) => ( - setPaused(true)} - onMouseLeave={() => setPaused(false)} - /> - ))} + {isLoading + ? Array.from({ length: 3 }).map((_, idx) => ( + + )) + : row1.map((rev, idx) => ( + + ))}
{/* Row 2 - 3 Cards scrolling left */}
- {row2.map((rev, idx) => ( - setPaused(true)} - onMouseLeave={() => setPaused(false)} - /> - ))} + {isLoading + ? Array.from({ length: 3 }).map((_, idx) => ( + + )) + : row2.map((rev, idx) => ( + + ))}
+ + {row3.length > 0 && ( + +
+ {row3.map((rev, idx) => ( + + ))} +
+
+ )}
); } // Card component for clarity and reuse -function ReviewCard({ +const ReviewCard = memo(function ReviewCard({ name, company, image, review, + rating, onMouseEnter, onMouseLeave, }) { + const stars = useMemo(() => { + if (!rating) return null; + return Array.from({ length: 5 }, (_, i) => ( + {i < rating ? "★" : "☆"} + )); + }, [rating]); + return (
- {name} + {image ? ( + {name} + ) : ( +
+ )}
{name}
{company}
+ {stars &&
{stars}
}
@@ -127,4 +138,21 @@ function ReviewCard({
); -} \ No newline at end of file +}); + +function ReviewSkeleton() { + return ( +
+
+ +
+ + +
+
+ + + +
+ ); +} diff --git a/src/components/profiledashboard/DailyRecommendedCard.jsx b/src/components/profiledashboard/DailyRecommendedCard.jsx index 1342d16..0670c7e 100644 --- a/src/components/profiledashboard/DailyRecommendedCard.jsx +++ b/src/components/profiledashboard/DailyRecommendedCard.jsx @@ -103,66 +103,53 @@ const DailyRecommendedCard = () => { } ]; - // Profile Card Component - - -const ProfileCard = ({ profile }) => { + const ProfileCard = ({ profile }) => { const [isLiked, setIsLiked] = useState(false); - const navigate = useNavigate(); + return ( - - navigate(`/profile-details/${profile.id}`)} - -className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-1 border-green-200"> - {/* Profile Image Section */} + transition={{ duration: 0.5 }} + onClick={() => navigate(`/profile-details/${profile.id}`)} + className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-1 border-green-200" + >
+ {profile.isPremium && ( + + + + )} - {/* Premium Badge */} - {profile.isPremium && ( - - - - )} + { + e.stopPropagation(); + }} + > + + Shortlist + - {/* Shortlist Button */} - { - e.stopPropagation(); - // shortlist logic - }} - > - - Shortlist - +
+ {profile.name} +
-
- {profile.name} -
- {/* */} - - {/* White Gradient Overlay at bottom of image */}

- {profile.name} + {profile.name}

- Matrimony ID: {profile.userId} + Matrimony ID: {profile.userId}

- {/* Stats and Follow Section */}
- + - Age : {profile.age} + Age : {profile.age}
- + - Height: {profile.height} + Height: {profile.height}
- + - {profile.religion} + {profile.religion}
- + {profile.education}
-
+
- + - {profile.location} + {profile.location}
- {/* Action Buttons */} -
- - - + + -
- + }} + > + {isLiked ? ( + + + + ) : ( + + + + )} + Interest + +
- ); }; - - return (
@@ -405,4 +404,4 @@ className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-1 bor ); }; -export default DailyRecommendedCard; \ No newline at end of file +export default DailyRecommendedCard; diff --git a/src/components/profiledashboard/NewJoinedProfile.jsx b/src/components/profiledashboard/NewJoinedProfile.jsx index 0f999da..0ee680c 100644 --- a/src/components/profiledashboard/NewJoinedProfile.jsx +++ b/src/components/profiledashboard/NewJoinedProfile.jsx @@ -16,11 +16,13 @@ import 'swiper/css'; import 'swiper/css/navigation'; import 'swiper/css/pagination'; import 'swiper/css/effect-coverflow'; +import { useNavigate } from 'react-router-dom'; const NewJoinedProfile = () => { const swiperRef = useRef(null); + const navigate = useNavigate(); // Sample profile data const profiles = [ @@ -111,123 +113,173 @@ const ProfileCard = ({ profile }) => { const [isLiked, setIsLiked] = useState(false); return ( - - - {/* Profile Image Section */} -
- - {/* Premium Badge */} - {profile.isPremium && ( - - - - )} - - {/* Shortlist Button */} - navigate(`/profile-details/${profile.id}`)} + className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-1 border-green-200" > - - Shortlist - +
+ {profile.isPremium && ( + + + + )} + { + e.stopPropagation(); + }} + > + + Shortlist + - {profile.name} - - {/* */} - - {/* White Gradient Overlay at bottom of image */}
+ {profile.name} +
+ +
- {/* Profile Info Overlay - positioned at bottom */} -
+

- {profile.name} + {profile.name}

- Matrimony ID: {profile.userId} + Matrimony ID: {profile.userId}

- {/* Stats and Follow Section */}
- + - Age : {profile.age} + Age : {profile.age}
- + - Height: {profile.height} + Height: {profile.height}
- + - {profile.religion} + {profile.religion}
- + {profile.education}
-
+
- + - {profile.location} + {profile.location}
- +
+ + + +
@@ -365,4 +417,4 @@ className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-2 bor ) } -export default NewJoinedProfile \ No newline at end of file +export default NewJoinedProfile diff --git a/src/components/profiledashboard/ProfileCardItem.jsx b/src/components/profiledashboard/ProfileCardItem.jsx new file mode 100644 index 0000000..9aa231c --- /dev/null +++ b/src/components/profiledashboard/ProfileCardItem.jsx @@ -0,0 +1,235 @@ +import { useState } from "react"; +import { motion } from "framer-motion"; +import { Crown, Bookmark } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import CakeIcon from "@mui/icons-material/Cake"; +import AccessibilityNewIcon from "@mui/icons-material/AccessibilityNew"; +import GroupsIcon from "@mui/icons-material/Groups"; +import SchoolIcon from "@mui/icons-material/School"; +import LocationOnIcon from "@mui/icons-material/LocationOn"; + +const buildDefaultRows = (profile) => [ + [ + { + icon: , + text: `Age: ${profile?.age ?? "-"}`, + }, + { + icon: , + text: `Height: ${profile?.height ?? "-"}`, + }, + ], + [ + { + icon: , + text: + profile?.religion || + profile?.caste || + profile?.community || + "-", + }, + ], + [ + { + icon: , + text: profile?.education || profile?.qualification || "-", + }, + ], + [ + { + icon: , + text: profile?.location || "-", + }, + ], +]; + +const getProfileIdText = (profile) => + profile?.userId || + profile?.idNumber || + profile?.matrimonyId || + profile?.id || + "-"; + +const ProfileCardItem = ({ + profile, + metaRows, + showActions = true, + showShortlist = true, + shortlistLabel = "Shortlist", + declineLabel = "Decline", + interestLabel = "Interest", + onDecline, + onInterest, + onShortlist, + onCardClick, + detailsPath, + className = "", +}) => { + const [isLiked, setIsLiked] = useState(false); + const navigate = useNavigate(); + const rows = metaRows?.length ? metaRows : buildDefaultRows(profile); + + const handleCardClick = () => { + if (onCardClick) { + onCardClick(profile); + return; + } + const target = detailsPath || `/profile-details/${profile?.id ?? ""}`; + if (target) { + navigate(target); + } + }; + + return ( + +
+ {profile?.isPremium && ( + + + + )} + + {showShortlist && ( + { + e.stopPropagation(); + onShortlist?.(profile); + }} + > + + {shortlistLabel} + + )} + +
+ {profile?.name +
+ +
+ +
+

+ {profile?.name || "-"} +

+

+ Matrimony ID: {getProfileIdText(profile)} +

+
+
+ +
+ {rows.map((row, rowIndex) => ( +
+ {row.map((item, itemIndex) => ( +
+ {item.icon} + + {item.text} + +
+ ))} +
+ ))} + + {showActions && ( +
+ + + +
+ )} +
+
+ ); +}; + +export default ProfileCardItem; diff --git a/src/components/ui/ProfileCardDemo.jsx b/src/components/ui/ProfileCardDemo.jsx index d5f71bf..69c272b 100644 --- a/src/components/ui/ProfileCardDemo.jsx +++ b/src/components/ui/ProfileCardDemo.jsx @@ -1,11 +1,17 @@ import React from "react"; -import { Heart, X, Crown, Bookmark, Eye } 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"; import { motion } from "framer-motion"; +import ProfileCardItem from "../profiledashboard/ProfileCardItem"; +import CakeIcon from "@mui/icons-material/Cake"; +import AccessibilityNewIcon from "@mui/icons-material/AccessibilityNew"; +import AccountBalanceWalletIcon from "@mui/icons-material/AccountBalanceWallet"; +import LocationOnIcon from "@mui/icons-material/LocationOn"; +import GroupsIcon from "@mui/icons-material/Groups"; +import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome"; export default function ProfileCard() { @@ -69,96 +75,75 @@ export default function ProfileCard() { }, ]; - return ( -
+ const buildProfileRows = (profile) => [ + [ + { + icon: , + text: profile?.age || "-", + }, + { + icon: , + text: profile?.height || "-", + }, + ], + [ + { + icon: , + text: profile?.salary ? `${profile.salary} LPA` : "-", + }, + { + icon: , + text: profile?.location || "-", + }, + ], + [ + { + icon: , + text: profile?.caste || "-", + }, + { + icon: , + text: profile?.zodiac1 || "-", + }, + ], + [ + { + icon: , + text: profile?.zodiac2 || "-", + }, + ], + ]; - {/* HEADING */} - -

- Daily Recommended -

-

- Find your perfect match today -

-
+ return ( +
+ {/* HEADING */} + +

+ Daily Recommended +

+

+ Find your perfect match today +

+
- {/* CARDS GRID */} -
-
- {profiles.map((profile) => ( -
- {/* IMAGE SECTION */} -
- profile - -
- -
- -
- Shortlist -
-
- - {/* CONTENT */} -
-

- {profile.name} -

- -
-

ID: {profile.idNumber}

-

- {profile.lastSeen} -

-
- -
- {[ - profile.age, - profile.height, - profile.salary + " LPA", - profile.location, - profile.caste, - profile.zodiac1, - profile.zodiac2, - ].map((v, i) => ( - - {v} - - ))} -
- -
- - - -
-
-
- ))} + {/* CARDS GRID */} +
+
+ {profiles.map((profile) => ( + + ))} +
-
-); + ); -} \ No newline at end of file +} diff --git a/src/feature/EducationalDetailsForm.jsx b/src/feature/EducationalDetailsForm.jsx index 700cba9..081ca5a 100644 --- a/src/feature/EducationalDetailsForm.jsx +++ b/src/feature/EducationalDetailsForm.jsx @@ -1,19 +1,102 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useMemo, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import { updateEducationalDetails } from "../redux/registrationFormSlice"; -import { TextField, Button, Grid } from "@mui/material"; +import { + TextField, + Button, + Grid, + FormControl, + InputLabel, + Select, + MenuItem, +} from "@mui/material"; +import { useEducationMasters, useEducationList } from "../hooks/useMasters"; -const EducationalDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => { +const EducationalDetailsForm = ({ + onSubmitStep, + onSkipStep, + errors, + onFieldChange, +}) => { const dispatch = useDispatch(); const data = useSelector((state) => state.registerform.educationalDetails); const inputRef = useRef(null); + const requiredMark = *; + + const { data: educationMasters, isLoading: isEducationMastersLoading } = + useEducationMasters(); + const educationListQuery = useEducationList(data.fieldOfStudy); + + const studyFieldOptions = useMemo(() => { + const raw = educationMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.studyFields || raw.study_fields || raw.fieldOfStudy || []; + }, [educationMasters]); + + const qualificationOptions = useMemo(() => { + const raw = educationListQuery.data; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.education || raw.data || []; + }, [educationListQuery.data]); + + const occupationOptions = useMemo(() => { + const raw = educationMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.occupation || raw.occupations || []; + }, [educationMasters]); + + const employeeTypeOptions = useMemo(() => { + const raw = educationMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.employeeType || raw.employee_type || []; + }, [educationMasters]); + + const annualIncomeOptions = useMemo(() => { + const raw = educationMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.annualIncome || raw.annual_income || []; + }, [educationMasters]); + + const workLocationOptions = useMemo(() => { + const raw = educationMasters; + if (!raw) return []; + if (Array.isArray(raw)) return []; + return raw.workLocation || raw.work_location || raw.workLocations || []; + }, [educationMasters]); + + const getOptionLabel = (item, fallback = "") => { + if (!item) return fallback; + if (typeof item === "string") return item; + return ( + item.study_field_name || + item.education_name || + item.occupation_name || + item.employee_type_name || + item.annual_income_name || + item.work_location_name || + item.name || + fallback + ); + }; useEffect(() => { inputRef.current?.focus(); }, []); const handleChange = (field, value) => { - dispatch(updateEducationalDetails({ [field]: value })); + const updates = { [field]: value }; + const fieldsToClear = [field]; + if (field === "fieldOfStudy") { + updates.qualification = ""; + fieldsToClear.push("qualification"); + } + dispatch(updateEducationalDetails(updates)); + if (onFieldChange) onFieldChange(fieldsToClear); }; const handleSubmit = () => { @@ -26,58 +109,168 @@ const EducationalDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => {
- {/* Highest Qualification */} -
- - handleChange("qualification", e.target.value)} - error={Boolean(errors.qualification)} - helperText={errors.qualification} - placeholder="Enter Highest Qualification" - variant="outlined" - /> -
- {/* Field of Study */}
- + + + + Select Field of Study + + + {errors.fieldOfStudy && ( +

+ {errors.fieldOfStudy} +

+ )} +
+
+ + {/* Highest Qualification */} +
+ + + + Select Highest Qualification + + + {errors.qualification && ( +

+ {errors.qualification} +

+ )} +
+
+ + {/* College Name */} +
+ handleChange("fieldOfStudy", e.target.value)} - error={Boolean(errors.fieldOfStudy)} - helperText={errors.fieldOfStudy} - placeholder="Enter Field of Study" + name="collegeName" + label="College Name" + value={data.collegeName} + onChange={(e) => handleChange("collegeName", e.target.value)} + error={Boolean(errors.collegeName)} + helperText={errors.collegeName} + placeholder="Enter College Name" variant="outlined" />
{/* Occupation */}
- - + Occupation{requiredMark} + + handleChange("occupation", e.target.value)} - error={Boolean(errors.occupation)} - helperText={errors.occupation} - placeholder="Enter Occupation" variant="outlined" - /> + error={Boolean(errors.occupation)} + > + Select Occupation + + {errors.occupation && ( +

+ {errors.occupation} +

+ )} +
{/* Company / Organization Name */}
- + { />
+ {/* Employee Type */} +
+ + + + Select Employee Type + + + {errors.employeeType && ( +

+ {errors.employeeType} +

+ )} +
+
+ {/* Annual Income */}
- - + Annual Income{requiredMark} + + handleChange("income", e.target.value)} - error={Boolean(errors.income)} - helperText={errors.income} - placeholder="Enter Annual Income" variant="outlined" - /> + error={Boolean(errors.income)} + > + Select Annual Income + + {errors.income && ( +

+ {errors.income} +

+ )} +
{/* Work Location */}
- - handleChange("workLocation", e.target.value)} - error={Boolean(errors.workLocation)} - helperText={errors.workLocation} - placeholder="Enter Work Location" - variant="outlined" - /> + + {workLocationOptions.length > 0 ? ( + + + Select Work Location + + + {errors.workLocation && ( +

+ {errors.workLocation} +

+ )} +
+ ) : ( + handleChange("workLocation", e.target.value)} + error={Boolean(errors.workLocation)} + helperText={errors.workLocation} + placeholder="Enter Work Location" + variant="outlined" + /> + )}
diff --git a/src/feature/FamilyDetailsForm.jsx b/src/feature/FamilyDetailsForm.jsx index 0362ce7..bc59430 100644 --- a/src/feature/FamilyDetailsForm.jsx +++ b/src/feature/FamilyDetailsForm.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useMemo, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import { updateFamilyDetails } from "../redux/registrationFormSlice"; import { @@ -9,19 +9,91 @@ import { Select, MenuItem, Button, + Box, } from "@mui/material"; +import { useFamilyMasters } from "../hooks/useMasters"; -const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => { +const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange }) => { const dispatch = useDispatch(); const data = useSelector((state) => state.registerform.familyDetails); const inputRef = useRef(null); + const requiredMark = *; + + const { data: familyMasters, isLoading: isFamilyMastersLoading } = + useFamilyMasters(); + + const occupationOptions = useMemo(() => { + const raw = familyMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.occupation || raw.occupations || []; + }, [familyMasters]); + + const maritalStatusOptions = useMemo(() => { + const raw = familyMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.maritalStatus || raw.marital_status || []; + }, [familyMasters]); + + const familyStatusOptions = useMemo(() => { + const raw = familyMasters; + if (!raw) return []; + if (Array.isArray(raw)) return []; + return raw.familyStatus || raw.family_status || []; + }, [familyMasters]); useEffect(() => { inputRef.current?.focus(); }, []); + const createSibling = () => ({ + name: "", + occupation: "", + maritalStatus: "", + haveChildrens: "", + }); + + const syncSiblingArray = (arr, count) => { + const target = Math.max(0, Number(count) || 0); + const next = [...(arr || [])]; + while (next.length < target) { + next.push(createSibling()); + } + if (next.length > target) { + next.length = target; + } + return next; + }; + const handleChange = (field, value) => { - dispatch(updateFamilyDetails({ [field]: value })); + const updates = { [field]: value }; + const fieldsToClear = [field]; + + if (field === "brotherCount") { + const count = Number(value) || 0; + updates.brotherCount = count; + updates.brothers = syncSiblingArray(data.brothers, count); + fieldsToClear.push("brothers"); + } + + if (field === "sisterCount") { + const count = Number(value) || 0; + updates.sisterCount = count; + updates.sisters = syncSiblingArray(data.sisters, count); + fieldsToClear.push("sisters"); + } + + dispatch(updateFamilyDetails(updates)); + if (onFieldChange) onFieldChange(fieldsToClear); + }; + + const handleSiblingChange = (type, index, field, value) => { + const list = [...(data[type] || [])]; + if (!list[index]) list[index] = createSibling(); + list[index] = { ...list[index], [field]: value }; + dispatch(updateFamilyDetails({ [type]: list })); + if (onFieldChange) onFieldChange(type); }; const handleSubmit = () => { @@ -29,155 +101,329 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => { onSubmitStep(); }; - return ( + const countOptions = Array.from({ length: 11 }, (_, i) => i); - <> - -
- -
- {/* Highest Qualification */} -
- - { + const sibling = (data[type] || [])[index] || createSibling(); + const labelPrefix = type === "brothers" ? "Brother" : "Sister"; + return ( + +
+ {labelPrefix} {index + 1} +
+
+ handleChange("fatherName", e.target.value)} - error={Boolean(errors.fatherName)} - helperText={errors.fatherName} - placeholder="Enter Father Name" - variant="outlined" - /> -
- -
- - - - handleChange("fatherOccupation", e.target.value)} - error={Boolean(errors.fatherOccupation)} - helperText={errors.fatherOccupation} - placeholder="Enter Father Occupation" - variant="outlined" - /> -
- -
- - handleChange("motherName", e.target.value)} - error={Boolean(errors.motherName)} - helperText={errors.motherName} - placeholder="Enter Mother Name" + label="Name" + value={sibling.name} + onChange={(e) => + handleSiblingChange(type, index, "name", e.target.value) + } variant="outlined" /> -
-
- - - handleChange("motherOccupation", e.target.value)} - error={Boolean(errors.motherOccupation)} - helperText={errors.motherOccupation} - placeholder="Enter Mother Occupation" - variant="outlined" - /> - -
- -
- - handleChange("siblings", e.target.value)} - error={Boolean(errors.siblings)} - helperText={errors.siblings} - placeholder="Enter Number of Brothers / Sisters" - variant="outlined" - /> - -
- -
- - - - Brothers / Sisters (Married / Unmarried) + + + Occupation - {errors.siblingsStatus && ( -

- {errors.siblingsStatus} -

- )}
-
+ + + Marital Status + + + - + + + Have Children + + + +
+ + ); + }; + + return ( +
+ +
+
+ + handleChange("fatherName", e.target.value)} + error={Boolean(errors.fatherName)} + helperText={errors.fatherName} + placeholder="Enter Father Name" + variant="outlined" + /> +
+ +
+ + handleChange("fatherOccupation", e.target.value)} + error={Boolean(errors.fatherOccupation)} + helperText={errors.fatherOccupation} + placeholder="Enter Father Occupation" + variant="outlined" + /> +
+ +
+ + handleChange("motherName", e.target.value)} + error={Boolean(errors.motherName)} + helperText={errors.motherName} + placeholder="Enter Mother Name" + variant="outlined" + /> +
+ +
+ + handleChange("motherOccupation", e.target.value)} + error={Boolean(errors.motherOccupation)} + helperText={errors.motherOccupation} + placeholder="Enter Mother Occupation" + variant="outlined" + /> +
+ +
+ + + Select Brother Count + + +
+ +
+ + + Select Sister Count + + +
+ +
+ + + Select Family Status + + {errors.familyStatus && ( +

+ {errors.familyStatus} +

+ )} +
+
+ +
+ + handleChange("nativePlace", e.target.value)} + error={Boolean(errors.nativePlace)} + helperText={errors.nativePlace} + placeholder="Enter Native Place" + variant="outlined" + /> +
+
+ + {Number(data.brotherCount) > 0 && ( +
+
+ Brother Details
+
+ {Array.from({ length: Number(data.brotherCount) }).map( + (_, index) => renderSiblingCard("brothers", index) + )} +
+
+ )} - - - - - - - - -
- - - - + +
); }; diff --git a/src/feature/LifestyleDetailsForm.jsx b/src/feature/LifestyleDetailsForm.jsx index c30501d..049652a 100644 --- a/src/feature/LifestyleDetailsForm.jsx +++ b/src/feature/LifestyleDetailsForm.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useMemo, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import { updateLifestyleDetails } from "../redux/registrationFormSlice"; import { @@ -8,12 +8,50 @@ import { Select, MenuItem, Button, + TextField, + Checkbox, + ListItemText, } from "@mui/material"; +import { LocalizationProvider } from "@mui/x-date-pickers"; +import { DatePicker } from "@mui/x-date-pickers/DatePicker"; +import { TimePicker } from "@mui/x-date-pickers/TimePicker"; +import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; +import { useLifestyleMasters } from "../hooks/useMasters"; -const LifestyleDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => { +const LifestyleDetailsForm = ({ + onSubmitStep, + onSkipStep, + errors, + onFieldChange, +}) => { const dispatch = useDispatch(); const data = useSelector((state) => state.registerform.lifestyleDetails); const inputRef = useRef(null); + const requiredMark = *; + + const { data: lifestyleMasters, isLoading: isLifestyleMastersLoading } = + useLifestyleMasters(); + + const dietOptions = useMemo(() => { + const raw = lifestyleMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.diet || raw.diets || []; + }, [lifestyleMasters]); + + const hobbyOptions = useMemo(() => { + const raw = lifestyleMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.hobbies || raw.hobby || []; + }, [lifestyleMasters]); + + const grahaOptions = useMemo(() => { + const raw = lifestyleMasters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.grahas || raw.graha || []; + }, [lifestyleMasters]); useEffect(() => { inputRef.current?.focus(); @@ -21,6 +59,27 @@ const LifestyleDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => { const handleChange = (field, value) => { dispatch(updateLifestyleDetails({ [field]: value })); + if (onFieldChange) onFieldChange(field); + }; + + const handleMultiChange = (field, value) => { + const nextValue = Array.isArray(value) ? value : String(value).split(","); + dispatch(updateLifestyleDetails({ [field]: nextValue })); + if (onFieldChange) onFieldChange(field); + }; + + const handleGrahaChange = (house, value) => { + const next = { ...(data.graha || {}) }; + next[house] = value; + dispatch(updateLifestyleDetails({ graha: next })); + if (onFieldChange) onFieldChange("graha"); + }; + + const handleAmsamChange = (house, value) => { + const next = { ...(data.amsam || {}) }; + next[house] = value; + dispatch(updateLifestyleDetails({ amsam: next })); + if (onFieldChange) onFieldChange("amsam"); }; const handleSubmit = () => { @@ -28,67 +87,302 @@ const LifestyleDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => { onSubmitStep(); }; - 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: "hobbies", - label: "Hobbies & Interests", - options: ["Song", "Reading", "Sports", "Travel"], - }, - ]; + const parseDateValue = (value) => { + if (!value) return null; + const date = new Date(value); + return Number.isNaN(date.getTime()) ? null : date; + }; + + const parseTimeValue = (value) => { + if (!value || typeof value !== "string") return null; + const [hours, minutes] = value.split(":").map(Number); + if (Number.isNaN(hours) || Number.isNaN(minutes)) return null; + const date = new Date(); + date.setHours(hours, minutes, 0, 0); + return date; + }; + + const formatDate = (value) => { + if (!(value instanceof Date) || Number.isNaN(value)) return ""; + const y = value.getFullYear(); + const m = String(value.getMonth() + 1).padStart(2, "0"); + const d = String(value.getDate()).padStart(2, "0"); + return `${y}-${m}-${d}`; + }; + + const formatTime = (value) => { + if (!(value instanceof Date) || Number.isNaN(value)) return ""; + const h = String(value.getHours()).padStart(2, "0"); + const m = String(value.getMinutes()).padStart(2, "0"); + return `${h}:${m}`; + }; + + const renderChartCell = (label, value, onChange) => ( +
+ + {label} + + + + +
+ ); + + const renderChartGrid = (type) => { + const getValue = (house) => + (type === "graha" ? data.graha : data.amsam)?.[house] || []; + const onChange = (house, value) => + type === "graha" + ? handleGrahaChange(house, value) + : handleAmsamChange(house, value); + const label = type === "graha" ? "Rasi" : "Navamsam"; + + return ( +
+ {renderChartCell(label, getValue(1), (value) => onChange(1, value))} + {renderChartCell(label, getValue(2), (value) => onChange(2, value))} + {renderChartCell(label, getValue(3), (value) => onChange(3, value))} + {renderChartCell(label, getValue(4), (value) => onChange(4, value))} + + {renderChartCell(label, getValue(5), (value) => onChange(5, value))} +
+
+
+ {renderChartCell(label, getValue(6), (value) => onChange(6, value))} + + {renderChartCell(label, getValue(7), (value) => onChange(7, value))} + {renderChartCell(label, getValue(8), (value) => onChange(8, value))} + + {renderChartCell(label, getValue(9), (value) => onChange(9, value))} + {renderChartCell(label, getValue(10), (value) => onChange(10, value))} + {renderChartCell(label, getValue(11), (value) => onChange(11, value))} + {renderChartCell(label, getValue(12), (value) => onChange(12, value))} +
+ ); + }; return (
- {fields.map(({ name, label, options }) => ( -
- - + + + Select Diet + handleChange(name, e.target.value)} - inputRef={name === "diet" ? inputRef : null} - > - - {options.map((opt) => ( - - {opt} + {dietOptions.map((opt) => { + const value = opt.id ?? opt; + const label = opt.diet_name || opt.name || String(opt); + return ( + + -1} /> + - ))} - - {errors[name] && ( -

- {errors[name]} -

- )} -
+ ); + })} + + {errors.diets && ( +

+ {errors.diets} +

+ )} +
+
+ +
+ + + + Select Hobbies & Interests + + + {errors.hobbies && ( +

+ {errors.hobbies} +

+ )} +
+
+
+ +
+

+ Astrology / Horoscope +

+
+ +
+
+ + + handleChange("dob", formatDate(value))} + slotProps={{ + textField: { + name: "dob", + fullWidth: true, + error: Boolean(errors.dob), + helperText: errors.dob, + }, + }} + /> + +
+ +
+ + + handleChange("tob", formatTime(value))} + slotProps={{ + textField: { + name: "tob", + fullWidth: true, + error: Boolean(errors.tob), + helperText: errors.tob, + }, + }} + /> + +
+ +
+ + handleChange("placeOfBirth", e.target.value)} + error={Boolean(errors.placeOfBirth)} + helperText={errors.placeOfBirth} + placeholder="Enter Place of Birth" + variant="outlined" + /> +
+
+ +
+
+
+

+ Add Rasi +

+ {renderChartGrid("graha")}
- ))} +
+ +
+
+

+ Add Navamsam +

+ {renderChartGrid("amsam")} +
+
{ +const PartnerPreferencesForm = ({ + onSubmitStep, + onSkipStep, + errors, + onFieldChange, +}) => { const dispatch = useDispatch(); const data = useSelector((state) => state.registerform.partnerPreferences); const inputRef = useRef(null); + const requiredMark = *; + + const { data: masters, isLoading: isPartnerMastersLoading } = + usePartnerPreferenceMasters(); + const subCasteQuery = useSubCasteMasters(data.castes); + const cityQuery = useCityMasters(data.states); + + const ageRangeOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.ageRange || raw.age_range || []; + }, [masters]); + + const casteOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.caste || raw.castes || []; + }, [masters]); + + const occupationOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.occupation || raw.occupations || []; + }, [masters]); + + const educationOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.education || raw.educations || []; + }, [masters]); + + const hobbyOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.hobbies || raw.hobby || []; + }, [masters]); + + const annualIncomeOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.annual_income || raw.annualIncome || []; + }, [masters]); + + const stateOptions = useMemo(() => { + const raw = masters; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.state || raw.states || []; + }, [masters]); + + const subCasteOptions = useMemo(() => { + const raw = subCasteQuery.data; + if (!raw) return []; + if (Array.isArray(raw)) { + const merged = raw.flatMap((entry) => { + if (!entry) return []; + if (Array.isArray(entry)) return entry; + return entry.sub_caste || entry.subCaste || entry.data || []; + }); + return merged; + } + return raw.sub_caste || raw.subCaste || raw.data || []; + }, [subCasteQuery.data]); + + const cityOptions = useMemo(() => { + const raw = cityQuery.data; + if (!raw) return []; + if (Array.isArray(raw)) return raw; + return raw.subCaste || raw.district || raw.data || []; + }, [cityQuery.data]); useEffect(() => { inputRef.current?.focus(); }, []); const handleChange = (field, value) => { - dispatch(updatePartnerPreferences({ [field]: value })); + const arrayFields = new Set([ + "castes", + "subCastes", + "occupations", + "educations", + "hobbies", + "states", + "districts", + ]); + const nextValue = + arrayFields.has(field) && typeof value === "string" + ? value.split(",").filter(Boolean) + : value; + const updates = { [field]: nextValue }; + const fieldsToClear = [field]; + + if (field === "castes") { + updates.subCastes = []; + fieldsToClear.push("subCastes"); + } + if (field === "states") { + updates.districts = []; + fieldsToClear.push("districts"); + } + + dispatch(updatePartnerPreferences(updates)); + if (onFieldChange) onFieldChange(fieldsToClear); }; const handleSubmit = () => { @@ -29,36 +139,98 @@ const PartnerPreferencesForm = ({ onSubmitStep, onSkipStep, errors }) => { onSubmitStep(); }; + const renderMultiSelect = ({ + name, + label, + options, + value, + getLabel, + getValue, + disabled, + }) => ( + + Select {label} + + {errors[name] && ( +

+ {errors[name]} +

+ )} +
+ ); + return (
- {/* Preferred Age Range */} + {/* Age Range */}
- - Select Preferred Age Range - + Select Age Range {errors.ageRange && (

{

- {/* Religion / Caste Preference */} + {/* Caste */}
+ {renderMultiSelect({ + name: "castes", + label: "Caste", + options: casteOptions, + value: data.castes, + getLabel: (opt) => opt.caste_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: isPartnerMastersLoading, + })} +
+ + {/* Sub Caste */} +
+ + {renderMultiSelect({ + name: "subCastes", + label: "Sub Caste", + options: subCasteOptions, + value: data.subCastes, + getLabel: (opt) => + opt.sub_caste_name || opt.subCaste_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: data.castes.length === 0 || subCasteQuery.isLoading, + })} +
+ + {/* Occupation */} +
+ + {renderMultiSelect({ + name: "occupations", + label: "Occupation", + options: occupationOptions, + value: data.occupations, + getLabel: (opt) => opt.occupation_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: isPartnerMastersLoading, + })} +
+ + {/* Qualification */} +
+ + {renderMultiSelect({ + name: "educations", + label: "Qualification", + options: educationOptions, + value: data.educations, + getLabel: (opt) => opt.education_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: isPartnerMastersLoading, + })} +
+ + {/* Lifestyle and Hobbies */} +
+ + {renderMultiSelect({ + name: "hobbies", + label: "Lifestyle & Hobbies", + options: hobbyOptions, + value: data.hobbies, + getLabel: (opt) => opt.hobby_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: isPartnerMastersLoading, + })} +
+ + {/* Annual Income */} +
+ - - Select Religion / Caste Preference + + Select Annual Income - {errors.religionCaste && ( + {errors.annualIncome && (

{ fontSize: "0.75rem", }} > - {errors.religionCaste} + {errors.annualIncome}

)}
- {/* Occupation Preference */} + {/* State */}
- - - Select Occupation Preference - - - {errors.occupationPref && ( -

- {errors.occupationPref} -

- )} -
+ {renderMultiSelect({ + name: "states", + label: "State", + options: stateOptions, + value: data.states, + getLabel: (opt) => opt.state_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: isPartnerMastersLoading, + })}
- {/* Lifestyle & Habits Preference */} + {/* City */}
- - - Select Lifestyle & Habits Preference - - - {errors.lifestylePref && ( -

- {errors.lifestylePref} -

- )} -
-
- - {/* Prefer Qualification */} -
- - - handleChange("qualificationPref", e.target.value) - } - error={Boolean(errors.qualificationPref)} - helperText={errors.qualificationPref} - variant="outlined" - /> -
- - {/* Occupation (text) */} -
- - - handleChange("occupationText", e.target.value) - } - error={Boolean(errors.occupationText)} - helperText={errors.occupationText} - variant="outlined" - /> -
- - {/* Prefer Annual Income */} -
- - handleChange("incomePref", e.target.value)} - error={Boolean(errors.incomePref)} - helperText={errors.incomePref} - variant="outlined" - /> -
- - {/* Prefer Location */} -
- - handleChange("locationPref", e.target.value)} - error={Boolean(errors.locationPref)} - helperText={errors.locationPref} - variant="outlined" - /> + {renderMultiSelect({ + name: "districts", + label: "City", + options: cityOptions, + value: data.districts, + getLabel: (opt) => + opt.district_name || opt.city_name || opt.name || String(opt), + getValue: (opt) => opt.id ?? opt, + disabled: data.states.length === 0 || cityQuery.isLoading, + })}
diff --git a/src/feature/PersonalDetailsForm.jsx b/src/feature/PersonalDetailsForm.jsx index 02040dc..200fbc4 100644 --- a/src/feature/PersonalDetailsForm.jsx +++ b/src/feature/PersonalDetailsForm.jsx @@ -35,7 +35,7 @@ import { useSendOtp, useVerifyOtp } from "../hooks/useAuth"; const OTP_LENGTH = 4; const OTP_TIMER_SEC = 120; // 2 minutes -const PersonalDetailsForm = ({ onSubmitStep, errors }) => { +const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange }) => { const dispatch = useDispatch(); const data = useSelector((state) => state.registerform.personalDetails); const nameInputRef = useRef(null); @@ -141,6 +141,52 @@ const PersonalDetailsForm = ({ onSubmitStep, errors }) => { setOtpTimer(OTP_TIMER_SEC); }, []); + const getApiErrorMessage = useCallback((error, fallback) => { + const data = error?.response?.data ?? error?.data ?? error; + if (!data) return fallback; + if (typeof data === "string") return data; + + const directMessage = + data.message || data.error || data.detail || data.msg; + if (directMessage) return directMessage; + + if (Array.isArray(data.errors)) { + const first = data.errors[0]; + if (typeof first === "string") return first; + if (first && typeof first === "object") { + return ( + first.message || + first.msg || + first.error || + first.detail || + fallback + ); + } + } + + if (data.errors && typeof data.errors === "object") { + const firstValue = Object.values(data.errors)[0]; + if (Array.isArray(firstValue)) { + const joined = firstValue.filter(Boolean).join(" "); + if (joined) return joined; + } + if (typeof firstValue === "string") return firstValue; + if (firstValue && typeof firstValue === "object") { + return ( + firstValue.message || + firstValue.msg || + firstValue.error || + firstValue.detail || + fallback + ); + } + } + + if (data.otp) return String(data.otp); + if (error?.message) return error.message; + return fallback; + }, []); + useEffect(() => { if (otpTimer <= 0) return; const timerId = setInterval(() => { @@ -207,18 +253,18 @@ const PersonalDetailsForm = ({ onSubmitStep, errors }) => { resetOtp(); setMobileOtpVerified(false); } catch (error) { - setMobileNumberError("Failed to send OTP. Please try again."); - const message = - error?.response?.data?.message || - error?.response?.data?.otp || - error?.message || - "Failed to send OTP"; + const message = getApiErrorMessage( + error, + "Failed to send OTP. Please try again." + ); + setMobileNumberError(message); toast.error(message, { position: "top-right" }); } }; const handleChange = (field, value) => { const updates = { [field]: value }; + const fieldsToClear = [field]; if (field === "mobileNumber") { setMobileNumberError(""); setShowOtp(false); @@ -230,21 +276,61 @@ const PersonalDetailsForm = ({ onSubmitStep, errors }) => { if (field === "religion") { updates.caste = ""; updates.subCaste = ""; + fieldsToClear.push("caste", "subCaste"); } if (field === "caste") { updates.subCaste = ""; + fieldsToClear.push("subCaste"); } if (field === "state") { updates.city = ""; + fieldsToClear.push("city"); } if (field === "raasi") { updates.star = ""; + fieldsToClear.push("star"); + } + if (field === "password") { + fieldsToClear.push("confirmPassword"); } dispatch(updatePersonalDetails(updates)); + if (onFieldChange) onFieldChange(fieldsToClear); }; const isOtpComplete = otp.every((digit) => digit !== ""); + const passwordStrength = useMemo(() => { + const value = data.password || ""; + if (!value) return null; + const rules = [ + { key: "length", label: "At least 8 characters", ok: value.length >= 8 }, + { key: "upper", label: "Uppercase letter", ok: /[A-Z]/.test(value) }, + { key: "lower", label: "Lowercase letter", ok: /[a-z]/.test(value) }, + { key: "number", label: "Number", ok: /\d/.test(value) }, + { key: "symbol", label: "Symbol", ok: /[^A-Za-z0-9]/.test(value) }, + { key: "length12", label: "12+ characters (recommended)", ok: value.length >= 12 }, + ]; + const score = rules.filter((rule) => rule.ok).length; + const percent = Math.round((score / rules.length) * 100); + + let label = "Weak"; + let color = "#d32f2f"; + if (score >= 5) { + label = "Strong"; + color = "#2e7d32"; + } else if (score >= 3) { + label = "Medium"; + color = "#ed6c02"; + } + + return { + label, + color, + percent, + rules, + }; + }, [data.password]); + const handleOtpSubmit = async () => { if (!isOtpComplete) { setOtpError("Complete OTP is required"); @@ -265,11 +351,10 @@ const PersonalDetailsForm = ({ onSubmitStep, errors }) => { setMobileNumberError(""); setOtpError(""); } catch (error) { - const message = - error?.response?.data?.message || - error?.response?.data?.otp || - error?.message || - "Invalid or expired OTP"; + const message = getApiErrorMessage( + error, + "Invalid or expired OTP" + ); setOtpError(message); toast.error(message, { position: "top-right" }); } @@ -576,6 +661,7 @@ const PersonalDetailsForm = ({ onSubmitStep, errors }) => { }} slotProps={{ textField: { + name: "dob", fullWidth: true, error: Boolean(errors.dob), helperText: errors.dob, @@ -954,6 +1040,64 @@ const PersonalDetailsForm = ({ onSubmitStep, errors }) => { }} variant="outlined" /> + {passwordStrength && ( +
+
+ Password strength + + {passwordStrength.label} + +
+
+
+
+
+ Recommended: 12+ characters with a mix of upper/lowercase, + numbers, and symbols. +
+
+ {passwordStrength.rules.map((rule) => ( +
+ {rule.ok ? ( + + ) : ( + + )} + + {rule.label} + +
+ ))} +
+
+ )}
{/* Confirm Password */} diff --git a/src/feature/PreviewScreen.jsx b/src/feature/PreviewScreen.jsx index 1958c3c..19c3141 100644 --- a/src/feature/PreviewScreen.jsx +++ b/src/feature/PreviewScreen.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; import { useSelector } from 'react-redux'; import { Edit2,Info } from 'lucide-react'; import { @@ -12,44 +12,154 @@ import { Button, Grid, } from '@mui/material'; +import { usePreviewDetails } from "../hooks/usePreview"; const PreviewScreen = ({ onEdit, onSubmit }) => { const formData = useSelector((state) => state.registerform); + const { data: previewData, isLoading, isError } = usePreviewDetails(); - const sections = [ - { - title: 'Personal Details', - step: 1, - data: formData.personalDetails, - }, - { - title: 'Educational & Professional Details', - step: 2, - data: formData.educationalDetails, - }, - { - title: 'Family Details', - step: 3, - data: formData.familyDetails, - }, - { - title: 'Lifestyle & Habits', - step: 4, - data: formData.lifestyleDetails, - }, - { - title: 'Partner Preferences', - step: 5, - data: formData.partnerPreferences, - }, - ]; + const sections = previewData?.personal_details + ? [ + { + title: "Personal Details", + step: 1, + data: previewData.personal_details, + }, + { + title: "Educational & Professional Details", + step: 2, + data: previewData.educational_details, + }, + { + title: "Family Details", + step: 3, + data: previewData.family_details, + }, + { + title: "Lifestyle & Habits", + step: 4, + data: previewData.lifestyle_details, + }, + { + title: "Partner Preferences", + step: 5, + data: previewData.partner_preferences, + }, + ] + : [ + { + title: 'Personal Details', + step: 1, + data: formData.personalDetails, + }, + { + title: 'Educational & Professional Details', + step: 2, + data: formData.educationalDetails, + }, + { + title: 'Family Details', + step: 3, + data: formData.familyDetails, + }, + { + title: 'Lifestyle & Habits', + step: 4, + data: formData.lifestyleDetails, + }, + { + title: 'Partner Preferences', + step: 5, + data: formData.partnerPreferences, + }, + ]; + + const renderValue = (key, value) => { + if (key === "profiles" || key === "profile") { + const list = Array.isArray(value) ? value : []; + return ( + + {list.length > 0 ? ( + list.map((imgObj, index) => { + const src = + typeof imgObj === "string" + ? imgObj + : imgObj?.preview || + imgObj?.url || + (imgObj?.file ? URL.createObjectURL(imgObj.file) : null); + if (!src) return null; + return ( + Profile + ); + }) + ) : ( + + + No photos uploaded + + )} + + ); + } + + if (Array.isArray(value)) { + if (value.length === 0) return "-"; + if (typeof value[0] === "object") { + return value.map((item, idx) => ( +
{JSON.stringify(item)}
+ )); + } + return value.join(", "); + } + + if (value && typeof value === "object") { + return "-"; + } + + return value || "-"; + }; return (
- {sections.map((section) => ( + {isLoading && ( + + Loading preview... + + )} + + {isError && ( + + Failed to load preview. + + )} + + {!isLoading && + sections.map((section) => ( { /> - {Object.entries(section.data).map(([key, value]) => { + {Object.entries(section.data || {}).map(([key, value]) => { // if (value && key !== 'profiles') { @@ -82,9 +192,7 @@ const PreviewScreen = ({ onEdit, onSubmit }) => { .replace(/_/g, ' ') .replace(/\b\w/g, (l) => l.toUpperCase()) .trim(); - const isImage = - typeof value === "string" && - (value.startsWith("http") || value.startsWith("data:image")); + const content = renderValue(key, value); return ( { {/* Special Case: Profiles Image Preview */} - {key === "profiles" ? ( - - {value && value.length > 0 ? ( - value.map((imgObj, index) => ( - Profile - )) - ) : ( - - - No photos uploaded - - )} - + {key === "profiles" || key === "profile" ? ( + content + ) : value ? ( + + {content} + ) : ( - // Text OR No Data - <> - {value ? ( - - {value} - - ) : ( - - - No data available - - )} - + + + No data available + )} diff --git a/src/feature/ProfilePreviewPage.jsx b/src/feature/ProfilePreviewPage.jsx index 90caa79..7c41d85 100644 --- a/src/feature/ProfilePreviewPage.jsx +++ b/src/feature/ProfilePreviewPage.jsx @@ -234,8 +234,10 @@ const ProfilePreviewPage = () => { {renderField("Qualification", educationalDetails.qualification, 2)} {renderField("Field of Study", educationalDetails.fieldOfStudy, 2)} + {renderField("College Name", educationalDetails.collegeName, 2)} {renderField("Occupation", educationalDetails.occupation, 2)} {renderField("Organization", educationalDetails.organization, 2)} + {renderField("Employee Type", educationalDetails.employeeType, 2)} {renderField("Income", educationalDetails.income, 2)} {renderField("Work Location", educationalDetails.workLocation, 2)} @@ -269,8 +271,10 @@ const ProfilePreviewPage = () => { {renderField("Father Occupation", familyDetails.fatherOccupation)} {renderField("Mother Name", familyDetails.motherName)} {renderField("Mother Occupation", familyDetails.motherOccupation)} - {renderField("Number of Siblings", familyDetails.siblings)} - {renderField("Siblings Marital status", familyDetails.siblingsStatus)} + {renderField("Brother Count", familyDetails.brotherCount)} + {renderField("Sister Count", familyDetails.sisterCount)} + {renderField("Family Status", familyDetails.familyStatus)} + {renderField("Native Place", familyDetails.nativePlace)} ); @@ -298,11 +302,21 @@ const ProfilePreviewPage = () => { - {renderField("Diet", lifestyleDetails.diet)} - {/* {renderField("Drinking", lifestyleDetails.drinking)} - {renderField("Smoking", lifestyleDetails.smoking)} */} - {renderField("Hobbies", lifestyleDetails.hobbies)} - + {renderField( + "Diet", + Array.isArray(lifestyleDetails.diets) + ? lifestyleDetails.diets.join(", ") + : lifestyleDetails.diets + )} + {renderField( + "Hobbies", + Array.isArray(lifestyleDetails.hobbies) + ? lifestyleDetails.hobbies.join(", ") + : lifestyleDetails.hobbies + )} + {renderField("Date of Birth", lifestyleDetails.dob)} + {renderField("Time of Birth", lifestyleDetails.tob)} + {renderField("Place of Birth", lifestyleDetails.placeOfBirth)} ); @@ -331,14 +345,50 @@ const ProfilePreviewPage = () => { - {renderField("Age", partnerPreferences.ageRange)} - {renderField("Religion", partnerPreferences.religionCaste)} - {renderField("Occupation", partnerPreferences.occupationPref)} - {renderField("Life style", partnerPreferences.lifestylePref)} - {renderField("Qualification", partnerPreferences.qualificationPref)} - {renderField("Occupation", partnerPreferences.occupationText)} - {renderField("Income", partnerPreferences.incomePref)} - {renderField("Location", partnerPreferences.locationPref)} + {renderField("Age Range", partnerPreferences.ageRange)} + {renderField( + "Caste", + Array.isArray(partnerPreferences.castes) + ? partnerPreferences.castes.join(", ") + : partnerPreferences.castes + )} + {renderField( + "Sub Caste", + Array.isArray(partnerPreferences.subCastes) + ? partnerPreferences.subCastes.join(", ") + : partnerPreferences.subCastes + )} + {renderField( + "Occupation", + Array.isArray(partnerPreferences.occupations) + ? partnerPreferences.occupations.join(", ") + : partnerPreferences.occupations + )} + {renderField( + "Qualification", + Array.isArray(partnerPreferences.educations) + ? partnerPreferences.educations.join(", ") + : partnerPreferences.educations + )} + {renderField( + "Lifestyle & Hobbies", + Array.isArray(partnerPreferences.hobbies) + ? partnerPreferences.hobbies.join(", ") + : partnerPreferences.hobbies + )} + {renderField("Annual Income", partnerPreferences.annualIncome)} + {renderField( + "State", + Array.isArray(partnerPreferences.states) + ? partnerPreferences.states.join(", ") + : partnerPreferences.states + )} + {renderField( + "City", + Array.isArray(partnerPreferences.districts) + ? partnerPreferences.districts.join(", ") + : partnerPreferences.districts + )} diff --git a/src/feature/StepperForm.jsx b/src/feature/StepperForm.jsx index 5ea34ee..128eda2 100644 --- a/src/feature/StepperForm.jsx +++ b/src/feature/StepperForm.jsx @@ -1,4 +1,4 @@ -import React, { useState,useEffect } from "react"; +import React, { useState, useEffect } from "react"; import { ChevronLeft } from "lucide-react"; import { useDispatch, useSelector } from "react-redux"; import { @@ -16,7 +16,105 @@ import LifestyleDetailsForm from "./LifestyleDetailsForm"; import PartnerPreferencesForm from "./PartnerPreferencesForm"; import PreviewScreen from "./PreviewScreen"; import { useLocation } from "react-router-dom"; -import { useRegisterStep1 } from "../hooks/useRegister"; +import { + useRegisterStep1, + useRegisterStep2, + useRegisterStep3, + useRegisterStep4, + useRegisterStep5, +} from "../hooks/useRegister"; +import { setAccessToken } from "../api/axiosInstance"; +import toast from "react-hot-toast"; + +const STEP_FIELD_ORDER = { + 1: [ + "name", + "gender", + "mobileNumber", + "dob", + "height", + "weight", + "maritalStatus", + "religion", + "profileFor", + "caste", + "subCaste", + "gothram", + "raasi", + "star", + "email", + "password", + "confirmPassword", + "state", + "city", + "pincode", + "profiles", + ], + 2: [ + "fieldOfStudy", + "qualification", + "collegeName", + "occupation", + "organization", + "employeeType", + "income", + "workLocation", + ], + 3: [ + "fatherName", + "fatherOccupation", + "motherName", + "motherOccupation", + "brotherCount", + "sisterCount", + "familyStatus", + "nativePlace", + ], + 4: ["diets", "hobbies", "dob", "tob", "placeOfBirth"], + 5: [ + "ageRange", + "castes", + "subCastes", + "occupations", + "educations", + "hobbies", + "annualIncome", + "states", + "districts", + ], +}; + +const STEP1_SERVER_FIELD_MAP = { + name: "name", + mobile: "mobileNumber", + mobile_number: "mobileNumber", + mobileNumber: "mobileNumber", + phone: "mobileNumber", + email: "email", + gender: "gender", + dob: "dob", + height: "height", + weight: "weight", + marital_status: "maritalStatus", + maritalStatus: "maritalStatus", + religion: "religion", + profile_for: "profileFor", + profileFor: "profileFor", + caste: "caste", + sub_caste: "subCaste", + subCaste: "subCaste", + gothram: "gothram", + raasi: "raasi", + star: "star", + state: "state", + district: "city", + city: "city", + pincode: "pincode", + password: "password", + confirm_password: "confirmPassword", + confirmPassword: "confirmPassword", + profiles: "profiles", +}; const Stepper = ({ currentStep, onStepClick }) => { @@ -84,6 +182,136 @@ const StepperForm = () => { const [errors, setErrors] = useState({}); const registerStep1 = useRegisterStep1(); + const registerStep2 = useRegisterStep2(); + const registerStep3 = useRegisterStep3(); + const registerStep4 = useRegisterStep4(); + const registerStep5 = useRegisterStep5(); + + const normalizeStep1Field = (key) => { + if (!key) return key; + const trimmed = String(key).trim(); + if (!trimmed) return trimmed; + return ( + STEP1_SERVER_FIELD_MAP[trimmed] || + STEP1_SERVER_FIELD_MAP[trimmed.toLowerCase()] || + trimmed + ); + }; + + const coerceErrorMessage = (value) => { + if (Array.isArray(value)) { + return value.filter(Boolean).join(" "); + } + if (typeof value === "string") return value; + if (value && typeof value === "object") { + return ( + value.message || + value.msg || + value.error || + value.detail || + "" + ); + } + if (value === null || value === undefined) return ""; + return String(value); + }; + + const mapServerErrors = (error) => { + const data = error?.response?.data ?? error?.data ?? error; + if (!data) return {}; + const payload = data.errors ?? data.error ?? data.data ?? data; + + if (typeof payload === "string") { + return { _form: payload }; + } + + if (Array.isArray(payload)) { + const out = {}; + payload.forEach((item) => { + if (!item) return; + if (typeof item === "string") { + out._form = out._form ? `${out._form} ${item}` : item; + return; + } + const key = item.field || item.name || item.param || item.key; + const message = + item.message || item.msg || item.error || item.detail || ""; + if (key) { + out[normalizeStep1Field(key)] = + String(message || "Invalid value"); + } + }); + return out; + } + + if (typeof payload === "object") { + const out = {}; + Object.entries(payload).forEach(([key, value]) => { + if ( + (key === "message" || key === "error" || key === "detail") && + typeof value === "string" + ) { + out._form = out._form ? `${out._form} ${value}` : value; + return; + } + const normalizedKey = normalizeStep1Field(key); + const message = coerceErrorMessage(value); + if (!normalizedKey) return; + out[normalizedKey] = message || "Invalid value"; + }); + return out; + } + + return {}; + }; + + const focusFirstError = (errorMap, fieldOrder = []) => { + if (!errorMap || Object.keys(errorMap).length === 0) return; + const order = fieldOrder.filter((key) => errorMap[key]); + const firstKey = + order[0] || + Object.keys(errorMap).find((key) => key !== "_form"); + if (!firstKey) return; + setTimeout(() => { + const byAria = document.querySelector( + `[aria-labelledby~="${firstKey}-label"]` + ); + if (byAria && typeof byAria.focus === "function") { + byAria.focus(); + return; + } + const byName = document.querySelector(`[name="${firstKey}"]`); + if (byName && typeof byName.focus === "function") { + byName.focus(); + return; + } + const byId = document.getElementById(firstKey); + if (byId && typeof byId.focus === "function") { + byId.focus(); + } + }, 0); + }; + + const clearFieldErrors = (fields) => { + if (!fields) return; + const list = Array.isArray(fields) ? fields : [fields]; + setErrors((prev) => { + if (!prev || Object.keys(prev).length === 0) return prev; + let changed = false; + const next = { ...prev }; + list.forEach((field) => { + if (field in next) { + delete next[field]; + changed = true; + } + }); + if (next._form) { + delete next._form; + changed = true; + } + return changed ? next : prev; + }); + }; useEffect(() => { @@ -154,8 +382,8 @@ const StepperForm = () => { "fieldOfStudy", "occupation", "organization", + "employeeType", "income", - "workLocation", ]; required.forEach((field) => { if (!educationalDetails[field]) { @@ -165,12 +393,8 @@ const StepperForm = () => { } else if (step === 3) { const required = [ "fatherName", - "fatherOccupation", "motherName", - "motherOccupation", - "siblings", - "siblingsStatus", - + "familyStatus", ]; required.forEach((field) => { if (!familyDetails[field]) { @@ -178,25 +402,36 @@ const StepperForm = () => { } }); } else if (step === 4) { - const required = ["diet", "drinking", "smoking", "hobbies"]; + const required = ["diets", "hobbies", "dob", "tob"]; required.forEach((field) => { - if (!lifestyleDetails[field]) { + const value = lifestyleDetails[field]; + if (Array.isArray(value)) { + if (value.length === 0) newErrors[field] = "This field is required"; + } else if (!value) { newErrors[field] = "This field is required"; } }); } else if (step === 5) { const required = [ "ageRange", - "religionCaste", - "occupationPref", - "lifestylePref", - "qualificationPref", - "occupationText", - "incomePref", - "locationPref", + "castes", + "subCastes", + "occupations", + "educations", + "hobbies", + "annualIncome", + "states", + "districts", ]; required.forEach((field) => { - if (!partnerPreferences[field]) { + const value = partnerPreferences[field]; + if (Array.isArray(value)) { + if (value.length === 0) { + newErrors[field] = "This field is required"; + } + return; + } + if (!value) { newErrors[field] = "This field is required"; } }); @@ -204,11 +439,8 @@ const StepperForm = () => { setErrors(newErrors); - // Autofocus first invalid field if (Object.keys(newErrors).length > 0) { - const firstKey = Object.keys(newErrors)[0]; - const el = document.querySelector(`[name="${firstKey}"]`); - if (el) el.focus(); + focusFirstError(newErrors, STEP_FIELD_ORDER[step] || []); } return Object.keys(newErrors).length === 0; @@ -237,6 +469,132 @@ const StepperForm = () => { fcm_token: localStorage.getItem("fcm_token") || "", }); + const buildRegisterStep2Payload = () => ({ + college_name: educationalDetails.collegeName || "", + study_field: educationalDetails.fieldOfStudy, + education: educationalDetails.qualification, + occupation: educationalDetails.occupation, + company_name: educationalDetails.organization || "", + employee_type: educationalDetails.employeeType, + annual_income: educationalDetails.income, + work_location: educationalDetails.workLocation || "", + }); + + const buildRegisterStep3Payload = () => { + const payload = { + father_name: familyDetails.fatherName, + father_occupation: familyDetails.fatherOccupation || "", + mother_name: familyDetails.motherName, + mother_occupation: familyDetails.motherOccupation || "", + family_status: familyDetails.familyStatus, + native_place: familyDetails.nativePlace || "", + brother_count: familyDetails.brotherCount || 0, + sister_count: familyDetails.sisterCount || 0, + }; + + (familyDetails.brothers || []).forEach((brother, index) => { + payload[`brothers[${index}][name]`] = brother?.name || ""; + payload[`brothers[${index}][occupation]`] = brother?.occupation || ""; + payload[`brothers[${index}][marital_status]`] = + brother?.maritalStatus || ""; + payload[`brothers[${index}][have_childrens]`] = + brother?.haveChildrens ?? ""; + }); + + (familyDetails.sisters || []).forEach((sister, index) => { + payload[`sisters[${index}][name]`] = sister?.name || ""; + payload[`sisters[${index}][occupation]`] = sister?.occupation || ""; + payload[`sisters[${index}][marital_status]`] = + sister?.maritalStatus || ""; + payload[`sisters[${index}][have_childrens]`] = + sister?.haveChildrens ?? ""; + }); + + return payload; + }; + + const buildRegisterStep4Payload = () => { + const payload = { + dob: lifestyleDetails.dob, + tob: lifestyleDetails.tob, + }; + + (lifestyleDetails.diets || []).forEach((id, index) => { + payload[`diets[${index}]`] = id; + }); + + (lifestyleDetails.hobbies || []).forEach((id, index) => { + payload[`hobbies[${index}]`] = id; + }); + + const graha = lifestyleDetails.graha || {}; + Object.keys(graha).forEach((house) => { + const values = graha[house] || []; + values.forEach((value, index) => { + payload[`graha_${house}[${index}]`] = value; + }); + }); + + const amsam = lifestyleDetails.amsam || {}; + Object.keys(amsam).forEach((house) => { + const values = amsam[house] || []; + values.forEach((value, index) => { + payload[`amsam_${house}[${index}]`] = value; + }); + }); + + return payload; + }; + + const buildRegisterStep5Payload = () => { + const payload = { + age_range: partnerPreferences.ageRange, + annual_income: partnerPreferences.annualIncome, + }; + + (partnerPreferences.castes || []).forEach((id, index) => { + payload[`castes[${index}]`] = id; + }); + + (partnerPreferences.subCastes || []).forEach((id, index) => { + payload[`sub_castes[${index}]`] = id; + }); + + (partnerPreferences.occupations || []).forEach((id, index) => { + payload[`occupations[${index}]`] = id; + }); + + (partnerPreferences.educations || []).forEach((id, index) => { + payload[`educations[${index}]`] = id; + }); + + (partnerPreferences.hobbies || []).forEach((id, index) => { + payload[`hobbies[${index}]`] = id; + }); + + (partnerPreferences.states || []).forEach((id, index) => { + payload[`states[${index}]`] = id; + }); + + (partnerPreferences.districts || []).forEach((id, index) => { + payload[`districts[${index}]`] = id; + }); + + return payload; + }; + + const extractAccessToken = (res) => + res?.access_token || + res?.accessToken || + res?.token || + res?.data?.access_token || + res?.data?.accessToken || + res?.data?.token || + res?.result?.access_token || + res?.result?.accessToken || + res?.result?.token || + null; + const handleStepSubmit = async () => { const isValid = validateStep(currentStep); if (!isValid) return; @@ -244,11 +602,45 @@ const StepperForm = () => { try { if (currentStep === 1) { const payload = buildRegisterStep1Payload(); - await registerStep1.mutateAsync(payload); + const res = await registerStep1.mutateAsync(payload); + const token = extractAccessToken(res); + if (token) { + setAccessToken(token); + } + } else if (currentStep === 2) { + const payload = buildRegisterStep2Payload(); + await registerStep2.mutateAsync(payload); + } else if (currentStep === 3) { + const payload = buildRegisterStep3Payload(); + await registerStep3.mutateAsync(payload); + } else if (currentStep === 4) { + const payload = buildRegisterStep4Payload(); + await registerStep4.mutateAsync(payload); + } else if (currentStep === 5) { + const payload = buildRegisterStep5Payload(); + await registerStep5.mutateAsync(payload); } + setErrors({}); setCurrentStep((prev) => Math.min(prev + 1, 6)); window.scrollTo(0, 0); } catch (e) { + if (currentStep === 1) { + const serverErrors = mapServerErrors(e); + if (Object.keys(serverErrors).length > 0) { + const hasFieldErrors = Object.keys(serverErrors).some( + (key) => key !== "_form" + ); + if (hasFieldErrors) { + setErrors(serverErrors); + focusFirstError(serverErrors, STEP_FIELD_ORDER[1]); + return; + } + if (serverErrors._form) { + toast.error(serverErrors._form, { position: "top-right" }); + return; + } + } + } alert("Failed to submit step. Please try again."); } }; @@ -296,6 +688,7 @@ const StepperForm = () => { ); case 2: @@ -304,6 +697,7 @@ const StepperForm = () => { onSubmitStep={handleStepSubmit} onSkipStep={handleSkip} errors={errors} + onFieldChange={clearFieldErrors} /> ); case 3: @@ -312,6 +706,7 @@ const StepperForm = () => { onSubmitStep={handleStepSubmit} onSkipStep={handleSkip} errors={errors} + onFieldChange={clearFieldErrors} /> ); case 4: @@ -320,6 +715,7 @@ const StepperForm = () => { onSubmitStep={handleStepSubmit} onSkipStep={handleSkip} errors={errors} + onFieldChange={clearFieldErrors} /> ); case 5: @@ -328,6 +724,7 @@ const StepperForm = () => { onSubmitStep={handleStepSubmit} onSkipStep={handleSkip} errors={errors} + onFieldChange={clearFieldErrors} /> ); case 6: diff --git a/src/hooks/useDependentMasters.js b/src/hooks/useDependentMasters.js index ef7ab6d..ad0ed8c 100644 --- a/src/hooks/useDependentMasters.js +++ b/src/hooks/useDependentMasters.js @@ -27,8 +27,16 @@ export const useCasteMasters = (religion_id) => export const useSubCasteMasters = (caste_id) => useQuery({ queryKey: ["sub-caste-masters", caste_id], - queryFn: () => getSubCasteMasters(caste_id), - enabled: !!caste_id, + queryFn: async () => { + if (Array.isArray(caste_id)) { + const results = await Promise.all( + caste_id.map((id) => getSubCasteMasters(id)) + ); + return results; + } + return getSubCasteMasters(caste_id); + }, + enabled: Array.isArray(caste_id) ? caste_id.length > 0 : !!caste_id, }); /** City depends on state */ @@ -36,7 +44,7 @@ export const useCityMasters = (state_id) => useQuery({ queryKey: ["city-masters", state_id], queryFn: () => getCityMasters(state_id), - enabled: !!state_id, + enabled: Array.isArray(state_id) ? state_id.length > 0 : !!state_id, }); /** Star depends on raasi */ diff --git a/src/hooks/useMasters.js b/src/hooks/useMasters.js index e69bc2a..756b15a 100644 --- a/src/hooks/useMasters.js +++ b/src/hooks/useMasters.js @@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { getPersonalDetailsMasters, getEducationMasters, + getEducationList, getFamilyMasters, getLifestyleMasters, getPartnerPreferenceMasters, @@ -21,6 +22,13 @@ export const useEducationMasters = () => queryFn: getEducationMasters, }); +export const useEducationList = (studyFieldId) => + useQuery({ + queryKey: ["education-list", studyFieldId], + queryFn: () => getEducationList(studyFieldId), + enabled: Boolean(studyFieldId), + }); + /** Family master */ export const useFamilyMasters = () => useQuery({ @@ -40,4 +48,4 @@ export const usePartnerPreferenceMasters = () => useQuery({ queryKey: ["partner-masters"], queryFn: getPartnerPreferenceMasters, - }); \ No newline at end of file + }); diff --git a/src/hooks/usePreview.js b/src/hooks/usePreview.js new file mode 100644 index 0000000..1900a32 --- /dev/null +++ b/src/hooks/usePreview.js @@ -0,0 +1,8 @@ +import { useQuery } from "@tanstack/react-query"; +import { getPreviewDetails } from "../api/preview.api"; + +export const usePreviewDetails = () => + useQuery({ + queryKey: ["preview-details"], + queryFn: getPreviewDetails, + }); diff --git a/src/hooks/useRegister.js b/src/hooks/useRegister.js index 1fb47b3..a8d2722 100644 --- a/src/hooks/useRegister.js +++ b/src/hooks/useRegister.js @@ -4,6 +4,7 @@ import { registerStep2API, registerStep3API, registerStep4API, + registerStep5API, } from "../api/register.api"; /** @@ -37,3 +38,11 @@ export const useRegisterStep4 = () => useMutation({ mutationFn: registerStep4API, }); + +/** + * Register - Step 5 + */ +export const useRegisterStep5 = () => + useMutation({ + mutationFn: registerStep5API, + }); diff --git a/src/hooks/useReviews.js b/src/hooks/useReviews.js new file mode 100644 index 0000000..0238357 --- /dev/null +++ b/src/hooks/useReviews.js @@ -0,0 +1,10 @@ +import { useQuery } from "@tanstack/react-query"; +import { getReviews } from "../api/reviews.api"; + +export const useReviews = () => + useQuery({ + queryKey: ["reviews"], + queryFn: getReviews, + staleTime: 1000 * 60 * 10, + refetchOnWindowFocus: false, + }); diff --git a/src/hooks/useTermsAndPolicies.js b/src/hooks/useTermsAndPolicies.js new file mode 100644 index 0000000..4eb18c2 --- /dev/null +++ b/src/hooks/useTermsAndPolicies.js @@ -0,0 +1,11 @@ +import { useQuery } from "@tanstack/react-query"; +import { getTermsAndPolicies } from "../api/terms.api"; + +export const useTermsAndPolicies = (type) => + useQuery({ + queryKey: ["terms-and-policies", type], + queryFn: () => getTermsAndPolicies(type), + enabled: Boolean(type), + staleTime: 1000 * 60 * 60, + refetchOnWindowFocus: false, + }); diff --git a/src/pages/PoliciesPage.jsx b/src/pages/PoliciesPage.jsx index e312e4b..f052110 100644 --- a/src/pages/PoliciesPage.jsx +++ b/src/pages/PoliciesPage.jsx @@ -1,13 +1,22 @@ - -import React from 'react'; -import { ArrowBackIosNew, Security, Shield, VerifiedUser } from '@mui/icons-material'; -import { useNavigate } from 'react-router-dom'; -import { motion } from 'framer-motion'; - -const text = `It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.`; +import React, { useMemo } from "react"; +import { Security, Shield, VerifiedUser } from "@mui/icons-material"; +import { useSearchParams } from "react-router-dom"; +import { motion } from "framer-motion"; +import { useTermsAndPolicies } from "../hooks/useTermsAndPolicies"; +import { Skeleton, SkeletonText } from "../components/common/Skeleton"; export default function PoliciesPage() { - const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const type = searchParams.get("type") || "privacy"; + const { data, isLoading, isError } = useTermsAndPolicies(type); + + const content = useMemo(() => { + return data?.data?.message || ""; + }, [data]); + + const title = useMemo(() => { + return data?.data?.name || "Privacy Policy"; + }, [data]); return (
@@ -19,40 +28,66 @@ export default function PoliciesPage() { >
-
- + -

Policies

-

Your Safety Is Our First Priority

+

{title}

+

+ Your Safety Is Our First Priority +

- -
-
+ +
+ {/*
-
+
*/}
-

Privacy Policy

-

{text}

+ {/*

{title}

*/} + {isLoading && ( +
+ + + +
+ )} + {isError && ( +

+ Failed to load policy. +

+ )} + {!isLoading && !isError && ( +
+ )}
- -

Safety Guidelines

-

{text}

-
- - +

Protected With Love & Care

-

Every profile, every chat, every dream — safeguarded 24×7.

+

+ Every profile, every chat, every dream — safeguarded 24×7. +

@@ -63,4 +98,4 @@ export default function PoliciesPage() {
); -} \ No newline at end of file +} diff --git a/src/pages/TermsAndCondition.jsx b/src/pages/TermsAndCondition.jsx index 7a2cc67..3597c0c 100644 --- a/src/pages/TermsAndCondition.jsx +++ b/src/pages/TermsAndCondition.jsx @@ -1,12 +1,22 @@ -import React from 'react'; -import { ArrowBackIosNew, Favorite, AutoStories } from '@mui/icons-material'; -import { useNavigate } from 'react-router-dom'; +import React, { useMemo } from 'react'; +import { Favorite, AutoStories } from '@mui/icons-material'; +import { useSearchParams } from 'react-router-dom'; import { motion } from 'framer-motion'; - -const loremText = `It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.`; +import { useTermsAndPolicies } from '../hooks/useTermsAndPolicies'; +import { Skeleton, SkeletonText } from '../components/common/Skeleton'; export default function TermsAndCondition() { - const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const type = searchParams.get("type") || "terms"; + const { data, isLoading, isError } = useTermsAndPolicies(type); + + const content = useMemo(() => { + return data?.data?.message || ""; + }, [data]); + + const title = useMemo(() => { + return data?.data?.name || "Terms & Conditions"; + }, [data]); return (
@@ -33,7 +43,7 @@ export default function TermsAndCondition() {
-

Terms & Conditions

+

{title}

Your Trust, Our Promise

@@ -49,37 +59,38 @@ export default function TermsAndCondition() { transition={{ delay: 0.4 }} className="space-y-8" > - {/* Card 1 */}
-
-
+
+ {/*
-
-
-

- {loremText} -

+
*/} +
+ {isLoading && ( +
+ + + +
+ )} + {isError && ( +

+ Failed to load terms. +

+ )} + {!isLoading && !isError && ( +
+ )}
- {/* Card 2 */} - -
- -
-

- {loremText} -

-
- {/* Final Trust Message */}
); -} \ No newline at end of file +} diff --git a/src/pages/UserDashboardHome.jsx b/src/pages/UserDashboardHome.jsx index c4e5ccb..ed43478 100644 --- a/src/pages/UserDashboardHome.jsx +++ b/src/pages/UserDashboardHome.jsx @@ -1,25 +1,22 @@ +import { Suspense, lazy } from "react"; import { Swiper, SwiperSlide } from 'swiper/react'; import { Navigation, Autoplay } from 'swiper/modules'; import { ChevronLeft, ChevronRight } from 'lucide-react'; import 'swiper/css'; import 'swiper/css/navigation'; -import ProfileCompletion from '../components/profiledashboard/ProfileCompletion'; -import DailyRecommendedCard from '../components/profiledashboard/DailyRecommendedCard'; -import MatrimonyArticles from '../components/profiledashboard/MatrimonyArticles'; -import MatchingList from '../components/profiledashboard/MatchingList'; -import PaidMemberCard from '../components/profiledashboard/PaidMemberCard'; -import LazyImage from '../components/common/LazyImage'; +import Skeleton from "../components/common/Skeleton"; import weddingpromo1 from "../assets/images/weddingpromo1.jpg"; import weddingpromo2 from "../assets/images/weddingpromo2.jpg"; import weddingpromo3 from "../assets/images/weddingpromo3.jpg"; import weddingpromo4 from "../assets/images/weddingpromo4.jpg"; -import ProfileCard from '../components/common/ProfileCard'; -import NewJoinedProfile from '../components/profiledashboard/NewJoinedProfile'; -import CustomerSupportCard from '../components/profiledashboard/CustomerSupportCard'; -import VideoSwiperGallery from '../components/profiledashboard/VideoSwiperGallery'; -import Profilecardemo from '../components/ui/ProfileCardDemo'; + +const ProfileCompletion = lazy(() => import("../components/profiledashboard/ProfileCompletion")); +const MatrimonyArticles = lazy(() => import("../components/profiledashboard/MatrimonyArticles")); +const MatchingList = lazy(() => import("../components/profiledashboard/MatchingList")); +const VideoSwiperGallery = lazy(() => import("../components/profiledashboard/VideoSwiperGallery")); +const Profilecardemo = lazy(() => import("../components/ui/ProfileCardDemo")); const images = [ @@ -35,6 +32,20 @@ const images = [ weddingpromo3 // couple full shot ]; +const SectionFallback = ({ height = 280 }) => ( +
+
+ + +
+ {Array.from({ length: 4 }).map((_, idx) => ( + + ))} +
+
+
+); + const UserDashboardHome = () => { return ( @@ -88,6 +99,8 @@ const UserDashboardHome = () => { src={img} alt={`Slide ${idx + 1}`} className="w-full h-full object-cover" + loading={idx === 0 ? "eager" : "lazy"} + decoding="async" /> {/* { `}
- + }> + + + {/* */} - {/* */} - - - {/* */} + }> + + + {/* */} - - -{/* */} + }> + + + }> + + + {/* */} -{/* */} -{/* */} - + {/* */} + {/* */} + }> + + ) } diff --git a/src/redux/registrationFormSlice.jsx b/src/redux/registrationFormSlice.jsx index ea5e211..5c9419b 100644 --- a/src/redux/registrationFormSlice.jsx +++ b/src/redux/registrationFormSlice.jsx @@ -28,6 +28,8 @@ const registrationformSlice = createSlice({ profiles: [], }, educationalDetails: { + collegeName: "", + employeeType: "", qualification: "", fieldOfStudy: "", occupation: "", @@ -40,25 +42,58 @@ const registrationformSlice = createSlice({ fatherOccupation: "", motherName: "", motherOccupation: "", - siblings: "", - siblingsStatus: "", - + brotherCount: 0, + sisterCount: 0, + brothers: [], + sisters: [], + familyStatus: "", + nativePlace: "", }, lifestyleDetails: { - diet: "", - // drinking: "", - // smoking: "", - hobbies: "", + diets: [], + hobbies: [], + dob: "", + tob: "", + placeOfBirth: "", + graha: { + 1: [], + 2: [], + 3: [], + 4: [], + 5: [], + 6: [], + 7: [], + 8: [], + 9: [], + 10: [], + 11: [], + 12: [], + }, + amsam: { + 1: [], + 2: [], + 3: [], + 4: [], + 5: [], + 6: [], + 7: [], + 8: [], + 9: [], + 10: [], + 11: [], + 12: [], + }, }, partnerPreferences: { ageRange: "", - religionCaste: "", - occupationPref: "", - lifestylePref: "", - qualificationPref: "", - occupationText: "", - incomePref: "", - locationPref: "", + castes: [], + subCastes: [], + occupations: [], + educations: [], + hobbies: [], + annualIncome: "", + states: [], + districts: [], }, }, @@ -148,8 +183,10 @@ preloadDummyProfile: (state) => { ...state.educationalDetails, qualification: "B.E", fieldOfStudy: "CSE", + collegeName: "ABC Engineering College", occupation: "Software Engineer", organization: "ABC Pvt Ltd", + employeeType: "Private", income: "10 LPA", workLocation: "Chennai", }; @@ -159,26 +196,74 @@ preloadDummyProfile: (state) => { fatherOccupation: "Business", motherName: "Mother Name", motherOccupation: "Homemaker", - siblings: "1", - siblingsStatus: "Married", + brotherCount: 1, + sisterCount: 1, + brothers: [ + { + name: "Rahul", + occupation: "Engineer", + maritalStatus: "Married", + haveChildrens: 1, + }, + ], + sisters: [ + { + name: "Rohini", + occupation: "Teacher", + maritalStatus: "Married", + haveChildrens: 0, + }, + ], + familyStatus: 3, + nativePlace: "Chennai", }; state.lifestyleDetails = { ...state.lifestyleDetails, - diet: "Veg", - // drinking: "No", - // smoking: "No", - hobbies: "Reading, Music", + diets: [1], + hobbies: [1, 3], + dob: "1995-05-01", + tob: "09:30", + placeOfBirth: "Chennai", + graha: { + 1: ["LAGNAM", "SURIYAN"], + 2: [], + 3: [], + 4: ["CHANDRAN", "CHEVVAI"], + 5: [], + 6: ["BUDHAN", "GURU"], + 7: [], + 8: ["SUKRAN", "SANI"], + 9: [], + 10: ["RAHU", "KETHU"], + 11: [], + 12: ["MANDHI"], + }, + amsam: { + 1: ["LAGNAM", "SURIYAN"], + 2: [], + 3: [], + 4: ["CHANDRAN", "CHEVVAI"], + 5: [], + 6: ["BUDHAN", "GURU"], + 7: [], + 8: ["SUKRAN", "SANI"], + 9: [], + 10: ["RAHU", "KETHU"], + 11: [], + 12: ["MANDHI"], + }, }; state.partnerPreferences = { ...state.partnerPreferences, - ageRange: "24-30", - religionCaste: "Hindu / Brahmin", - occupationPref: "IT / Software", - lifestylePref: "Non-smoker, Non-drinker", - qualificationPref: "Degree", - occupationText: "IT, Banking", - incomePref: "10-20 LPA", - locationPref: "Chennai, Bengaluru", + ageRange: 2, + castes: [1], + subCastes: [1], + occupations: [57], + educations: [14], + hobbies: [1, 3], + annualIncome: 1, + states: [31], + districts: [1], }; }, diff --git a/src/routes/AppRoutes.jsx b/src/routes/AppRoutes.jsx index 7fefe4c..84ff743 100644 --- a/src/routes/AppRoutes.jsx +++ b/src/routes/AppRoutes.jsx @@ -1,8 +1,21 @@ +import { Suspense } from 'react'; import { Route, Routes } from 'react-router-dom'; import UserRoutes from './UserRoutes'; import PublicRoutes from './PublicRoutes'; import ScrollToTop from '../components/common/ScrollToTop'; +import Skeleton from "../components/common/Skeleton"; +const RouteFallback = () => ( +
+
+ + + + + +
+
+); const AppRoutes = () => { return ( @@ -10,11 +23,12 @@ const AppRoutes = () => { {/* Wrap UserRoutes inside AuthProvider separately */} - - {UserRoutes()} - {PublicRoutes()} - - + }> + + {UserRoutes()} + {PublicRoutes()} + + ); }; diff --git a/src/routes/PublicRoutes.jsx b/src/routes/PublicRoutes.jsx index 1f45309..4c98607 100644 --- a/src/routes/PublicRoutes.jsx +++ b/src/routes/PublicRoutes.jsx @@ -1,13 +1,12 @@ +import { lazy } from "react"; import { Route } from "react-router-dom"; -import HomePage from "../pages/HomePage"; -import LandingLayout from "../layout/LandingLayout"; -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 HomePage = lazy(() => import("../pages/HomePage")); +const LoginPage = lazy(() => import("../pages/auth/LoginPage")); +const ForgotPasswordPage = lazy(() => import("../pages/auth/ForgotPasswordPage")); +const StepperForm = lazy(() => import("../feature/StepperForm")); +const NotFound = lazy(() => import("../pages/NotFound")); const PublicRoutes = () => { return ( <> diff --git a/src/routes/UserRoutes.jsx b/src/routes/UserRoutes.jsx index aa39aba..3ac4718 100644 --- a/src/routes/UserRoutes.jsx +++ b/src/routes/UserRoutes.jsx @@ -1,26 +1,28 @@ -import { Route, useNavigate } from "react-router-dom"; -import ProfileLayout from "../layout/ProfileLayout"; -import UserDashboardHome from "../pages/UserDashboardHome"; -import PoliciesPage from '../pages/PoliciesPage'; -import TermsAndConditionPage from '../pages/TermsAndCondition'; -import SafetyCentrePage from '../pages/SafetyCentre'; -import SubscriptionPlanPage from '../pages/SubscriptionPlan'; -import SubscriptionHistoryPage from '../pages/SubscriptionHistory' -import MatchesPage from "../pages/MatchesPage"; -import InterestSendPage from "../pages/InterestSendPage"; -import BlockedProfileListPage from "../pages/BlockedProfileListPage"; -import AccountSettingPage from "../pages/AccountSettingsPage"; -import ProfileDetailPage from "../pages/ProfileDetailPage"; -import ChatUI from "../pages/ChatPage"; -import HoroscopeGenerator from "../pages/HoroscoperGeneratePage"; -import ContactUsPage from "../pages/ContactUsPage"; -import ChangePasswordPage from "../components/auth/ChangePasswordForm"; -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"; +import { lazy } from "react"; +import { Route } from "react-router-dom"; +const ProfileLayout = lazy(() => import("../layout/ProfileLayout")); +const MatchesLayout = lazy(() => import("../layout/MatchesLayout")); + +const UserDashboardHome = lazy(() => import("../pages/UserDashboardHome")); +const PoliciesPage = lazy(() => import("../pages/PoliciesPage")); +const TermsAndConditionPage = lazy(() => import("../pages/TermsAndCondition")); +const SafetyCentrePage = lazy(() => import("../pages/SafetyCentre")); +const SubscriptionPlanPage = lazy(() => import("../pages/SubscriptionPlan")); +const SubscriptionHistoryPage = lazy(() => import("../pages/SubscriptionHistory")); +const MatchesPage = lazy(() => import("../pages/MatchesPage")); +const InterestSendPage = lazy(() => import("../pages/InterestSendPage")); +const BlockedProfileListPage = lazy(() => import("../pages/BlockedProfileListPage")); +const AccountSettingPage = lazy(() => import("../pages/AccountSettingsPage")); +const ProfileDetailPage = lazy(() => import("../pages/ProfileDetailPage")); +const ChatUI = lazy(() => import("../pages/ChatPage")); +const HoroscopeGenerator = lazy(() => import("../pages/HoroscoperGeneratePage")); +const ContactUsPage = lazy(() => import("../pages/ContactUsPage")); +const ChangePasswordPage = lazy(() => import("../components/auth/ChangePasswordForm")); +const StepperForm = lazy(() => import("../feature/StepperForm")); +const FilterForm = lazy(() => import("../feature/FilterForm")); +const ProfilePreviewPage = lazy(() => import("../feature/ProfilePreviewPage")); +const NotificationPage = lazy(() => import("../pages/NotificationPage")); +const ProfileCardDemo = lazy(() => import("../components/ui/ProfileCardDemo")); const UserRoutes = () => { diff --git a/src/utills/auth.js b/src/utills/auth.js index 5e44206..21edce4 100644 --- a/src/utills/auth.js +++ b/src/utills/auth.js @@ -1,3 +1,3 @@ export const isAuthenticated = () => { - return !!localStorage.getItem("token"); + return !!localStorage.getItem("access_token"); };