From eadb80fe59e59dff1518cc2186e590eced99aa2f Mon Sep 17 00:00:00 2001 From: Rajatava Das Date: Wed, 25 Feb 2026 00:24:41 +0530 Subject: [PATCH 1/2] Admin page/form/blog --- package-lock.json | 21 +- src/components/Core/Button.jsx | 12 +- src/components/Core/Input.jsx | 47 +- src/components/Core/styles/Core.module.scss | 74 ++- src/components/Form/FormField.jsx | 203 +++++- src/components/Form/Section.jsx | 27 +- src/components/Form/styles/Form.module.scss | 89 ++- .../Modals/Profile/Admin/PreviewForm.jsx | 337 +++++----- .../Modals/Profile/Admin/SectionModal.jsx | 95 ++- .../Profile/Admin/styles/Preview.module.scss | 432 ++++++++++--- .../Admin/Form/BlogForm/AddBlogForm.jsx | 291 ++++----- .../BlogForm/styles/AddBlogForm.module.scss | 584 +++++++++++------- .../Profile/Admin/Form/NewForm/NewForm.jsx | 478 +++++++------- .../Form/NewForm/styles/NewForm.module.scss | 278 +++++++-- 14 files changed, 1951 insertions(+), 1017 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b3f05a1..6d564da9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,7 +121,6 @@ "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz", "integrity": "sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.6", @@ -678,7 +677,6 @@ "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==", - "peer": true, "dependencies": { "@emotion/memoize": "^0.8.1" } @@ -692,7 +690,6 @@ "version": "11.11.4", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -733,7 +730,6 @@ "version": "11.11.5", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -1276,7 +1272,6 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", "hasInstallScript": true, - "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.5.2" }, @@ -2120,7 +2115,6 @@ "version": "5.15.20", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.20.tgz", "integrity": "sha512-tVq3l4qoXx/NxUgIx/x3lZiPn/5xDbdTE8VrLczNpfblLYZzlrbxA7kb9mI8NoBF6+w9WE9IrxWnKK5KlPI2bg==", - "peer": true, "dependencies": { "@babel/runtime": "^7.23.9", "@mui/base": "5.0.0-beta.40", @@ -3187,7 +3181,6 @@ "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -3374,7 +3367,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3987,8 +3979,7 @@ "node_modules/blurhash": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz", - "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==", - "peer": true + "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==" }, "node_modules/boxen": { "version": "7.1.1", @@ -4129,7 +4120,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -4839,8 +4829,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "peer": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/data-view-buffer": { "version": "1.0.1", @@ -5480,7 +5469,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -11901,7 +11889,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -12003,7 +11990,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -12251,7 +12237,6 @@ "version": "6.23.1", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", - "peer": true, "dependencies": { "@remix-run/router": "1.16.1", "react-router": "6.23.1" @@ -12919,7 +12904,6 @@ "version": "1.77.2", "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz", "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==", - "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -14211,7 +14195,6 @@ "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/src/components/Core/Button.jsx b/src/components/Core/Button.jsx index cca083b4..00316935 100644 --- a/src/components/Core/Button.jsx +++ b/src/components/Core/Button.jsx @@ -11,9 +11,15 @@ const Button = ({ ...rest }) => { const combinedStyle = { - color: variant === "primary" ? "#FF8A00" : "#fff", - backgroundColor: variant === "primary" ? "#2D2D2D" : "transparent", - borderColor: variant === "primary" ? "#2D2D2D" : "#fff", + color: "#fff", + background: + variant === "primary" + ? "linear-gradient(135deg, #FF8A00 0%, #d03e21 100%)" + : "transparent", + border: + variant === "primary" + ? "none" + : "1px solid rgba(255, 255, 255, 0.3)", opacity: disabled || isLoading ? 0.5 : 1, cursor: disabled || isLoading ? "not-allowed" : "pointer", ...style, diff --git a/src/components/Core/Input.jsx b/src/components/Core/Input.jsx index d4f883e9..b87cc375 100644 --- a/src/components/Core/Input.jsx +++ b/src/components/Core/Input.jsx @@ -57,26 +57,34 @@ const customStyles = { display: "flex", outline: "none", width: "99.5%", - fontSize: "12px", - backgroundColor: "transparent", - borderRadius: "4px", + fontSize: "13px", + backgroundColor: "rgba(255, 255, 255, 0.03)", + borderRadius: "8px", color: "#fff", marginBottom: "0", - maxHeight: "40px", + maxHeight: "42px", marginLeft: "8px", marginRight: "8px", marginTop: "4px", position: "relative", - border: "1px solid rgba(211, 211, 211, 0.5)", + border: "1px solid rgba(211, 211, 211, 0.25)", boxShadow: "none", + transition: "all 0.25s cubic-bezier(0.4, 0, 0.2, 1)", "&:hover": { - borderColor: "#fff !important", + borderColor: "rgba(255, 138, 0, 0.4)", + backgroundColor: "rgba(255, 255, 255, 0.05)", }, }), menu: (provided) => ({ ...provided, width: "99.5%", marginLeft: "8px", + backgroundColor: "#1e1e1e", + borderRadius: "10px", + border: "1px solid rgba(255, 138, 0, 0.12)", + boxShadow: "0 12px 40px rgba(0, 0, 0, 0.5)", + overflow: "hidden", + padding: "4px", }), menuPortal: (provided) => ({ ...provided, zIndex: 111 }), placeholder: (provided) => ({ @@ -84,25 +92,28 @@ const customStyles = { display: "flex", alignItems: "center", marginTop: "-7px", + color: "rgba(255, 255, 255, 0.35)", + fontSize: "12px", }), option: (provided, state) => ({ ...provided, - color: state.isSelected ? "#FF8A00" : "#2D2D2D", - backgroundColor: state.isSelected ? "#2D2D2D" : "#fff", + color: state.isSelected ? "#FF8A00" : "rgba(255, 255, 255, 0.85)", + backgroundColor: state.isSelected + ? "rgba(255, 138, 0, 0.1)" + : "transparent", cursor: "pointer", - width: "99%", + width: "100%", border: "none", - margin: "0 auto", - borderRadius: "4px", + borderRadius: "6px", + padding: "8px 12px", + fontSize: "13px", + transition: "all 0.15s ease", "&:hover": { - transition: "ease-in-out 0.3s", - backgroundColor: "#2D2D2D", + backgroundColor: "rgba(255, 138, 0, 0.08)", color: "#FF8A00", - margin: "2px auto", }, "&:active": { - backgroundColor: "#2D2D2D", - color: "#FF8A00", + backgroundColor: "rgba(255, 138, 0, 0.15)", }, }), indicatorSeparator: (provided) => ({ @@ -115,7 +126,7 @@ const customStyles = { display: "flex", alignItems: "center", marginTop: "-7px", - fontSize:"larger" + fontSize: "13px", }), }; @@ -523,7 +534,7 @@ const Input = (props) => { className={`${styles.containerInput} ${containerClassName}`} style={ containerStyle || { - marginTop: type === "select" ? "0" : "8px", + marginTop: "8px", } } > diff --git a/src/components/Core/styles/Core.module.scss b/src/components/Core/styles/Core.module.scss index f6f8cc94..abb663ad 100644 --- a/src/components/Core/styles/Core.module.scss +++ b/src/components/Core/styles/Core.module.scss @@ -5,13 +5,41 @@ margin-top: 20px; outline: none; border: none; - padding: 8px 16px; - font-size: 12px; - background-color: transparent; - border: 1px solid rgba(211, 211, 211, 0.5); + padding: 10px 22px; + font-size: 13px; + background: linear-gradient(135deg, #FF8A00 0%, #d03e21 100%); + color: #fff; cursor: pointer; - border-radius: 4px; - font-weight: 500; + border-radius: 8px; + font-weight: 600; + letter-spacing: 0.02em; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 2px 8px rgba(255, 138, 0, 0.15); + position: relative; + overflow: hidden; +} + +.main_Button::before { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, transparent 50%); + opacity: 0; + transition: opacity 0.25s ease; +} + +.main_Button:hover { + transform: translateY(-1px); + box-shadow: 0 4px 16px rgba(255, 138, 0, 0.3); +} + +.main_Button:hover::before { + opacity: 1; +} + +.main_Button:active { + transform: translateY(0px) scale(0.98); + box-shadow: 0 1px 4px rgba(255, 138, 0, 0.2); } .h1 { @@ -58,24 +86,38 @@ position: relative; width: auto; } + .input { display: flex; outline: none; border: none; - padding: 10px; - font-size: 12px; + padding: 11px 12px; + font-size: 13px; margin: 6px; margin-bottom: 10px; - background-color: transparent; - border: 1px solid rgba(211, 211, 211, 0.5) !important; - border-radius: 4px; + background-color: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(211, 211, 211, 0.25) !important; + border-radius: 8px; color: #fff; position: relative; width: auto; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); } + +.input::placeholder { + color: rgba(255, 255, 255, 0.35); + font-size: 12px; +} + .input:hover { - border: 1px solid #fff !important; - transition: 0.3s ease-in-out; + border: 1px solid rgba(255, 138, 0, 0.4) !important; + background-color: rgba(255, 255, 255, 0.05); +} + +.input:focus { + border: 1px solid #FF8A00 !important; + box-shadow: 0 0 0 3px rgba(255, 138, 0, 0.12); + background-color: rgba(255, 255, 255, 0.05); } .inputTxtArea { @@ -83,23 +125,27 @@ width: 380px; resize: none; } + .inputSelect { color: #fff; width: 380px !important; } + .inputSelect option { color: black; } + .inputDate { padding: 6px !important; width: auto !important; height: 40px !important; position: relative; } + input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; -moz-appearance: none; appearance: none; margin: 0; -} +} \ No newline at end of file diff --git a/src/components/Form/FormField.jsx b/src/components/Form/FormField.jsx index 8bfa5f62..eb3143df 100644 --- a/src/components/Form/FormField.jsx +++ b/src/components/Form/FormField.jsx @@ -88,9 +88,9 @@ function FormField(props) { ? property === "isRequired" ? value : value - .split(",") - .map((val) => val.trim()) - .filter(Boolean) + .split(",") + .map((val) => val.trim()) + .filter(Boolean) : []; if (property === "value") { @@ -99,9 +99,8 @@ function FormField(props) { type: "length", value: values.length > 1 ? 1 : 50, operator: "<=", - message: `${field.name} should be less than ${ - values.length > 1 ? 1 : 200 - } characters long`, + message: `${field.name} should be less than ${values.length > 1 ? 1 : 200 + } characters long`, }; newFields[fieldIndex].validations = [fieldValidation]; @@ -174,29 +173,177 @@ function FormField(props) { options={fieldTypes} onChange={(value) => handleChangeValue(value, "type")} /> - + + {(field.value ? field.value.split(",").filter(Boolean) : [""]).map( + (opt, idx, arr) => ( +
+ + {idx + 1}. + + + (e.target.style.borderColor = "#FF8A00") + } + onBlur={(e) => + (e.target.style.borderColor = + "rgba(211,211,211,0.25)") + } + onChange={(e) => { + const newOpts = [ + ...arr, + ]; + newOpts[idx] = e.target.value; + handleChangeValue( + newOpts.join(","), + "value" + ); + }} + /> + {arr.length > 1 && ( + { + const newOpts = arr.filter( + (_, i) => i !== idx + ); + handleChangeValue( + newOpts.join(","), + "value" + ); + }} + style={{ + cursor: "pointer", + color: "rgba(255,255,255,0.3)", + fontSize: "18px", + lineHeight: 1, + padding: "2px 4px", + borderRadius: "4px", + transition: "all 0.15s ease", + }} + title="Remove option" + onMouseEnter={(e) => { + e.target.style.color = "#ff4444"; + e.target.style.background = + "rgba(255,68,68,0.1)"; + }} + onMouseLeave={(e) => { + e.target.style.color = + "rgba(255,255,255,0.3)"; + e.target.style.background = "transparent"; + }} + > + × + + )} +
+ ) + )} +
{ + const current = field.value || ""; + const opts = current ? current.split(",") : []; + opts.push(" "); + handleChangeValue(opts.join(","), "value"); + }} + style={{ + display: "flex", + alignItems: "center", + gap: "6px", + marginLeft: "6px", + marginTop: "4px", + padding: "6px 10px", + cursor: "pointer", + color: "#FF8A00", + fontSize: "12px", + fontWeight: "600", + borderRadius: "6px", + transition: "background 0.15s ease", + width: "fit-content", + }} + onMouseEnter={(e) => + (e.target.style.background = + "rgba(255,138,0,0.08)") + } + onMouseLeave={(e) => + (e.target.style.background = "transparent") + } + > + + + + + Add Option +
+ + ) : ( + { - handleChangeValue(e.target.value, "value"); - }} - /> + ? "file" + : "text" + } + disabled={ + field.type === "file" || field.type === "image" + } + style={{ + cursor: + field.type === "file" || field.type === "image" + ? "not-allowed" + : "text", + }} + className={styles.fieldInput} + containerClassName={styles.containerInput} + onChange={(e) => { + handleChangeValue(e.target.value, "value"); + }} + /> + )}
{ {section.name} {isIncludesOptions().length > 0 && ( - setshowValidations(!showValidations)} - /> + title="Configure section routing" + style={{ + display: "flex", + alignItems: "center", + gap: "6px", + padding: "6px 14px", + borderRadius: "8px", + background: showValidations + ? "linear-gradient(135deg, #FF8A00, #d03e21)" + : "rgba(255, 138, 0, 0.1)", + border: "1px solid rgba(255, 138, 0, 0.35)", + cursor: "pointer", + transition: "all 0.25s ease", + fontSize: "12px", + fontWeight: "600", + color: showValidations ? "#fff" : "#FF8A00", + }} + > + + Redirect +
)} {showDescription ? ( diff --git a/src/components/Form/styles/Form.module.scss b/src/components/Form/styles/Form.module.scss index a264bbb6..cc5981fd 100644 --- a/src/components/Form/styles/Form.module.scss +++ b/src/components/Form/styles/Form.module.scss @@ -4,10 +4,12 @@ margin-top: 1.6em; width: 86%; } + .formInput { width: 90% !important; margin-bottom: 1.4em; } + .formInputTxtArea { width: 90% !important; height: 31vh !important; @@ -17,97 +19,130 @@ display: flex; flex-direction: column; width: 86%; - padding: 1em; - border-radius: 8px; - border: 0.5px solid transparent; + padding: 1.2em 1.4em; + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.06); + border-left: 3px solid rgba(255, 138, 0, 0.35); position: relative; - background-color: rgba(128, 127, 126, 0.066); - margin-bottom: 1em; + background: rgba(255, 255, 255, 0.02); + margin-bottom: 1.2em; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } + .disabledSec { position: absolute; top: 0; left: 0; right: 0; bottom: 0; - border-radius: 8px; - background-color: #fd8e100e; + border-radius: 12px; + background-color: rgba(253, 142, 16, 0.03); z-index: 10; opacity: 0.8; cursor: not-allowed; } + .formFieldContainer:hover { - border: 0.5px solid #ff88008c; - transition: 0.5s ease-in-out; -} -.formFieldContainer:active { - border: 0.5px solid #ff88008c; - transition: 0.5s ease-in-out; + border-color: rgba(255, 138, 0, 0.2); + border-left-color: #FF8A00; + background: rgba(255, 255, 255, 0.035); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); } + .mainFieldForm { display: flex; flex-direction: row; align-items: center; position: relative; width: 100%; - margin-bottom: 8px; + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px solid rgba(255, 255, 255, 0.04); } + +.mainFieldForm:last-child { + border-bottom: none; + margin-bottom: 0; + padding-bottom: 0; +} + .fieldInput { width: 90% !important; } + .containerInput { display: flex; flex-direction: column; width: 30%; } + .sectionValidation { position: absolute; bottom: 0px; right: 50px; - background-color: rgb(41, 41, 41); - border-radius: 4px; + background: rgba(30, 30, 30, 0.98); + border-radius: 12px; width: 500px; max-height: 424px; z-index: 1800 !important; - padding: 1em; - border: 1px solid #b8b7b78c; + padding: 1.2em; + border: 1px solid rgba(255, 138, 0, 0.15); margin-bottom: 2.4em; overflow-y: auto; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4); + backdrop-filter: blur(8px); } + .sectionValidation::-webkit-scrollbar { - width: 0px; + width: 4px; } + +.sectionValidation::-webkit-scrollbar-thumb { + background: rgba(255, 138, 0, 0.3); + border-radius: 4px; +} + .popField { position: absolute; bottom: -120%; right: 0; - background-color: rgb(41, 41, 41); - border-radius: 4px; + background: rgba(30, 30, 30, 0.98); + border-radius: 12px; width: 600px; max-height: 424px; z-index: 1500 !important; - padding: 1em; - border: 1px solid #b8b7b78c; + padding: 1.2em; + border: 1px solid rgba(255, 138, 0, 0.15); margin-bottom: 2.4em; overflow-y: auto; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4); } + .popField::-webkit-scrollbar { - width: 0px; + width: 4px; } + +.popField::-webkit-scrollbar-thumb { + background: rgba(255, 138, 0, 0.3); + border-radius: 4px; +} + .popFieldInpt { display: flex; width: 100%; align-items: center; - margin-bottom: 4px; + margin-bottom: 6px; } + .popFieldInptContainer { display: flex; flex-direction: column; width: 50%; } + .bindInptContainer { display: flex; flex-direction: column; width: 100%; - margin-bottom: 8px; -} + margin-bottom: 10px; +} \ No newline at end of file diff --git a/src/features/Modals/Profile/Admin/PreviewForm.jsx b/src/features/Modals/Profile/Admin/PreviewForm.jsx index 1d4ce420..4abd05c2 100644 --- a/src/features/Modals/Profile/Admin/PreviewForm.jsx +++ b/src/features/Modals/Profile/Admin/PreviewForm.jsx @@ -136,6 +136,24 @@ const PreviewForm = ({ }; }); + // Collect all section IDs that are targets of matched field validations + const enabledTargetIds = new Set(); + updatedSections.forEach((section) => { + const fieldValidations = section?.validations?.filter( + (valid) => valid.field_id + ); + if (fieldValidations && fieldValidations.length > 0) { + fieldValidations.forEach((valid) => { + const isMatch = section.fields.some((fld) => { + return fld.onChangeValue === valid.values; + }); + if (isMatch && valid.onNext) { + enabledTargetIds.add(valid.onNext); + } + }); + } + }); + const newSections = updatedSections.map((section) => { const isHavingFieldValidations = section?.validations?.filter( (valid) => valid.field_id @@ -150,11 +168,15 @@ const PreviewForm = ({ }); } + // A section is enabled if: + // 1. It has matched field validations and a next section, OR + // 2. It is the target of a matched validation from another section const nextSection = getOutboundList(data, section._id)?.nextSection; + const isTarget = enabledTargetIds.has(section._id); return { ...section, - isDisabled: !(isMatched && nextSection), + isDisabled: !(isMatched && nextSection) && !isTarget, }; }); @@ -485,103 +507,103 @@ const PreviewForm = ({ }; const renderPaymentScreen = () => { - const { eventType, receiverDetails, eventAmount } = formData; + const { eventType, receiverDetails, eventAmount } = formData; - const handleDownloadQR = async () => { - try { - let imageUrl = - typeof receiverDetails.media === "string" - ? receiverDetails.media - : URL.createObjectURL(receiverDetails.media); + const handleDownloadQR = async () => { + try { + let imageUrl = + typeof receiverDetails.media === "string" + ? receiverDetails.media + : URL.createObjectURL(receiverDetails.media); - let blobUrl = imageUrl; + let blobUrl = imageUrl; - if (typeof receiverDetails.media === "string") { - const response = await fetch(imageUrl); - const blob = await response.blob(); - blobUrl = URL.createObjectURL(blob); - } + if (typeof receiverDetails.media === "string") { + const response = await fetch(imageUrl); + const blob = await response.blob(); + blobUrl = URL.createObjectURL(blob); + } - const link = document.createElement("a"); - link.href = blobUrl; - link.download = "qr-code.png"; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); + const link = document.createElement("a"); + link.href = blobUrl; + link.download = "qr-code.png"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); - if (typeof receiverDetails.media !== "string") { - URL.revokeObjectURL(blobUrl); + if (typeof receiverDetails.media !== "string") { + URL.revokeObjectURL(blobUrl); + } + } catch (error) { + console.error("Error downloading QR code:", error); + alert("Failed to download QR code."); } - } catch (error) { - console.error("Error downloading QR code:", error); - alert("Failed to download QR code."); - } - }; - - const handleCopyUPIID = () => { - if (receiverDetails.upi) { - navigator.clipboard.writeText(receiverDetails.upi) - .then(() => { - alert("UPI ID copied to clipboard!"); - }) - .catch(() => { - alert("Failed to copy UPI ID."); - }); - } - }; - - if (eventType === "Paid" && currentSection.name === "Payment Details") { - return ( -
- {receiverDetails.media && ( - {"QR-Code"} - )} + }; - {/* ✅ Download & Copy Buttons */} -
- - -
+ const handleCopyUPIID = () => { + if (receiverDetails.upi) { + navigator.clipboard.writeText(receiverDetails.upi) + .then(() => { + alert("UPI ID copied to clipboard!"); + }) + .catch(() => { + alert("Failed to copy UPI ID."); + }); + } + }; -

