diff --git a/apps/OpenSign/src/pages/UserProfile.js b/apps/OpenSign/src/pages/UserProfile.js index eaeafffaa..b95d60312 100644 --- a/apps/OpenSign/src/pages/UserProfile.js +++ b/apps/OpenSign/src/pages/UserProfile.js @@ -8,9 +8,10 @@ import sanitizeFileName from "../primitives/sanitizeFileName"; import axios from "axios"; import PremiumAlertHeader from "../primitives/PremiumAlertHeader"; import Tooltip from "../primitives/Tooltip"; -import { isEnableSubscription } from "../constant/const"; +import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const"; import { checkIsSubscribed } from "../constant/Utils"; import Upgrade from "../primitives/Upgrade"; +import ModalUi from "../primitives/ModalUi"; function UserProfile() { const navigate = useNavigate(); @@ -32,12 +33,16 @@ function UserProfile() { const [jobTitle, setJobTitle] = useState( extendUser && extendUser?.[0]?.JobTitle ); - + const [isVerifyModal, setIsVerifyModal] = useState(false); + const [otp, setOtp] = useState(""); + const [otpLoader, setOtpLoader] = useState(false); + const [isEmailVerified, setIsEmailVerified] = useState(false); useEffect(() => { getUserDetail(); }, []); const getUserDetail = async () => { + setIsLoader(true); const extClass = localStorage.getItem("Extand_Class"); const jsonSender = JSON.parse(extClass); const HeaderDocId = jsonSender[0]?.HeaderDocId; @@ -48,6 +53,9 @@ function UserProfile() { if (HeaderDocId) { setIsDisableDocId(HeaderDocId); } + const isEmailVerified = Parse.User.current()?.attributes?.emailVerified; + setIsEmailVerified(isEmailVerified); + setIsLoader(false); }; const handleSubmit = async (e) => { e.preventDefault(); @@ -177,6 +185,50 @@ function UserProfile() { const handleDisableDocId = () => { setIsDisableDocId((prevChecked) => !prevChecked); }; + const handleVerifyBtn = async () => { + setIsVerifyModal(true); + await handleSendOTP(); + }; + const handleCloseVerifyModal = async () => { + setIsVerifyModal(false); + }; + const handleSendOTP = async () => { + try { + let url = `${parseBaseUrl}functions/SendOTPMailV1/`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId + }; + const body = { email: Parse.User.current().getEmail() }; + await axios.post(url, body, { headers: headers }); + } catch (error) { + alert(error.message); + } + }; + + const handleVerifyEmail = async (e) => { + e.preventDefault(); + setOtpLoader(true); + try { + const resEmail = await Parse.Cloud.run("verifyemail", { + otp: otp, + email: Parse.User.current().getEmail() + }); + alert(resEmail.message); + setIsVerifyModal(false); + } catch (error) { + alert(error.message); + } finally { + setOtpLoader(false); + } + }; + const handleReset = async (e) => { + e.preventDefault(); + setOtpLoader(true); + await handleSendOTP(); + setOtpLoader(false); + alert("OTP sent on you email"); + }; return ( @@ -310,9 +362,20 @@ function UserProfile() { <li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all"> <span className="font-semibold">Is Email verified:</span>{" "} <span> - {UserProfile && UserProfile.emailVerified - ? "Verified" - : "Not verified"} + {isEmailVerified ? ( + "Verified" + ) : ( + <span> + Not verified( + <span + onClick={() => handleVerifyBtn()} + className="hover:underline text-blue-600 cursor-pointer" + > + verify + </span> + ) + </span> + )} </span> </li> <li className="border-y-[1px] border-gray-300 break-all"> @@ -399,6 +462,59 @@ function UserProfile() { </button> </div> </div> + + {isVerifyModal && ( + <ModalUi + isOpen + title={"OTP verification"} + handleClose={handleCloseVerifyModal} + > + {otpLoader ? ( + <div + style={{ + height: "150px", + display: "flex", + alignItems: "center", + justifyContent: "center" + }} + > + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + ) : ( + <form onSubmit={(e) => handleVerifyEmail(e)}> + <div className="px-6 py-3"> + <label className="mb-2">Enter OTP</label> + <input + type="tel" + pattern="[0-9]{4}" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + placeholder="Enter OTP sent on mail" + value={otp} + onChange={(e) => setOtp(e.target.value)} + /> + </div> + <hr /> + <div className="px-6 my-3"> + <button type="submit" className={submitBtn}> + Verify + </button> + <button + className={`${rejectBtn} ml-2`} + onClick={(e) => handleReset(e)} + > + Resend + </button> + </div> + </form> + )} + </ModalUi> + )} </div> )} </React.Fragment> diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index 1833e2d30..230ee17c3 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -33,7 +33,8 @@ import getInvoices from './parsefunction/getInvoices.js'; import getPayments from './parsefunction/getPayments.js'; import getSubscriptions from './parsefunction/getSubscriptions.js'; import TenantAterFind from './parsefunction/TenantAfterFind.js'; -import saveSubscriptio from './parsefunction/saveSubscription.js'; +import saveSubscription from './parsefunction/saveSubscription.js'; +import VerifyEmail from './parsefunction/VerifyEmail.js'; Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('UserGroups', getUserGroups); @@ -70,4 +71,5 @@ Parse.Cloud.afterFind('contracts_Document', DocumentBeforeFind); Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind); Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind); Parse.Cloud.afterFind('partners_Tenant', TenantAterFind); -Parse.Cloud.define('savesubscription', saveSubscriptio); +Parse.Cloud.define('savesubscription', saveSubscription); +Parse.Cloud.define('verifyemail', VerifyEmail); diff --git a/apps/OpenSignServer/cloud/parsefunction/VerifyEmail.js b/apps/OpenSignServer/cloud/parsefunction/VerifyEmail.js new file mode 100644 index 000000000..8c1f08d32 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/VerifyEmail.js @@ -0,0 +1,49 @@ +export default async function VerifyEmail(request) { + try { + if (!request?.user) { + throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); + } else { + let otpN = request.params.otp; + let otp = parseInt(otpN); + let email = request.params.email; + + //checking otp is correct or not which already save in defaultdata_Otp class + const checkOtp = new Parse.Query('defaultdata_Otp'); + checkOtp.equalTo('Email', email); + checkOtp.equalTo('OTP', otp); + + const res = await checkOtp.first({ useMasterKey: true }); + if (res) { + // Fetch the user by their objectId + const isEmailVerified = request?.user?.get('emailVerified'); + if (isEmailVerified) { + return { message: 'Email is already verified.' }; + } else { + const userQuery = new Parse.Query(Parse.User); + const user = await userQuery.get(request?.user.id, { + sessionToken: request?.user.getSessionToken(), + }); + + // Update the emailVerified field to true + user.set('emailVerified', true); + // Save the user object + const res = await user.save(null, { useMasterKey: true }); + if (res) { + return { message: 'Email is verified.' }; + } else { + const error = new Error('Something went wrong, please try again later!'); + error.code = 400; // Set the error code (e.g., 400 for bad request) + throw error; + } + } + } else { + const error = new Error('OTP is invalid.'); + error.code = 400; // Set the error code (e.g., 400 for bad request) + throw error; + } + } + } catch (err) { + console.log('err ', err.code + ' ' + err.message); + throw err; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js b/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js index 9b1e262f6..2771e81c4 100644 --- a/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js +++ b/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js @@ -1,5 +1,5 @@ import axios from 'axios'; -export default async function saveSubscriptio(request) { +export default async function saveSubscription(request) { const serverUrl = process.env.SERVER_URL; const appId = process.env.APP_ID; const subscription = request.params.subscription;