feat: validation to add user

This commit is contained in:
prafull-opensignlabs
2024-08-07 20:02:41 +05:30
parent 76b90f9bc0
commit 908edda14b
20 changed files with 13841 additions and 17728 deletions
File diff suppressed because one or more lines are too long
+303 -172
View File
@@ -2,8 +2,9 @@ import React, { useEffect, useState } from "react";
import Parse from "parse";
import Title from "./Title";
import Loader from "../primitives/Loader";
import { copytoData } from "../constant/Utils";
import { copytoData, fetchSubscriptionInfo } from "../constant/Utils";
import { isEnableSubscription } from "../constant/const";
import ModalUi from "../primitives/ModalUi";
function generatePassword(length) {
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@@ -25,8 +26,21 @@ const AddUser = (props) => {
password: "",
role: ""
});
const [amount, setAmount] = useState({
quantity: 1,
price: 0,
totalPrice: 0
});
const [planInfo, setPlanInfo] = useState({
priceperUser: 0,
price: 0,
totalPrice: 0
});
const [isFormLoader, setIsFormLoader] = useState(false);
const [isLoader, setIsLoader] = useState(false);
const [teamList, setTeamList] = useState([]);
const [allowedUser, setAllowedUser] = useState(0);
const [err, setErr] = useState("");
const role = ["OrgAdmin", "Editor", "User"];
useEffect(() => {
@@ -34,6 +48,39 @@ const AddUser = (props) => {
}, []);
const getTeamList = async () => {
if (isEnableSubscription) {
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
try {
setIsLoader(true);
const resSub = await fetchSubscriptionInfo();
if (!resSub.error) {
setPlanInfo((prev) => ({
...prev,
priceperUser: resSub.price,
totalPrice: resSub.totalPrice
}));
setAmount((prev) => ({
...prev,
price: resSub.price,
totalPrice: resSub.price + resSub.totalPrice
}));
const res = await Parse.Cloud.run("allowedusers", {
tenantId: extUser?.TenantId?.objectId
});
setAllowedUser(res);
} else {
setAllowedUser(0);
}
} catch (err) {
setAllowedUser(0);
console.log("Err in alloweduser", err);
setErr(err.message);
} finally {
setIsLoader(false);
}
}
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
const teamRes = await Parse.Cloud.run("getteams", { active: true });
if (teamRes.length > 0) {
@@ -48,7 +95,9 @@ const AddUser = (props) => {
};
const checkUserExist = async () => {
try {
const res = await Parse.Cloud.run("getUserDetails");
const res = await Parse.Cloud.run("getUserDetails", {
email: formdata.email
});
if (res) {
return true;
} else {
@@ -63,11 +112,11 @@ const AddUser = (props) => {
e.preventDefault();
e.stopPropagation();
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
setIsLoader(true);
setIsFormLoader(true);
const res = await checkUserExist();
if (res) {
props.setIsAlert({ type: "danger", msg: "User already exist." });
setIsLoader(false);
setIsFormLoader(false);
setTimeout(() => {
props.setIsAlert({ type: "success", msg: "" });
}, 1000);
@@ -153,14 +202,8 @@ const AddUser = (props) => {
props.handleUserData(parseData);
}
setIsLoader(false);
setFormdata({
name: "",
email: "",
phone: "",
team: "",
role: ""
});
setIsFormLoader(false);
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
}
} catch (err) {
console.log("err ", err);
@@ -200,19 +243,13 @@ const AddUser = (props) => {
}
props.handleUserData(parseData);
}
setIsLoader(false);
setFormdata({
name: "",
email: "",
phone: "",
team: "",
role: ""
});
setIsFormLoader(false);
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
}
}
} catch (err) {
console.log("err", err);
setIsLoader(false);
setIsFormLoader(false);
props.setIsAlert({ type: "danger", msg: "something went wrong." });
} finally {
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500);
@@ -222,13 +259,7 @@ const AddUser = (props) => {
// Define a function to handle the "add yourself" checkbox
const handleReset = () => {
setFormdata({
name: "",
email: "",
phone: "",
team: "",
role: ""
});
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
if (props.closePopup) {
props.closePopup();
}
@@ -242,154 +273,254 @@ const AddUser = (props) => {
props.setIsAlert({ type: "success", msg: "Copied" });
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds
};
const handlePricePerUser = (e) => {
const quantity = e.target.value;
const price = e.target?.value > 0 ? planInfo.priceperUser * quantity : 0;
const totalprice = price + planInfo.totalPrice;
setAmount((prev) => ({
...prev,
quantity: quantity,
price: price,
totalPrice: totalprice
}));
};
const handleAddOnSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsFormLoader(true);
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
try {
const resAddon = await Parse.Cloud.run("buyaddon", {
users: amount.quantity,
tenantId: extUser?.TenantId?.objectId
});
if (resAddon) {
setAllowedUser(amount.quantity);
}
} catch (err) {
console.log("Err in buy addon", err);
props.setIsAlert({ type: "danger", msg: "something went wrong." });
} finally {
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 2000);
setIsFormLoader(false);
}
};
return (
<div className="shadow-md rounded-box my-[1px] p-3 bg-[#ffffff]">
<Title title={"Add User"} />
{isLoader && (
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50 rounded-box">
<Loader />
</div>
)}
<div className="w-full mx-auto">
<form onSubmit={handleSubmit}>
{/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */}
<div className="mb-3">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
Name
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="text"
name="name"
value={formdata.name}
onChange={(e) => handleChange(e)}
required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
<ModalUi
isOpen={props.isOpen}
title={allowedUser > 0 ? "Add User" : "Add Seats"}
handleClose={props.closePopup}
>
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
<Title title="Add User" />
{isFormLoader && (
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
<Loader />
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Email
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="email"
name="email"
value={formdata.email}
onChange={(e) => handleChange(e)}
required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
)}
{!isLoader ? (
<>
{err ? (
<div className="flex justify-center items-center h-[70px] text-[18px]">
{err}
</div>
) : (
<div className="w-full mx-auto">
{!isEnableSubscription || allowedUser > 0 ? (
<form onSubmit={handleSubmit}>
<div className="mb-3">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
Name
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="text"
name="name"
value={formdata.name}
onChange={(e) => handleChange(e)}
required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Email
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="email"
name="email"
value={formdata.email}
onChange={(e) => handleChange(e)}
required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Password
</label>
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
<div className="break-all">{formdata?.password}</div>
<i
onClick={() => copytoclipboard(formdata?.password)}
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
></i>
</div>
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
Password will only be generated once; make sure to copy
it.
</div>
</div>
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Phone
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
<input
type="text"
name="phone"
placeholder="optional"
value={formdata.phone}
onChange={(e) => handleChange(e)}
// required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
{isEnableSubscription && (
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Team<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.team}
onChange={(e) => handleChange(e)}
name="team"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
required
>
<option defaultValue={""} value={""}>
select
</option>
{teamList.length > 0 &&
teamList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
)}
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Role<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.role}
onChange={(e) => handleChange(e)}
name="role"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
required
>
<option defaultValue={""} value={""}>
select
</option>
{role.length > 0 &&
role.map((x) => (
<option key={x} value={x}>
{x}
</option>
))}
</select>
</div>
<div className="flex items-center mt-3 gap-2 text-white">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
<div
type="button"
onClick={() => handleReset()}
className="op-btn op-btn-secondary"
>
Cancel
</div>
</div>
</form>
) : (
<form onSubmit={handleAddOnSubmit}>
<p className="flex justify-center text-center mx-2 mb-3 text-base font-medium">
You have reached the limit for creating users. Please
purchase the add-on.
</p>
<div className="mb-3 flex justify-between">
<label
htmlFor="quantity"
className="block text-xs text-gray-700 font-semibold"
>
Quantity of user
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="number"
name="quantity"
value={amount.quantity}
onChange={(e) => handlePricePerUser(e)}
className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
required
/>
</div>
<div className="mb-3 flex justify-between">
<label className="block text-xs text-gray-700 font-semibold">
Price (1 * {planInfo.priceperUser})
</label>
<div className="w-1/4 flex justify-center items-center text-sm">
{amount.price}
</div>
</div>
<hr className="text-base-content mb-3" />
<div className=" flex justify-between">
<label className="block text-sm text-gray-700 font-semibold">
Total price for next time
</label>
<div className="w-1/4 flex justify-center items-center text-sm font-semibold">
{amount.totalPrice}
</div>
</div>
<button className="op-btn op-btn-primary w-full mt-2">
Proceed
</button>
</form>
)}
</div>
)}
</>
) : (
<div className="w-full h-[200px] inset-0 flex justify-center items-center z-50">
<Loader />
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Password
</label>
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
<div className="break-all">{formdata?.password}</div>
<i
onClick={() => copytoclipboard(formdata?.password)}
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
></i>
</div>
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
Password will only be generated once; make sure to copy it.
</div>
</div>
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Phone
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
<input
type="text"
name="phone"
placeholder="optional"
value={formdata.phone}
onChange={(e) => handleChange(e)}
// required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
{isEnableSubscription && (
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Team<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.team}
onChange={(e) => handleChange(e)}
name="team"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
required
>
<option defaultValue={""} value={""}>
select
</option>
{teamList.length > 0 &&
teamList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
)}
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Role<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.role}
onChange={(e) => handleChange(e)}
name="role"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
required
>
<option defaultValue={""} value={""}>
select
</option>
{role.length > 0 &&
role.map((x) => (
<option key={x} value={x}>
{x}
</option>
))}
</select>
</div>
<div className="flex items-center mt-3 gap-2 text-white">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
<div
type="button"
onClick={() => handleReset()}
className="op-btn op-btn-secondary"
>
Cancel
</div>
</div>
</form>
)}
</div>
</div>
</ModalUi>
);
};
+43
View File
@@ -63,6 +63,49 @@ export async function fetchSubscription(
return { plan: "", billingDate: "" };
}
}
export async function fetchSubscriptionInfo() {
try {
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
// console.log("extClass ", extClass);
if (extClass && extClass.length > 0) {
const extUser = extClass[0].objectId;
const baseURL = localStorage.getItem("baseUrl");
const url = `${baseURL}functions/getsubscriptions`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
};
const params = { extUserId: extUser };
const tenatRes = await axios.post(url, params, { headers: headers });
const price =
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
?.plan?.price;
const totalPrice =
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
?.amount;
const planId =
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
?.subscription_id;
const plan_code =
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
?.plan?.plan_code;
return {
status: "success",
price: price,
totalPrice: totalPrice,
planId: planId,
plan_code: plan_code
};
}
} catch (err) {
console.log("Err in fetch subscription", err);
return { status: "error", error: err };
}
}
//function to get subcripition details from subscription class
export async function checkIsSubscribed() {
try {
+2 -2
View File
@@ -9,5 +9,5 @@ export const isEnableSubscription =
process.env.REACT_APP_ENABLE_SUBSCRIPTION?.toLowerCase() === "true"
? true
: false;
export const isStaging =
window.location.origin === "https://staging-app.opensignlabs.com";
export const isStaging = "http://localhost:3001";
// window.location.origin === "https://staging-app.opensignlabs.com";
+1 -5
View File
@@ -215,11 +215,7 @@ const DebugPdf = () => {
};
return (
<div>
{copied && (
<Alert type="success">
<span className="ml-3">Copied</span>
</Alert>
)}
{copied && <Alert type="success">Copied</Alert>}
<Title title={"Debug Pdf"} />
{width < 800 ? (
<HandleError handleError={"Debug PDF only availble for PC"} />
+4 -9
View File
@@ -1,7 +1,6 @@
import React, { useEffect, useRef, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { formJson } from "../json/FormJson";
import AddUser from "../components/AddUser";
import sanitizeFileName from "../primitives/sanitizeFileName";
import Parse from "parse";
import DropboxChooser from "../components/shared/fields/DropboxChoose";
@@ -24,15 +23,11 @@ import Loader from "../primitives/Loader";
function Form() {
const { id } = useParams();
if (id === "lM0xRnM3iE") {
return <AddUser />;
const config = formJson[id];
if (config) {
return <Forms {...config} />;
} else {
const config = formJson[id];
if (config) {
return <Forms {...config} />;
} else {
return <PageNotFound prefix={"Form"} />;
}
return <PageNotFound prefix={"Form"} />;
}
}
+1 -5
View File
@@ -99,11 +99,7 @@ function GenerateToken() {
return (
<React.Fragment>
<Title title={"API Token"} />
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
{isLoader ? (
<div className="flex justify-center items-center h-screen">
<Loader />
+1 -3
View File
@@ -757,9 +757,7 @@ function Login() {
</div>
</div>
{state.alertMsg && (
<Alert type={state.alertType}>
<div className="ml-3">{state.alertMsg}</div>
</Alert>
<Alert type={state.alertType}>{state.alertMsg}</Alert>
)}
</div>
<ModalUi isOpen={isModal} title="Additional Info" showClose={false}>
+1 -5
View File
@@ -1061,11 +1061,7 @@ function PlaceHolderSign() {
className="flex flex-row justify-between items-center mb-1"
key={ind}
>
{copied && (
<Alert type="success">
<div className="ml-3">Copied</div>
</Alert>
)}
{copied && <Alert type="success">Copied</Alert>}
<span className="w-[220px] md:w-[300px] whitespace-nowrap overflow-hidden text-ellipsis ">
{data.signerEmail}
</span>
+1 -5
View File
@@ -226,11 +226,7 @@ const TeamList = () => {
<>
{isAdmin ? (
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">
Teams{" "}
@@ -65,11 +65,7 @@ const UpdateExistUserAdmin = () => {
return (
<div className="h-screen flex justify-center">
<Title title={"Add Admin"} />
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
{loader ? (
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
<Loader />
+7 -15
View File
@@ -197,11 +197,7 @@ const UserList = () => {
<>
{isAdmin ? (
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">
Users{" "}
@@ -390,17 +386,13 @@ const UserList = () => {
<div className="text-sm font-semibold">No Data Available</div>
</div>
)}
<ModalUi
title={"Add User"}
<AddUser
isOpen={isModal}
handleClose={handleFormModal}
>
<AddUser
setIsAlert={setIsAlert}
handleUserData={handleUserData}
closePopup={handleFormModal}
/>
</ModalUi>
setIsAlert={setIsAlert}
handleUserData={handleUserData}
closePopup={handleFormModal}
/>
</div>
) : (
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
+1 -1
View File
@@ -20,7 +20,7 @@ const Alert = ({ children, type }) => {
children && (
<div className="z-[1000] fixed top-20 left-1/2 transform -translate-x-1/2 text-sm">
<div className={`op-alert ${textcolor}`}>
<span>{children}</span>
<span className="ml-3">{children}</span>
</div>
</div>
)
@@ -3,8 +3,9 @@ export default async function saveSubscription(request, response) {
const body = request.body;
const Email = request.body.data.subscription.customer.email;
const Next_billing_date = request.body.data.subscription.next_billing_at;
const planCode = request.body.data.subscription.plan.plan_code
const planCode = request.body.data.subscription.plan.plan_code;
const addons = request.body?.data?.subscription?.addons || [];
const existAddon = addons.reduce((acc, curr) => acc + curr.quantity, 1);
try {
const extUserCls = new Parse.Query('contracts_Users');
extUserCls.equalTo('Email', Email);
@@ -24,6 +25,7 @@ export default async function saveSubscription(request, response) {
updateSubscription.set('SubscriptionDetails', body);
updateSubscription.set('Next_billing_date', new Date(Next_billing_date));
updateSubscription.set('PlanCode', planCode);
updateSubscription.set('AllowedUsers', parseInt(existAddon));
await updateSubscription.save(null, { useMasterKey: true });
return response.status(200).json({ status: 'update subscription!' });
} else {
@@ -47,6 +49,7 @@ export default async function saveSubscription(request, response) {
});
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
createSubscription.set('PlanCode', planCode);
createSubscription.set('AllowedUsers', parseInt(existAddon));
await createSubscription.save(null, { useMasterKey: true });
return response.status(200).json({ status: 'create subscription!' });
}
+4
View File
@@ -60,6 +60,8 @@ import addTeam from './parsefunction/addTeam.js';
import updateTeam from './parsefunction/updateTeam.js';
import getOrgAdmins from './parsefunction/getOrgAdmins.js';
import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js';
import AllowedUsers from './parsefunction/AlllowedUsers.js';
import Buyaddon from './parsefunction/BuyAddon.js';
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
@@ -129,3 +131,5 @@ Parse.Cloud.define('addteam', addTeam);
Parse.Cloud.define('updateteam', updateTeam);
Parse.Cloud.define('getorgadmins', getOrgAdmins);
Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg);
Parse.Cloud.define('allowedusers', AllowedUsers);
Parse.Cloud.define('buyaddon', Buyaddon);
@@ -0,0 +1,44 @@
export default async function AllowedUsers(request) {
const tenantId = request.params.tenantId;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
try {
const subscription = new Parse.Query('contracts_Subscriptions');
subscription.equalTo('TenantId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: tenantId,
});
subscription.include('ExtUserPtr');
const resSub = await subscription.first({ useMasterKey: true });
if (resSub) {
const _resSub = JSON.parse(JSON.stringify(resSub));
const userCls = new Parse.Query('contracts_Users');
userCls.equalTo('OrganizationId', {
__type: 'Pointer',
className: 'contracts_Organizations',
objectId: _resSub.ExtUserPtr.OrganizationId.objectId,
});
userCls.notEqualTo('IsDisabled', true);
const count = await userCls.count({ useMasterKey: true });
if (count > 0) {
const allowedUser = resSub.get('AllowedUsers') || 0;
const remainUsers = allowedUser - count;
if (remainUsers > 0) {
return remainUsers;
} else {
return 0;
}
} else {
const alloweduser = resSub.get('AllowedUsers') || 0;
return alloweduser;
}
}
} catch (err) {
console.log('err in allowedusers', err);
const code = err?.code || 400;
const msg = err?.message || 'Something went wrong.';
throw new Parse.Error(code, msg);
}
}
@@ -0,0 +1,94 @@
import axios from 'axios';
export default async function Buyaddon(request) {
const tenantId = request.params.tenantId;
const users = request.params.users;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
if (users && tenantId) {
try {
const subscription = new Parse.Query('contracts_Subscriptions');
subscription.equalTo('TenantId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: tenantId,
});
subscription.include('ExtUserPtr');
const resSub = await subscription.first({ useMasterKey: true });
if (resSub) {
const _resSub = JSON.parse(JSON.stringify(resSub));
// Define the URL
const url = 'https://accounts.zoho.in/oauth/v2/token';
// Convert the data to x-www-form-urlencoded format
const formData = new URLSearchParams();
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
formData.append('grant_type', 'refresh_token');
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
// Make the POST request using Axios
const res = await axios.post(url, formData, { headers });
if (res.data.access_token) {
const subscriptionId = _resSub.SubscriptionId;
const price = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.price;
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
const addonsArr = _resSub?.SubscriptionDetails?.data?.subscription?.addons || [];
const addon = addonsArr.reduce((acc, curr) => acc + curr.quantity, 0);
const quantity = parseInt(users) + parseInt(addon);
const data = JSON.stringify({
plan: { plan_code: plan_code },
addons: [
{
addon_code: 'extra-users',
addon_description: 'Extra users',
price: price,
quantity: quantity,
},
],
});
await axios.put(
'https://www.zohoapis.in/billing/v1/subscriptions/' + subscriptionId,
data,
{
headers: {
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
},
}
);
const hostedpage_id = _resSub.SubscriptionDetails.hostedpage_id;
const userData = await axios.get(
'https://www.zohoapis.in/billing/v1/hostedpages/' + hostedpage_id,
{
headers: {
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
},
}
);
const allowedUsers = quantity + 1;
const updateSub = new Parse.Object('contracts_Subscriptions');
updateSub.id = resSub.id;
updateSub.set('SubscriptionDetails', userData.data);
updateSub.set('AllowedUsers', allowedUsers);
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
return 'success';
} else {
throw new Parse.Error('400', 'Invalid access token.');
}
}
} catch (err) {
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
const msg =
err?.response?.data?.error ||
err?.response?.data ||
err?.message ||
'Something went wrong.';
console.log('err in buyaddon', code, msg);
throw new Parse.Error(code, msg);
}
}
}
@@ -18,9 +18,7 @@ export default async function ZohoDetails(request) {
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
formData.append('grant_type', 'refresh_token');
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
};
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
// Make the POST request using Axios
const res = await axios.post(url, formData, { headers });
// console.log("Access Token:", res.data);
@@ -4,11 +4,11 @@ async function getUserDetails(request) {
try {
const userId = request.params.userId;
const userQuery = new Parse.Query('contracts_Users');
if (request?.user) {
if (reqEmail) {
userQuery.equalTo('Email', reqEmail);
} else {
const email = request.user.get('email');
userQuery.equalTo('Email', email);
} else {
userQuery.equalTo('Email', reqEmail);
}
userQuery.include('TenantId');
userQuery.include('UserId');
@@ -32,6 +32,8 @@ export default async function saveSubscription(request) {
objectId: extUser.get('TenantId').id,
});
const subscription = await subcriptionCls.first({ useMasterKey: true });
const addons = subscription?.data?.subscription?.addons || [];
const existAddon = addons.reduce((acc, curr) => acc + curr.quantity, 1);
if (subscription) {
const updateSubscription = new Parse.Object('contracts_Subscriptions');
updateSubscription.id = subscription.id;
@@ -39,6 +41,7 @@ export default async function saveSubscription(request) {
updateSubscription.set('SubscriptionDetails', body);
updateSubscription.set('Next_billing_date', new Date(Next_billing_date));
updateSubscription.set('PlanCode', planCode);
updateSubscription.set('AllowedUsers', parseInt(existAddon));
await updateSubscription.save(null, { useMasterKey: true });
return { status: 'update subscription!' };
} else {
@@ -62,6 +65,7 @@ export default async function saveSubscription(request) {
});
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
createSubscription.set('PlanCode', planCode);
createSubscription.set('AllowedUsers', parseInt(existAddon));
await createSubscription.save(null, { useMasterKey: true });
return { status: 'create subscription!' };
}