- Make the payment of{" "} - ₹{eventAmount}{" "} - using QR-Code or Pay using UPI ID:{" "} - {receiverDetails.upi} (No Refund Policy) -

-
- ); - } + {receiverDetails.media && ( + {"QR-Code"} + )} - return null; -}; + {/* ✅ Download & Copy Buttons */} +
+ + +
+ +

+ Make the payment of{" "} + ₹{eventAmount}{" "} + using QR-Code or Pay using UPI ID:{" "} + {receiverDetails.upi} (No Refund Policy) +

+ + ); + } + + return null; + }; return ( @@ -602,85 +624,97 @@ const PreviewForm = ({ ))} - +

{eventData?.eventTitle || "Preview Event"} - +

+ {/* Progress Stepper */} + {data && data.length > 1 && ( +
+ {data + .filter((sec) => !sec.isDomainSection || + (currentSection?.isDomainSection && sec._id === currentSection._id) || + isCompleted.includes(sec._id)) + .map((section, index, arr) => ( +
+
+ {index < arr.length - 1 && ( +
+ )} +
+ ))} +
+ )} {isLoading ? ( ) : !isCompleted.includes("Submitted") ? ( -
-
- +
+
+
{currentSection.name} - - - {currentSection.description} - +
+ {currentSection.description && ( +
+ {currentSection.description} +
+ )}
{renderPaymentScreen()}
-
- {inboundList() && inboundList().backSection && ( - - )} - +
+ {(() => { + const navigation = inboundList(); + return ( + <> + {navigation && navigation.backSection && ( + + )} + + + ); + })()}
) : isSuccess ? ( -
+
Complete
) : ( -
+
{ const getInputFields = (field) => { const valiedTypes = ["checkbox", "radio"]; if (valiedTypes.includes(field.type)) { - const valueToArray = field.value.split(","); - return valueToArray.map((value, index) => ( -
- handleChange(field, e.target.value)} - /> + const valueToArray = field.value.split(",").map(v => v.trim()).filter(Boolean); + return ( +
+ {valueToArray.map((value, index) => { + const isChecked = field.type === "checkbox" + ? (field.onChangeValue || []).includes(value) + : field.onChangeValue === value; + + return ( + + ); + })}
- )); + ); } }; @@ -77,8 +126,8 @@ const Section = ({ section, handleChange }) => { options={ field.type === "select" ? field.value.split(",").map((option) => { - return { value: option, label: option }; - }) + return { value: option, label: option }; + }) : [] } /> @@ -96,7 +145,7 @@ const Section = ({ section, handleChange }) => { section.fields.map( (field) => field !== undefined && ( -
+
{field.type !== "checkbox" && field.type !== "radio" ? ( { options={ field.type === "select" ? field.value.split(",").map((option) => { - return { value: option, label: option }; - }) + return { value: option, label: option }; + }) : [] } /> diff --git a/src/features/Modals/Profile/Admin/styles/Preview.module.scss b/src/features/Modals/Profile/Admin/styles/Preview.module.scss index 3b5dd216..7b70be5f 100644 --- a/src/features/Modals/Profile/Admin/styles/Preview.module.scss +++ b/src/features/Modals/Profile/Admin/styles/Preview.module.scss @@ -1,3 +1,4 @@ +// ===== Main overlay ===== .mainPreview { display: flex; flex-direction: column; @@ -6,24 +7,25 @@ right: 0; bottom: 0; position: fixed; - background: rgba(7, 7, 7, 0.5); + background: rgba(0, 0, 0, 0.65); z-index: 50; - backdrop-filter: blur(2px); + backdrop-filter: blur(12px); overflow: hidden; } - - +// ===== Form modal wrapper ===== .previewContainerWrapper { - background: linear-gradient( - 90deg, - rgba(32, 32, 32, 0.95) -11.52%, - rgba(37, 37, 37, 0.95) 106.29% - ); - border-radius: 1.26863rem; - backdrop-filter: blur(4px); - border: 1.2px solid rgba(214, 214, 214, 0.81); - width: 35rem; + background: linear-gradient(160deg, + rgba(22, 22, 26, 0.98) 0%, + rgba(32, 32, 38, 0.98) 100%); + border-radius: 22px; + backdrop-filter: blur(16px); + border: 1px solid rgba(255, 138, 0, 0.1); + box-shadow: + 0 32px 100px rgba(0, 0, 0, 0.6), + 0 0 0 1px rgba(255, 255, 255, 0.04) inset, + 0 0 60px rgba(255, 138, 0, 0.03); + width: 40rem; height: 90%; margin: auto; z-index: 100; @@ -31,120 +33,398 @@ display: flex; justify-content: center; align-items: center; + position: relative; } +// ===== Scrollable content ===== .previewContainer { width: 100%; height: 100%; - padding: 2rem; + padding: 2.2rem 2.5rem; overflow-y: auto; - overflow-x: hidden; /* Added to prevent horizontal overflow */ + overflow-x: hidden; } .previewContainer::-webkit-scrollbar { - width: 6px; + width: 4px; +} + +.previewContainer::-webkit-scrollbar-track { + background: transparent; } .previewContainer::-webkit-scrollbar-thumb { - background: #888; + background: rgba(255, 138, 0, 0.2); border-radius: 10px; } .previewContainer::-webkit-scrollbar-thumb:hover { - background: #555; + background: rgba(255, 138, 0, 0.45); } - -.previewContainer > * { - padding-right: 1rem; +.previewContainer>* { + padding-right: 0.5rem; } - -.closeBtn{ +// ===== Close button ===== +.closeBtn { position: absolute; - width: 100%; - right: 3px; + width: 38px; + height: 38px; display: flex; - justify-content: flex-end; - color: #fff; + justify-content: center; + align-items: center; + color: rgba(255, 255, 255, 0.5); cursor: pointer; - z-index: 5; - top: 1rem; - right: 1rem; + z-index: 10; + top: 1.2rem; + right: 1.2rem; + border-radius: 50%; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.06); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -.closeBtn:hover{ - color:#FF8A00; - transition: .2s linear; +.closeBtn:hover { + color: #FF8A00; + background: rgba(255, 138, 0, 0.1); + border-color: rgba(255, 138, 0, 0.2); + transform: rotate(90deg); } -.no-scroll { +.noScroll { overflow: hidden; } +// ===== Progress stepper ===== +.progressStepper { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 2rem; + padding: 0.8rem 1.2rem; + gap: 0; + flex-wrap: wrap; + background: rgba(255, 255, 255, 0.02); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.04); +} + +.stepItem { + display: flex; + align-items: center; + gap: 0; +} + +.stepDot { + width: 10px; + height: 10px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.08); + border: 2px solid rgba(255, 255, 255, 0.15); + transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1); + flex-shrink: 0; +} + +.stepDotCompleted { + background: #FF8A00; + border-color: #FF8A00; + box-shadow: 0 0 10px rgba(255, 138, 0, 0.5); +} + +.stepDotActive { + background: transparent; + border-color: #FF8A00; + box-shadow: 0 0 14px rgba(255, 138, 0, 0.35); + width: 12px; + height: 12px; + animation: activePulse 2s ease-in-out infinite; +} + +@keyframes activePulse { + + 0%, + 100% { + box-shadow: 0 0 10px rgba(255, 138, 0, 0.3); + } + + 50% { + box-shadow: 0 0 18px rgba(255, 138, 0, 0.6); + } +} + +.stepLine { + width: 28px; + height: 2px; + background: rgba(255, 255, 255, 0.08); + transition: background 0.4s ease; +} + +.stepLineCompleted { + background: linear-gradient(90deg, #FF8A00, rgba(255, 138, 0, 0.35)); +} + +// ===== Form title ===== +.formTitle { + text-align: center; + margin-bottom: 1.5rem; + font-size: 1.7em; + font-weight: 700; + background: linear-gradient(135deg, #fff 20%, #FF8A00 80%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + letter-spacing: -0.02em; + text-shadow: 0 0 40px rgba(255, 138, 0, 0.1); +} + +// ===== Section header ===== +.sectionHeader { + margin-bottom: 1.4rem; + padding-bottom: 1rem; + border-bottom: 1px solid rgba(255, 138, 0, 0.1); + position: relative; + + &::after { + content: ''; + position: absolute; + bottom: -1px; + left: 0; + width: 60px; + height: 2px; + background: linear-gradient(90deg, #FF8A00, transparent); + border-radius: 1px; + } +} + +.sectionName { + font-size: 1.2em; + font-weight: 700; + color: #fff; + margin-bottom: 0.35em; + letter-spacing: -0.01em; +} + +.sectionDescription { + font-size: 0.82em; + opacity: 0.45; + color: #fff; + line-height: 1.6; + font-weight: 400; +} + +// ===== Form fields container ===== .formFieldContainer { display: flex; flex-direction: row; flex-wrap: wrap; - // justify-content: center; - // justify-content: space-evenly; - column-gap: 3rem; + column-gap: 1.8rem; width: 100%; - padding: 1em; - padding-left: 2rem; - row-gap: 1rem; - border-radius: 8px; - border: 0.5px solid transparent; - background-color: rgba(128, 127, 126, 0.066); - margin-bottom: 1em; + padding: 1.5em 1.6em; + row-gap: 0.6rem; + border-radius: 14px; + border: 1px solid rgba(255, 255, 255, 0.06); + background: linear-gradient(170deg, + rgba(255, 255, 255, 0.025) 0%, + rgba(255, 138, 0, 0.01) 100%); + margin-bottom: 1.4em; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15); + align-items: flex-start; + + // Force every direct child field div to fill its flex space + >div { + display: flex; + flex-direction: column; + + // Force the Input component's wrapper to fill width + >div { + width: 100% !important; + } + + input, + select, + textarea { + width: 100% !important; + box-sizing: border-box; + } + + select { + margin-top: 12px; + } + } + + // Style input fields within the form + input[type="text"], + input[type="number"], + textarea { + transition: all 0.25s ease; + + &:focus { + border-color: rgba(255, 138, 0, 0.5) !important; + box-shadow: 0 0 0 3px rgba(255, 138, 0, 0.08); + } + } + + // Style radio and checkbox labels + label { + transition: color 0.2s ease; + } + + // Radio/checkbox input styling + input[type="radio"], + input[type="checkbox"] { + accent-color: #FF8A00; + cursor: pointer; + width: auto !important; + } } + .formFieldContainer:hover { - border: 0.5px solid #ff88008c; - transition: 0.5s ease-in-out; + border-color: rgba(255, 138, 0, 0.12); + background: linear-gradient(170deg, + rgba(255, 255, 255, 0.035) 0%, + rgba(255, 138, 0, 0.015) 100%); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); } -.formFieldContainer:active { - border: 0.5px solid #ff88008c; - transition: 0.5s ease-in-out; + +// ===== Section content animation ===== +.sectionContent { + animation: fadeSlideIn 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; } -@media (min-width: 481px) and (max-width:800px){ - .previewContainer{ - height: 100%; - width: 100%; +@keyframes fadeSlideIn { + from { + opacity: 0; + transform: translateY(16px); } -} -@media (max-width: 480px){ - .previewContainerWrapper{ - height: 70%; - width: 90%; + to { + opacity: 1; + transform: translateY(0); } - .previewContainer{ - height: 100%; - width: 100%; - margin-left: 1rem; - padding: 1rem; +} + +// ===== Button area ===== +.buttonGroup { + display: flex; + flex-direction: row; + justify-content: center; + gap: 14px; + margin-top: 1.6rem; + padding-top: 0.4rem; + + button { + min-width: 120px; + padding: 10px 28px; + border-radius: 10px; + font-weight: 600; + font-size: 0.9em; + letter-spacing: 0.3px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 6px 24px rgba(255, 138, 0, 0.2); } - .closeBtn{ - width: 80%; + &:active { + transform: translateY(0); } + } +} + +// ===== Team container ===== +.teamContainer { + width: 100%; +} +.teamField { + width: 30%; } -@media (max-width: 380px) { - .previewContainerWrapper{ - height: 70%; +// ===== Success screen ===== +.successScreen { + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + animation: fadeSlideIn 0.5s ease forwards; +} + +// ===== Responsive ===== +@media (min-width: 481px) and (max-width: 800px) { + .previewContainerWrapper { width: 90%; + border-radius: 18px; + } + + .previewContainer { + height: 100%; + width: 100%; + padding: 1.8rem; + } +} + +@media (max-width: 480px) { + .previewContainerWrapper { + height: 85%; + width: 95%; + border-radius: 16px; + } + + .previewContainer { + height: 100%; + width: 100%; + padding: 1.2rem; + } + + .closeBtn { + top: 0.6rem; + right: 0.6rem; + width: 32px; + height: 32px; + } + + .progressStepper { + margin-bottom: 1.2rem; + padding: 0.6rem 0.8rem; + } + + .stepLine { + width: 14px; + } + + .formFieldContainer { + padding: 1em; + } + + .formTitle { + font-size: 1.3em; } - .previewContainer{ - height: 100%; - width: 100%; - margin-left: 1rem; - } - .formFieldContainer{ - width: 115%; - margin-left: -1rem; + .buttonGroup { + button { + min-width: 100px; + padding: 9px 20px; } + } +} + +@media (max-width: 380px) { + .previewContainerWrapper { + height: 80%; + width: 95%; + } + + .previewContainer { + padding: 1rem; + } + + .formFieldContainer { + width: 100%; + } } \ No newline at end of file diff --git a/src/sections/Profile/Admin/Form/BlogForm/AddBlogForm.jsx b/src/sections/Profile/Admin/Form/BlogForm/AddBlogForm.jsx index aa8daf49..bd1e6740 100644 --- a/src/sections/Profile/Admin/Form/BlogForm/AddBlogForm.jsx +++ b/src/sections/Profile/Admin/Form/BlogForm/AddBlogForm.jsx @@ -456,7 +456,7 @@ function NewBlogForm() { window.dispatchEvent(new Event('blog-updated')); } - + } catch (error) { console.error("Error refreshing blogs after update:", error); } @@ -493,7 +493,7 @@ function NewBlogForm() { try { setIsLoading(true); const response = await api.post("/api/gemini/summary", { - mediumLink: data.mediumLink + mediumLink: data.mediumLink }); const result = response.data; @@ -543,7 +543,7 @@ function NewBlogForm() { setIsLoading(true); const response = await api.post("/api/gemini/autofill", { - mediumLink: data.mediumLink + mediumLink: data.mediumLink }); const result = response.data; @@ -604,29 +604,22 @@ function NewBlogForm() { }; return ( -
+

- New Blog + {isEditing ? "Edit" : "New"} Blog

-
-
+
+
setisVisibility(!isVisibility)} + > {isVisibility ? ( - setisVisibility(!isVisibility)} - /> + ) : ( - setisVisibility(!isVisibility)} - /> + )}
@@ -637,36 +630,22 @@ function NewBlogForm() {
{isVisibility && ( -
-
-