mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-28 10:49:41 +02:00
Merge pull request #338 from OpenSignLabs/api-v1-beta
feat: enable automatic redirect to remembered url after login
This commit is contained in:
@@ -0,0 +1 @@
|
||||
v1.1.1-beta
|
||||
|
||||
+17
-99
@@ -7,7 +7,7 @@ import Signup from "./routes/Signup";
|
||||
import Form from "./routes/Form";
|
||||
import Report from "./routes/Report";
|
||||
import Dashboard from "./routes/Dashboard";
|
||||
import PlanSubscriptions from "./routes/PlanSubscriptions";
|
||||
import Subscriptions from "./routes/PlanSubscriptions";
|
||||
import HomeLayout from "./layout/HomeLayout";
|
||||
import UserProfile from "./routes/UserProfile";
|
||||
import PageNotFound from "./routes/PageNotFound";
|
||||
@@ -60,112 +60,30 @@ function App() {
|
||||
) : (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route
|
||||
exact
|
||||
path="/"
|
||||
element={
|
||||
<ValidateRoute>
|
||||
<Login />
|
||||
</ValidateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/signup"
|
||||
element={
|
||||
<ValidateRoute>
|
||||
<Signup />
|
||||
</ValidateRoute>
|
||||
}
|
||||
/>
|
||||
<Route element={<ValidateRoute />}>
|
||||
<Route exact path="/" element={<Login />} />
|
||||
<Route exact path="/signup" element={<Signup />} />
|
||||
</Route>
|
||||
<Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} />
|
||||
<Route exact path="/forgetpassword" element={<ForgetPassword />} />
|
||||
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
|
||||
<>
|
||||
<Route exact path="/pgsignup" element={<Pgsignup />} />
|
||||
<Route
|
||||
exact
|
||||
path="/subscription"
|
||||
element={<PlanSubscriptions />}
|
||||
/>
|
||||
<Route exact path="/subscription" element={<Subscriptions />} />
|
||||
</>
|
||||
)}
|
||||
<Route
|
||||
exact
|
||||
path="/changepassword"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<ChangePassword />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/mf/:remoteApp/*"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<Microapp />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/asmf/:remoteApp/*"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<Microapp />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/rpmf/:remoteApp/*"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<ReportMicroapp />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/form/:id"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<Form />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/report/:id"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<Report />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/dashboard/:id"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<Dashboard />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="/profile"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<UserProfile />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/generatetoken"
|
||||
element={
|
||||
<HomeLayout>
|
||||
<GenerateToken />
|
||||
</HomeLayout>
|
||||
}
|
||||
/>
|
||||
<Route element={<HomeLayout />}>
|
||||
<Route path="/changepassword" element={<ChangePassword />} />
|
||||
<Route path="/mf/:remoteApp/*" element={<Microapp />} />
|
||||
<Route path="/asmf/:remoteApp/*" element={<Microapp />} />
|
||||
<Route path="/rpmf/:remoteApp/*" element={<ReportMicroapp />} />
|
||||
<Route path="/form/:id" element={<Form />} />
|
||||
<Route path="/report/:id" element={<Report />} />
|
||||
<Route path="/dashboard/:id" element={<Dashboard />} />
|
||||
<Route path="/profile" element={<UserProfile />} />
|
||||
<Route path="/generatetoken" element={<GenerateToken />} />
|
||||
</Route>
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
{/* <Route exact path="/ForgotPassword" element={<ForgotPassword />} /> */}
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
)}
|
||||
|
||||
@@ -8,15 +8,16 @@ import axios from "axios";
|
||||
import { useSelector } from "react-redux";
|
||||
import Parse from "parse";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
||||
|
||||
const HomeLayout = ({ children }) => {
|
||||
const HomeLayout = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { width } = useWindowSize();
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const arr = useSelector((state) => state.TourSteps);
|
||||
const [isUserValid, setIsUserValid] = useState(true);
|
||||
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
@@ -27,6 +28,7 @@ const HomeLayout = ({ children }) => {
|
||||
});
|
||||
if (user) {
|
||||
setIsUserValid(true);
|
||||
setIsLoader(false);
|
||||
} else {
|
||||
setIsUserValid(false);
|
||||
}
|
||||
@@ -184,7 +186,7 @@ const HomeLayout = ({ children }) => {
|
||||
console.log("err ", err);
|
||||
} finally {
|
||||
localStorage.removeItem("accesstoken");
|
||||
navigate("/", { replace: true });
|
||||
navigate("/", { replace: true, state: { from: location } });
|
||||
}
|
||||
};
|
||||
return (
|
||||
@@ -194,27 +196,48 @@ const HomeLayout = ({ children }) => {
|
||||
</div>
|
||||
{isUserValid ? (
|
||||
<>
|
||||
<div className="flex md:flex-row flex-col z-50">
|
||||
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
|
||||
|
||||
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
|
||||
<div className="bg-[#eef1f5] p-3">{children}</div>
|
||||
<div className="z-30">
|
||||
<Footer />
|
||||
</div>
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={tourConfigs}
|
||||
isOpen={isTour}
|
||||
closeWithMask={false}
|
||||
disableKeyboardNavigation={["esc"]}
|
||||
// disableInteraction={true}
|
||||
scrollOffset={-100}
|
||||
rounded={5}
|
||||
showCloseButton={isCloseBtn}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex md:flex-row flex-col z-50">
|
||||
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
|
||||
|
||||
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
|
||||
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
|
||||
<div className="z-30">
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={tourConfigs}
|
||||
isOpen={isTour}
|
||||
closeWithMask={false}
|
||||
disableKeyboardNavigation={["esc"]}
|
||||
// disableInteraction={true}
|
||||
scrollOffset={-100}
|
||||
rounded={5}
|
||||
showCloseButton={isCloseBtn}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
|
||||
const ValidateRoute = ({ children }) => {
|
||||
import { Outlet } from "react-router-dom";
|
||||
const ValidateRoute = () => {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
@@ -28,7 +28,7 @@ const ValidateRoute = ({ children }) => {
|
||||
localStorage.removeItem("accesstoken");
|
||||
}
|
||||
};
|
||||
return <div>{children}</div>;
|
||||
return <div>{<Outlet />}</div>;
|
||||
};
|
||||
|
||||
export default ValidateRoute;
|
||||
|
||||
@@ -24,7 +24,7 @@ const Dashboard = (props) => {
|
||||
getDashboard(localStorage.getItem("PageLanding"));
|
||||
}
|
||||
} else {
|
||||
navigate("/", { replace: true });
|
||||
navigate("/", { replace: true, state: { from: location } });
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [id]);
|
||||
|
||||
@@ -8,12 +8,13 @@ import axios from "axios";
|
||||
import Title from "../components/Title";
|
||||
import GoogleSignInBtn from "../components/LoginGoogle";
|
||||
// import LoginFacebook from "../components/LoginFacebook";
|
||||
import { NavLink, useNavigate } from "react-router-dom";
|
||||
import { NavLink, useNavigate, useLocation } from "react-router-dom";
|
||||
import login_img from "../assets/images/login_img.svg";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
|
||||
function Login(props) {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { width } = useWindowSize();
|
||||
const [state, setState] = useState({
|
||||
email: "",
|
||||
@@ -132,6 +133,9 @@ function Login(props) {
|
||||
`${localStorage.getItem("_appName")}_appeditor`
|
||||
) {
|
||||
userSettings.forEach(async (element) => {
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${element.pageType}/${element.pageId}`;
|
||||
if (element.role === _currentRole) {
|
||||
let _role = _currentRole.replace(
|
||||
`${localStorage.getItem("_appName")}_`,
|
||||
@@ -260,9 +264,8 @@ function Login(props) {
|
||||
localStorage.removeItem(
|
||||
"userDetails"
|
||||
);
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, {
|
||||
replace: true
|
||||
@@ -274,9 +277,8 @@ function Login(props) {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -313,9 +315,8 @@ function Login(props) {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -462,6 +463,9 @@ function Login(props) {
|
||||
`${localStorage.getItem("_appName")}_appeditor`
|
||||
) {
|
||||
userSettings.forEach(async (element) => {
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${element.pageType}/${element.pageId}`;
|
||||
if (element.role === _currentRole) {
|
||||
let _role = _currentRole.replace(
|
||||
`${localStorage.getItem("_appName")}_`,
|
||||
@@ -569,9 +573,7 @@ function Login(props) {
|
||||
if (billingDate) {
|
||||
if (billingDate > new Date()) {
|
||||
localStorage.removeItem("userDetails");
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, {
|
||||
replace: true
|
||||
@@ -581,9 +583,7 @@ function Login(props) {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
} else {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -599,9 +599,8 @@ function Login(props) {
|
||||
if (billingDate) {
|
||||
if (billingDate > new Date()) {
|
||||
localStorage.removeItem("userDetails");
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
@@ -609,9 +608,7 @@ function Login(props) {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
} else {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ import axios from "axios";
|
||||
import { fetchAppInfo, showTenantName } from "../redux/actions/index";
|
||||
import { connect } from "react-redux";
|
||||
import Title from "../components/Title";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
|
||||
const appId = localStorage.getItem("AppID12");
|
||||
const server = localStorage.getItem("BaseUrl12");
|
||||
@@ -13,6 +13,7 @@ Parse.serverURL = server;
|
||||
Parse.initialize(appId);
|
||||
const PgSignUp = (props) => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [parseBaseUrl] = useState(localStorage.getItem("BaseUrl12"));
|
||||
const [parseAppId] = useState(localStorage.getItem("AppID12"));
|
||||
const [formData, setFormData] = useState({
|
||||
@@ -187,7 +188,7 @@ const PgSignUp = (props) => {
|
||||
console.log("err ", error);
|
||||
if (error.message === "Account already exists for this username.") {
|
||||
alert("Account already exists!");
|
||||
navigate("/");
|
||||
navigate("/", { replace: true });
|
||||
} else {
|
||||
setIsLoader(false);
|
||||
alert("Something went wrong, please try again later!");
|
||||
@@ -351,7 +352,7 @@ const PgSignUp = (props) => {
|
||||
element.pageType
|
||||
);
|
||||
setIsLoader(false);
|
||||
navigate("/");
|
||||
navigate("/", { replace: true });
|
||||
} else {
|
||||
extendedInfo.forEach((x) => {
|
||||
if (x.TenantId) {
|
||||
@@ -389,9 +390,12 @@ const PgSignUp = (props) => {
|
||||
);
|
||||
setIsLoader(false);
|
||||
alert("Registered user successfully");
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${element.pageType}/${element.pageId}`;
|
||||
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
} else {
|
||||
alert("Registered user successfully");
|
||||
@@ -402,7 +406,12 @@ const PgSignUp = (props) => {
|
||||
);
|
||||
localStorage.setItem("pageType", element.pageType);
|
||||
setIsLoader(false);
|
||||
navigate(`/${element.pageType}/${element.pageId}`);
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${element.pageType}/${element.pageId}`;
|
||||
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
|
||||
@@ -39,7 +39,7 @@ const PlanSubscriptions = () => {
|
||||
setIsLoader(false);
|
||||
setYearlyVisible(false);
|
||||
} else {
|
||||
navigate("/");
|
||||
navigate("/", { replace: true });
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
@@ -78,31 +78,6 @@ const PlanSubscriptions = () => {
|
||||
id="monthlyPlans"
|
||||
className={`${yearlyVisible ? "none" : "block my-2"}`}
|
||||
>
|
||||
{/* <div className=" my-2 w-full flex justify-center">
|
||||
<ul
|
||||
className="navs"
|
||||
style={{
|
||||
listStyle: "none",
|
||||
display: "flex",
|
||||
alignItems: "baseline"
|
||||
}}
|
||||
>
|
||||
<li className="nav-item">
|
||||
<button className="nav-link frequency active" name="1_months">
|
||||
Monthly
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className="nav-link frequency "
|
||||
onClick={toggleFrequency}
|
||||
name="1_years"
|
||||
>
|
||||
Yearly
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div> */}
|
||||
<div className="flex justify-center w-full my-2">
|
||||
<ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300">
|
||||
{plansArr.map((item) => (
|
||||
|
||||
@@ -20,7 +20,7 @@ import multer from 'multer';
|
||||
// import fs from 'node:fs';
|
||||
import updateDocument from './routes/updateDocument.js';
|
||||
import deleteDocument from './routes/deleteDocument.js';
|
||||
// import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js';
|
||||
import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js';
|
||||
|
||||
dotenv.config();
|
||||
const storage = multer.memoryStorage();
|
||||
@@ -49,7 +49,8 @@ app.get('/contactlist', getContactList);
|
||||
app.post('/createdocument', upload.array('file', 1), createDocument);
|
||||
|
||||
// create Document with templateId
|
||||
// app.post('/createdocument/:template_id', createDocumentWithTemplate);
|
||||
app.post('/createdocument/:template_id', createDocumentWithTemplate);
|
||||
|
||||
// get Document on the basis of id
|
||||
app.get('/document/:document_id', getDocument);
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||
export default async function createDocumentWithTemplate(request, response) {
|
||||
const signers = request.body.Signers;
|
||||
const folderId = request.body.FolderId;
|
||||
const templateId = request.params.template_id;
|
||||
const url = process.env.SERVER_URL;
|
||||
try {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('token', reqToken);
|
||||
const token = await tokenQuery.first({ useMasterKey: true });
|
||||
if (token !== undefined) {
|
||||
// Valid Token then proceed request
|
||||
const userPtr = token.get('userId');
|
||||
|
||||
const templateQyuery = new Parse.Query('contracts_Template');
|
||||
const templateRes = await templateQyuery.get(templateId, { useMasterKey: true });
|
||||
if (templateRes) {
|
||||
const template = JSON.parse(JSON.stringify(templateRes));
|
||||
if (template?.Placeholders?.length > 0) {
|
||||
let isValid = template?.Placeholders?.length <= signers?.length;
|
||||
let updateSigners = template?.Placeholders?.every(y =>
|
||||
signers?.some(x => x.Role === y.Role)
|
||||
);
|
||||
if (isValid && updateSigners) {
|
||||
const folderPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
};
|
||||
const template = JSON.parse(JSON.stringify(templateRes));
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', template.Name);
|
||||
if (template?.Note) {
|
||||
object.set('Note', template.Note);
|
||||
}
|
||||
if (template?.Description) {
|
||||
object.set('Description', template.Description);
|
||||
}
|
||||
if (template?.Signers) {
|
||||
object.set('Signers', template?.Signers);
|
||||
}
|
||||
object.set('URL', template.URL);
|
||||
object.set('CreatedBy', template.CreatedBy);
|
||||
object.set('ExtUserPtr', template.ExtUserPtr);
|
||||
if (signers) {
|
||||
const placeholders = template?.Placeholders?.map(placeholder => {
|
||||
let matchingSigner = signers.find(y => y.Role === placeholder.Role);
|
||||
if (matchingSigner) {
|
||||
return {
|
||||
...placeholder,
|
||||
email: matchingSigner.Email,
|
||||
signerObjId: '',
|
||||
signerPtr: {},
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...placeholder,
|
||||
};
|
||||
}
|
||||
});
|
||||
console.log('placeholders ', placeholders);
|
||||
object.set('Placeholders', placeholders);
|
||||
}
|
||||
if (folderId) {
|
||||
object.set('Folder', folderPtr);
|
||||
}
|
||||
const newACL = new Parse.ACL();
|
||||
newACL.setPublicReadAccess(false);
|
||||
newACL.setPublicWriteAccess(false);
|
||||
newACL.setReadAccess(userPtr.id, true);
|
||||
newACL.setWriteAccess(userPtr.id, true);
|
||||
object.setACL(newACL);
|
||||
const res = await object.save(null, { useMasterKey: true });
|
||||
return response.json({ objectId: res.id, url: url });
|
||||
} else {
|
||||
return response.status(400).json({ error: 'Please provide signers properly!' });
|
||||
}
|
||||
} else {
|
||||
return response.status(400).json({ error: 'Please setup template properly!' });
|
||||
}
|
||||
} else {
|
||||
return response.status(404).json({ error: 'Invalid template id!' });
|
||||
}
|
||||
} else {
|
||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
if (err.code === 101) {
|
||||
return response.status(404).json({ error: 'Invalid template id!' });
|
||||
}
|
||||
return response.status(400).json({ error: 'Something went wrong!' });
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -151,7 +151,7 @@ exports.up = async Parse => {
|
||||
},
|
||||
{
|
||||
icon: 'fa-solid fa-key',
|
||||
title: 'Generate token',
|
||||
title: 'API Token',
|
||||
target: '_self',
|
||||
pageType: 'generatetoken',
|
||||
description: '',
|
||||
@@ -316,7 +316,7 @@ exports.up = async Parse => {
|
||||
},
|
||||
{
|
||||
icon: 'fa-solid fa-key',
|
||||
title: 'Generate token',
|
||||
title: 'API Token',
|
||||
target: '_self',
|
||||
pageType: 'generatetoken',
|
||||
description: '',
|
||||
|
||||
@@ -10,6 +10,7 @@ import LegaDrive from "./Component/LegaDrive/LegaDrive";
|
||||
import PageNotFound from "./Component/PageNotFound";
|
||||
import TemplatePlaceHolder from "./Component/TemplatePlaceholder";
|
||||
import Parse from "parse";
|
||||
import GuestLogin from "./premitives/GuestLogin";
|
||||
Parse.serverURL = localStorage.getItem("baseUrl");
|
||||
Parse.initialize(localStorage.getItem("parseAppId"));
|
||||
// `AppRoutes` is used to define route path of app and
|
||||
@@ -50,6 +51,8 @@ function AppRoutes() {
|
||||
<Route path="/legadrive" element={<LegaDrive />} />
|
||||
{/* Page Not Found */}
|
||||
<Route path="/template/:templateId" element={<TemplatePlaceHolder />} />
|
||||
<Route path="/guestlogin" element={<GuestLogin />} />
|
||||
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
import React, { useState } from "react";
|
||||
import ModalUi from './ModalUi'
|
||||
import "../css/LoginPage.css";
|
||||
import loader from "../assests/loader2.gif";
|
||||
import axios from "axios";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { themeColor } from "../utils/ThemeColor/backColor";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import GuestSign from "./GuestSign";
|
||||
|
||||
function GuestLogin({children, userdetails}) {
|
||||
const { id, userMail, contactBookId, serverUrl } = useParams();
|
||||
let navigate = useNavigate();
|
||||
const [email, setEmail] = useState(userMail || "prafull.navkar@nxglabs.com");
|
||||
const [OTP, setOTP] = useState("");
|
||||
const [EnterOTP, setEnterOtp] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
handleServerUrl();
|
||||
}, []);
|
||||
|
||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||
const handleServerUrl = () => {
|
||||
//split url in array from '&'
|
||||
localStorage.clear();
|
||||
// const checkSplit = serverUrl?.split("&");
|
||||
// const server = checkSplit?.[0];
|
||||
// const parseId = checkSplit?.[1];
|
||||
// const appName = checkSplit?.[2];
|
||||
|
||||
// const newServer = server.replaceAll("%2F", "/");
|
||||
// localStorage.setItem("baseUrl", newServer);
|
||||
// localStorage.setItem("parseAppId", parseId);
|
||||
// localStorage.setItem("_appName", appName);
|
||||
|
||||
localStorage.setItem("baseUrl", "https://staging-app.opensignlabs.com/api/app/");
|
||||
localStorage.setItem("parseAppId", "opensignstgn");
|
||||
localStorage.setItem("_appName", "contracts");
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
const { value } = event.target;
|
||||
setOTP(value);
|
||||
};
|
||||
|
||||
//send email OTP function
|
||||
const SendOtp = async (e) => {
|
||||
const serverUrl =
|
||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
||||
const parseId =
|
||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
||||
if (serverUrl && localStorage) {
|
||||
setLoading(true);
|
||||
e.preventDefault();
|
||||
setEmail(email);
|
||||
|
||||
try {
|
||||
let url = `${serverUrl}functions/SendOTPMailV1/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email.toString()
|
||||
};
|
||||
let Otp = await axios.post(url, body, { headers: headers });
|
||||
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
setEnterOtp(true);
|
||||
}
|
||||
} catch (error) {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
} else {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
};
|
||||
|
||||
//verify OTP send on via email
|
||||
const VerifyOTP = async (e) => {
|
||||
e.preventDefault();
|
||||
const serverUrl =
|
||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
||||
const parseId =
|
||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
||||
if (OTP) {
|
||||
setLoading(true);
|
||||
try {
|
||||
let url = `${serverUrl}functions/AuthLoginAsMail/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email,
|
||||
otp: OTP
|
||||
};
|
||||
let user = await axios.post(url, body, { headers: headers });
|
||||
if (user.data.result === "Invalid Otp") {
|
||||
alert("Invalid Otp");
|
||||
setLoading(false);
|
||||
} else if (user.data.result === "user not found!") {
|
||||
alert("User not found!");
|
||||
setLoading(false);
|
||||
} else {
|
||||
let _user = user.data.result;
|
||||
const parseId = localStorage.getItem("parseAppId");
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem(
|
||||
`Parse/${parseId}/currentUser`,
|
||||
JSON.stringify(_user)
|
||||
);
|
||||
localStorage.setItem("username", _user.name);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||
localStorage.setItem("isGuestSigner", true);
|
||||
setLoading(false);
|
||||
// uKymQWaYL6
|
||||
navigate(
|
||||
`/loadmf/signmicroapp/recipientSignPdf/${id}/${contactBookId}`
|
||||
);
|
||||
}
|
||||
} catch (error) {}
|
||||
} else {
|
||||
alert("Please Enter OTP!");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: "2rem" }}>
|
||||
<ModalUi isOpen>
|
||||
<>
|
||||
{isLoading ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "80px", height: "80px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
{isLoading.message}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
margin: "10px",
|
||||
border: "0.5px solid #c5c7c9",
|
||||
padding: "30px",
|
||||
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
|
||||
}}
|
||||
>
|
||||
<div className="main_head">
|
||||
<div className="main-logo">
|
||||
<img
|
||||
alt="sign img"
|
||||
src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"
|
||||
width="100%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!EnterOTP ? (
|
||||
<div >
|
||||
<div >
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">
|
||||
Verification code is sent to your email
|
||||
</span>
|
||||
<div className="card card-box" style={{ borderRadius: "0px" }}>
|
||||
<div className="card-body">
|
||||
<input
|
||||
type="email"
|
||||
name="mobile"
|
||||
value={email}
|
||||
disabled
|
||||
className="loginInput"
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div className="btnContainer">
|
||||
{loading ? (
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="verifyBtn"
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
marginLeft: "0px !important"
|
||||
}}
|
||||
onClick={(e) => SendOtp(e)}
|
||||
>
|
||||
Send OTP
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div >
|
||||
<div >
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">You will get a OTP via Email</span>
|
||||
<div className="card card-box">
|
||||
<div className="card-body">
|
||||
<label>Enter Verification Code</label>
|
||||
<input
|
||||
type="number"
|
||||
className="loginInput"
|
||||
name="OTP"
|
||||
value={OTP}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{loading ? (
|
||||
<button
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
type="button"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => VerifyOTP(e)}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</ModalUi>
|
||||
<div><GuestSign /></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GuestLogin;
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user