mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-12
This commit is contained in:
@@ -586,23 +586,22 @@
|
||||
"Recent signature requests": "This is a list of documents that are waiting for your signature.",
|
||||
"Recently sent for signatures":"This is a list of documents you've sent to other parties for signature.",
|
||||
"Drafts":"This are documents you have started but have not finalized for sending."
|
||||
},
|
||||
"enter-email-plaholder":"Add an email address and hit enter",
|
||||
"success-email-alert":"Email sent successfully!",
|
||||
"expired-doc-title":"Expired Document",
|
||||
"expired-on-mssg" :"This document expired on {{expiredDate}} and is no longer available to sign.",
|
||||
"signature-validate-alert":"Please confirm that you have selected at least {{minRequiredCount}} checkboxes.",
|
||||
"signature-validate-alert-2" :"Ensure this field is accurately filled and meets all requirements.",
|
||||
"user-name-exist":"user name already exist"
|
||||
|
||||
|
||||
|
||||
},
|
||||
"enter-email-plaholder":"Add an email address and hit enter",
|
||||
"success-email-alert":"Email sent successfully!",
|
||||
"expired-doc-title":"Expired Document",
|
||||
"expired-on-mssg" :"This document expired on {{expiredDate}} and is no longer available to sign.",
|
||||
"signature-validate-alert":"Please confirm that you have selected at least {{minRequiredCount}} checkboxes.",
|
||||
"signature-validate-alert-2" :"Ensure this field is accurately filled and meets all requirements.",
|
||||
"remaing-users":"Remaining users",
|
||||
"Role":"Role",
|
||||
"additional-users":"Please purchase add-on users.",
|
||||
"Quantity-of-users":"Quantity of users",
|
||||
"Price":"Price",
|
||||
"Total-price-for-next-time":"Total price for next time",
|
||||
"Proceed":"Proceed",
|
||||
"Select":"Select",
|
||||
"Add-seats":"Add Seats",
|
||||
"user-name-exist":"user name already exist"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
"subscribe-card-plan":"Signez 100 documents à l'aide de l'API. Seulement 0,15 $/doc par la suite.",
|
||||
"user-name-limit-char" :"Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner",
|
||||
"tour-content":"Ne plus afficher",
|
||||
"team":"ÉQUIPE",
|
||||
"team":"Équipe",
|
||||
"docs":"Documents",
|
||||
"session-expired" :"Votre session a expiré.",
|
||||
"user":"Utilisateur",
|
||||
@@ -585,19 +585,24 @@
|
||||
"Recent signature requests": "Voici une liste de documents qui attendent votre signature.",
|
||||
"Recently sent for signatures":"Il s'agit d'une liste de documents que vous avez envoyés à d'autres parties pour signature.",
|
||||
"Drafts":"Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi."
|
||||
},
|
||||
"enter-email-plaholder":"Ajoutez une adresse email et appuyez sur Entrée",
|
||||
"success-email-alert" :"E-mail envoyé avec succès!",
|
||||
"expired-doc-title" :"Document expiré",
|
||||
"expired-on-mssg" :"Ce document a expiré le {{expiredDate}} et n'est plus disponible pour signature.",
|
||||
"signature-validate-alert":"Veuillez confirmer que vous avez coché au moins {{minRequiredCount}} cases.",
|
||||
|
||||
},
|
||||
"enter-email-plaholder":"Ajoutez une adresse email et appuyez sur Entrée",
|
||||
"success-email-alert" :"E-mail envoyé avec succès!",
|
||||
"expired-doc-title" :"Document expiré",
|
||||
"expired-on-mssg" :"Ce document a expiré le {{expiredDate}} et n'est plus disponible pour signature.",
|
||||
"signature-validate-alert":"Veuillez confirmer que vous avez coché au moins {{minRequiredCount}} cases.",
|
||||
"signature-validate-alert-2" :"Assurez-vous que ce champ est rempli avec précision et répond à toutes les exigences.",
|
||||
"user-name-exist" :"le nom d'utilisateur existe déjà"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"user-name-exist" :"le nom d'utilisateur existe déjà",
|
||||
"remaing-users":"Utilisateurs restants",
|
||||
"Role":"Rôle",
|
||||
"additional-users":"Veuillez acheter des utilisateurs supplémentaires.",
|
||||
"Quantity-of-users":"Quantité d'utilisateurs",
|
||||
"Price":"Prix",
|
||||
"Total-price-for-next-time":"Prix total pour la prochaine fois",
|
||||
"Proceed":"Procéder",
|
||||
"Select":"sélectionner",
|
||||
"Add-seats":"Ajouter des sièges"
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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";
|
||||
import { useTranslation } from "react-i18next";
|
||||
function generatePassword(length) {
|
||||
const characters =
|
||||
@@ -27,8 +28,22 @@ 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,
|
||||
totalAllowedUser: 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(() => {
|
||||
@@ -36,6 +51,40 @@ 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,
|
||||
totalAllowedUser: resSub.totalAllowedUser
|
||||
}));
|
||||
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) {
|
||||
@@ -67,11 +116,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: t("user-already-exist") });
|
||||
setIsLoader(false);
|
||||
setIsFormLoader(false);
|
||||
setTimeout(() => {
|
||||
props.setIsAlert({ type: "success", msg: "" });
|
||||
}, 1000);
|
||||
@@ -157,14 +206,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);
|
||||
@@ -204,19 +247,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: t("something-went-wrong-mssg")
|
||||
@@ -229,13 +266,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();
|
||||
}
|
||||
@@ -256,164 +287,283 @@ const AddUser = (props) => {
|
||||
props.setIsAlert({ type: "success", msg: t("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) {
|
||||
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||
if (_resAddon.status === "success") {
|
||||
setAllowedUser(_resAddon.addon);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in buy addon", err);
|
||||
props.setIsAlert({
|
||||
type: "danger",
|
||||
msg: t("something-went-wrong-mssg")
|
||||
});
|
||||
} 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"
|
||||
>
|
||||
{t("name")}
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
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 ? t("add-user") : t("Add-seats")}
|
||||
handleClose={props.closePopup}
|
||||
>
|
||||
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
|
||||
<Title title={t("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"
|
||||
>
|
||||
{t("email")}
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value={formdata.email}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
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}>
|
||||
<p className="flex justify-center mb-1">
|
||||
{t("remaing-users")}{" "}
|
||||
<span
|
||||
className={`${
|
||||
allowedUser < 2 ? "op-text-accent" : "op-text-primary"
|
||||
} font-medium ml-1`}
|
||||
>
|
||||
{allowedUser} of {planInfo.totalAllowedUser}
|
||||
</span>
|
||||
</p>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
{t("name")}
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
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"
|
||||
>
|
||||
{t("email")}
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value={formdata.email}
|
||||
onChange={(e) => handleChange(e)}
|
||||
required
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
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 className="block text-xs text-gray-700 font-semibold">
|
||||
{t("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">
|
||||
{t("password-generateed")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
{t("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"
|
||||
>
|
||||
{t("team")}
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<select
|
||||
name="team"
|
||||
value={formdata.team}
|
||||
onChange={(e) => handleChange(e)}
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
>
|
||||
<option defaultValue={""} value={""}>
|
||||
{t("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"
|
||||
>
|
||||
{t("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"
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
>
|
||||
<option defaultValue={""} value={""}>
|
||||
{t("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">
|
||||
{t("submit")}
|
||||
</button>
|
||||
<div
|
||||
type="button"
|
||||
onClick={() => handleReset()}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
{t("cancel")}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<form onSubmit={handleAddOnSubmit}>
|
||||
<p className="flex justify-center text-center mx-2 mb-3 text-base op-text-accent font-medium">
|
||||
{t("additional-users")}
|
||||
</p>
|
||||
<div className="mb-3 flex justify-between">
|
||||
<label
|
||||
htmlFor="quantity"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
{t("Quantity-of-users")}
|
||||
<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">
|
||||
{t("Price")} (1 * {planInfo.priceperUser})
|
||||
</label>
|
||||
<div className="w-1/4 flex justify-center items-center text-sm">
|
||||
USD {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">
|
||||
{t("Total-price-for-next-time")}
|
||||
</label>
|
||||
<div className="w-1/4 flex justify-center items-center text-sm font-semibold">
|
||||
USD {amount.totalPrice}
|
||||
</div>
|
||||
</div>
|
||||
<button className="op-btn op-btn-primary w-full mt-2">
|
||||
{t("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"
|
||||
>
|
||||
{t("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">
|
||||
{t("password-generateed")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
{t("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"
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
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"
|
||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ import Parse from "parse";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import {
|
||||
checkIsSubscribed,
|
||||
checkIsSubscribedTeam,
|
||||
getAppLogo,
|
||||
openInNewTab,
|
||||
saveLanguageInLocal
|
||||
} from "../constant/Utils";
|
||||
import { isEnableSubscription, isStaging } from "../constant/const";
|
||||
import { paidUrl, validplan } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Header = ({ showSidebar }) => {
|
||||
@@ -22,8 +22,7 @@ const Header = ({ showSidebar }) => {
|
||||
const image = localStorage.getItem("profileImg") || dp;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(true);
|
||||
const [isPro, setIsPro] = useState(false);
|
||||
const [isTeam, setIsTeam] = useState(false);
|
||||
const [isTeam, setIsTeam] = useState({ plan: "", isValid: false });
|
||||
const [applogo, setAppLogo] = useState(
|
||||
localStorage.getItem("appLogo") || " "
|
||||
);
|
||||
@@ -37,9 +36,8 @@ const Header = ({ showSidebar }) => {
|
||||
}, []);
|
||||
async function checkSubscription() {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
const getIsTeam = await checkIsSubscribedTeam();
|
||||
if (getIsSubscribe) {
|
||||
const subscribe = await checkIsSubscribed();
|
||||
if (subscribe.isValid) {
|
||||
const applogo = await getAppLogo();
|
||||
if (applogo?.logo) {
|
||||
setAppLogo(applogo?.logo);
|
||||
@@ -47,9 +45,8 @@ const Header = ({ showSidebar }) => {
|
||||
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||
}
|
||||
}
|
||||
setIsPro(getIsSubscribe);
|
||||
setIsTeam(getIsTeam);
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
setIsTeam(subscribe);
|
||||
setIsSubscribe(subscribe.isValid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +100,14 @@ const Header = ({ showSidebar }) => {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
}
|
||||
};
|
||||
const handleNavigation = () => {
|
||||
const route = paidUrl(isTeam.plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="op-navbar bg-base-100 shadow">
|
||||
<div className="flex-none">
|
||||
@@ -127,18 +132,18 @@ const Header = ({ showSidebar }) => {
|
||||
<div>
|
||||
<button
|
||||
className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent"
|
||||
onClick={() => navigate("/subscription")}
|
||||
onClick={() => handleNavigation()}
|
||||
>
|
||||
{t("upgrade-now")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{!isTeam && isPro && (
|
||||
{isTeam.isValid && !validplan[isTeam.plan] && (
|
||||
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||
{t("pro")}
|
||||
</div>
|
||||
)}
|
||||
{isTeam && (
|
||||
{validplan[isTeam.plan] && (
|
||||
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] text-[13px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||
{t("team")}
|
||||
</div>
|
||||
|
||||
@@ -23,8 +23,8 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
}, []);
|
||||
const fetchSubscription = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe.isValid);
|
||||
}
|
||||
};
|
||||
const handleStrInput = (e) => {
|
||||
|
||||
@@ -63,6 +63,8 @@ export async function fetchSubscription(
|
||||
} else {
|
||||
plan = tenatRes.data?.result?.result?.PlanCode;
|
||||
billingDate = tenatRes.data?.result?.result?.Next_billing_date?.iso;
|
||||
const allowedUsers = tenatRes.data?.result?.result?.AllowedUsers || 0;
|
||||
localStorage.setItem("allowedUsers", allowedUsers);
|
||||
}
|
||||
return { plan, billingDate, status };
|
||||
} catch (err) {
|
||||
@@ -70,46 +72,72 @@ 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;
|
||||
const totalAllowedUser = tenatRes.data?.result?.result?.AllowedUsers || 0;
|
||||
return {
|
||||
status: "success",
|
||||
price: price,
|
||||
totalPrice: totalPrice,
|
||||
planId: planId,
|
||||
plan_code: plan_code,
|
||||
totalAllowedUser: totalAllowedUser
|
||||
};
|
||||
}
|
||||
} 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 {
|
||||
const res = await fetchSubscription();
|
||||
if (res.plan === "freeplan") {
|
||||
return false;
|
||||
} else if (res.billingDate) {
|
||||
if (new Date(res.billingDate) > new Date()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in fetch subscription", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//function to get subcripition details from subscription class
|
||||
export async function checkIsSubscribedTeam() {
|
||||
try {
|
||||
const res = await fetchSubscription();
|
||||
if (res.plan === "freeplan") {
|
||||
return false;
|
||||
return { plan: res.plan, isValid: false };
|
||||
} else if (res.billingDate) {
|
||||
const plan = validplan[res.plan] || false;
|
||||
if (plan && new Date(res.billingDate) > new Date()) {
|
||||
return true;
|
||||
return { plan: res.plan, isValid: true };
|
||||
} else if (new Date(res.billingDate) > new Date()) {
|
||||
return { plan: res.plan, isValid: true };
|
||||
} else {
|
||||
return false;
|
||||
return { plan: res.plan, isValid: false };
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
return { plan: res.plan, isValid: false };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in fetch subscription", err);
|
||||
return false;
|
||||
return { plan: "no-plan", isValid: false };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { serverUrl_fn } from "./appinfo";
|
||||
const parseAppId = process.env.REACT_APP_APPID
|
||||
? process.env.REACT_APP_APPID
|
||||
: "opensign";
|
||||
const serverUrl = serverUrl_fn()
|
||||
const serverUrl = serverUrl_fn();
|
||||
export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
||||
//checking server url and save file's size
|
||||
const tenantPtr = {
|
||||
|
||||
@@ -26,7 +26,7 @@ body {
|
||||
.op-bg-info {
|
||||
@apply bg-info;
|
||||
}
|
||||
.op-bg-success{
|
||||
.op-bg-success {
|
||||
@apply bg-success;
|
||||
}
|
||||
.op-bg-warning {
|
||||
@@ -43,14 +43,17 @@ body {
|
||||
.op-text-info {
|
||||
@apply text-info;
|
||||
}
|
||||
.op-text-success{
|
||||
.op-text-accent {
|
||||
@apply text-accent;
|
||||
}
|
||||
.op-text-success {
|
||||
@apply text-success;
|
||||
}
|
||||
.op-text-warning {
|
||||
@apply text-warning;
|
||||
}
|
||||
.op-border-primary{
|
||||
@apply border-primary
|
||||
.op-border-primary {
|
||||
@apply border-primary;
|
||||
}
|
||||
/* CSS for scrollbar customization */
|
||||
* {
|
||||
@@ -70,4 +73,4 @@ body {
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: gray;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { isStaging } from "../constant/const";
|
||||
const plans = [
|
||||
{
|
||||
planName: "OPENSIGN™ FREE",
|
||||
code: { monthly: "freeplan", yearly: "freeplan" },
|
||||
img: "free.png",
|
||||
currency: "",
|
||||
monthlyPrice: "Free",
|
||||
@@ -52,6 +53,9 @@ const plans = [
|
||||
},
|
||||
{
|
||||
planName: "OPENSIGN™ PROFESSIONAL",
|
||||
code: isStaging
|
||||
? { monthly: "pro-weekly", yearly: "pro-yearly" }
|
||||
: { monthly: "professional-monthly", yearly: "professional-yearly" },
|
||||
img: "professional.png",
|
||||
currency: "$",
|
||||
monthlyPrice: "29.99",
|
||||
@@ -98,6 +102,7 @@ const plans = [
|
||||
},
|
||||
{
|
||||
planName: "OPENSIGN™ TEAMS",
|
||||
code: { monthly: "teams-monthly", yearly: "teams-yearly" },
|
||||
img: "teams.png",
|
||||
currency: "$",
|
||||
monthlyPrice: `39.99<sup style="font-size: 17px;">/user</sup>`,
|
||||
@@ -105,10 +110,10 @@ const plans = [
|
||||
subtitle: "Exclusive Access to advanced features.",
|
||||
btn: { text: "Subscribe", color: "op-btn-accent" },
|
||||
url: isStaging
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-monthly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly",
|
||||
yearlyUrl: isStaging
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-yearly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly",
|
||||
target: "_self",
|
||||
benefits: [
|
||||
@@ -171,4 +176,72 @@ export const validplan = {
|
||||
"enterprise-monthly": true,
|
||||
"enterprise-yearly": true
|
||||
};
|
||||
export const paidUrl = (plan) => {
|
||||
const teamperiod = {
|
||||
"team-weekly": "monthly",
|
||||
"team-yearly": "yearly",
|
||||
"teams-monthly": "monthly",
|
||||
"teams-yearly": "yearly"
|
||||
};
|
||||
const period = teamperiod[plan] || "";
|
||||
if (period) {
|
||||
const extUser =
|
||||
localStorage.getItem("Extand_Class") &&
|
||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
const user = {
|
||||
name: extUser?.Name,
|
||||
email: extUser?.Email,
|
||||
company: extUser?.Company,
|
||||
phone: extUser?.Phone
|
||||
};
|
||||
// console.log("userDetails ", userDetails);
|
||||
const fullname = user && user.name ? user.name.split(" ") : "";
|
||||
const firstname = fullname?.[0]
|
||||
? "first_name=" + encodeURIComponent(fullname?.[0])
|
||||
: "";
|
||||
const lastname = fullname?.[1]
|
||||
? "&last_name=" + encodeURIComponent(fullname?.[1])
|
||||
: "";
|
||||
const name = firstname ? firstname + lastname : "";
|
||||
const email =
|
||||
user && user.email ? "&email=" + encodeURIComponent(user.email) : "";
|
||||
const company =
|
||||
user && user.company
|
||||
? "&company_name=" + encodeURIComponent(user.company)
|
||||
: "";
|
||||
const phone =
|
||||
user && user.phone ? "&mobile=" + encodeURIComponent(user.phone) : "";
|
||||
const allowedUsers = localStorage.getItem("allowedUsers")
|
||||
? localStorage.getItem("allowedUsers") - 1
|
||||
: "";
|
||||
const quantity = allowedUsers
|
||||
? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&`
|
||||
: "";
|
||||
|
||||
const details =
|
||||
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
||||
quantity +
|
||||
name +
|
||||
email +
|
||||
company +
|
||||
phone;
|
||||
|
||||
if (user) {
|
||||
localStorage.setItem("userDetails", JSON.stringify(user));
|
||||
}
|
||||
const url = {
|
||||
monthly: isStaging
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-monthly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly",
|
||||
yearly: isStaging
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-yearly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly"
|
||||
};
|
||||
|
||||
const planurl = url[period] + details;
|
||||
return planurl;
|
||||
} else {
|
||||
return "/subscription";
|
||||
}
|
||||
};
|
||||
export default plans;
|
||||
|
||||
@@ -11,9 +11,10 @@ import ModalUi from "../primitives/ModalUi";
|
||||
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { useCookies } from "react-cookie";
|
||||
import { fetchSubscription } from "../constant/Utils";
|
||||
import { fetchSubscription, openInNewTab } from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { showHeader } from "../redux/reducers/showHeader";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const HomeLayout = () => {
|
||||
@@ -95,7 +96,14 @@ const HomeLayout = () => {
|
||||
domain: updateDomain
|
||||
});
|
||||
};
|
||||
|
||||
const handleNavigation = (plan) => {
|
||||
const route = paidUrl(plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
async function checkIsSubscribed() {
|
||||
if (isEnableSubscription) {
|
||||
const res = await fetchSubscription();
|
||||
@@ -107,10 +115,10 @@ const HomeLayout = () => {
|
||||
setIsUserValid(true);
|
||||
setIsLoader(false);
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handleNavigation(res.plan);
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handleNavigation(res.plan);
|
||||
}
|
||||
} else {
|
||||
setIsUserValid(true);
|
||||
|
||||
@@ -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"} />
|
||||
|
||||
@@ -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 Parse from "parse";
|
||||
import DropboxChooser from "../components/shared/fields/DropboxChoose";
|
||||
import Alert from "../primitives/Alert";
|
||||
@@ -37,15 +36,11 @@ function generatePdfName(length) {
|
||||
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"} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,8 +90,8 @@ const Forms = (props) => {
|
||||
}, []);
|
||||
const fetchSubscription = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe.isValid);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import Tooltip from "../primitives/Tooltip";
|
||||
import Loader from "../primitives/Loader";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
import Tour from "reactour";
|
||||
import { validplan } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function GenerateToken() {
|
||||
@@ -18,7 +19,7 @@ function GenerateToken() {
|
||||
const [apiToken, SetApiToken] = useState("");
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false });
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isTour, setIsTour] = useState(false);
|
||||
useEffect(() => {
|
||||
@@ -34,8 +35,8 @@ function GenerateToken() {
|
||||
const fetchToken = async () => {
|
||||
try {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe);
|
||||
}
|
||||
const url = parseBaseUrl + "functions/getapitoken";
|
||||
const headers = {
|
||||
@@ -56,7 +57,7 @@ function GenerateToken() {
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
if (!isSubscribe && isEnableSubscription) {
|
||||
if (!validplan[isSubscribe.plan] && isEnableSubscription) {
|
||||
setIsTour(true);
|
||||
} else {
|
||||
setIsLoader(true);
|
||||
@@ -100,11 +101,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 />
|
||||
@@ -128,7 +125,7 @@ function GenerateToken() {
|
||||
<span
|
||||
id="token"
|
||||
className={`${
|
||||
isSubscribe
|
||||
validplan[isSubscribe.plan]
|
||||
? ""
|
||||
: "bg-white/20 pointer-events-none select-none"
|
||||
} md:text-end py-2 md:py-0`}
|
||||
@@ -195,9 +192,9 @@ function GenerateToken() {
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
{!validplan[isSubscribe.plan] && isEnableSubscription && (
|
||||
<div data-tut="apisubscribe">
|
||||
<SubscribeCard />
|
||||
<SubscribeCard plan_code={isSubscribe.plan} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
saveLanguageInLocal
|
||||
} from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||
|
||||
@@ -80,7 +81,14 @@ function Login() {
|
||||
}
|
||||
setState({ ...state, [name]: value });
|
||||
};
|
||||
|
||||
const handlePaidRoute = (plan) => {
|
||||
const route = paidUrl(plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
const handleSubmit = async (event) => {
|
||||
localStorage.removeItem("accesstoken");
|
||||
event.preventDefault();
|
||||
@@ -158,9 +166,9 @@ function Login() {
|
||||
JSON.stringify(LocalUserDetails)
|
||||
);
|
||||
const res = await fetchSubscription();
|
||||
const freeplan = res.plan;
|
||||
const plan = res.plan;
|
||||
const billingDate = res.billingDate;
|
||||
if (freeplan === "freeplan") {
|
||||
if (plan === "freeplan") {
|
||||
setState({ ...state, loading: false });
|
||||
navigate(redirectUrl);
|
||||
} else if (billingDate) {
|
||||
@@ -171,11 +179,11 @@ function Login() {
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
navigate(`/subscription`, { replace: true });
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
navigate(`/subscription`, { replace: true });
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
@@ -330,9 +338,9 @@ function Login() {
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
if (isEnableSubscription) {
|
||||
const res = await fetchSubscription();
|
||||
const freeplan = res.plan;
|
||||
const plan = res.plan;
|
||||
const billingDate = res.billingDate;
|
||||
if (freeplan === "freeplan") {
|
||||
if (plan === "freeplan") {
|
||||
navigate(redirectUrl);
|
||||
} else if (billingDate) {
|
||||
if (new Date(billingDate) > new Date()) {
|
||||
@@ -342,14 +350,14 @@ function Login() {
|
||||
if (isFreeplan) {
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isFreeplan) {
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -462,8 +470,8 @@ function Login() {
|
||||
localStorage.setItem("userDetails", JSON.stringify(userInfo));
|
||||
const res = await fetchSubscription();
|
||||
const billingDate = res.billingDate;
|
||||
const freeplan = res.plan;
|
||||
if (freeplan === "freeplan") {
|
||||
const plan = res.plan;
|
||||
if (plan === "freeplan") {
|
||||
navigate(redirectUrl);
|
||||
} else if (billingDate) {
|
||||
if (new Date(billingDate) > new Date()) {
|
||||
@@ -471,10 +479,10 @@ function Login() {
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
} else {
|
||||
// Redirect to the appropriate URL after successful login
|
||||
@@ -789,9 +797,7 @@ function Login() {
|
||||
</div>
|
||||
<SelectLanguage />
|
||||
{state.alertMsg && (
|
||||
<Alert type={state.alertType}>
|
||||
<div className="ml-3">{state.alertMsg}</div>
|
||||
</Alert>
|
||||
<Alert type={state.alertType}>{state.alertMsg}</Alert>
|
||||
)}
|
||||
</div>
|
||||
<ModalUi
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
handleDownloadPdf,
|
||||
handleToPrint,
|
||||
handleDownloadCertificate,
|
||||
openInNewTab,
|
||||
getDefaultSignature
|
||||
} from "../constant/Utils";
|
||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||
@@ -47,6 +48,7 @@ import { useSelector } from "react-redux";
|
||||
import SignerListComponent from "../components/pdf/SignerListComponent";
|
||||
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function PdfRequestFiles(props) {
|
||||
@@ -232,6 +234,15 @@ function PdfRequestFiles(props) {
|
||||
const currentUser = JSON.parse(localuser);
|
||||
await handleSendOTP(currentUser?.email);
|
||||
};
|
||||
|
||||
const handleNavigation = (plan) => {
|
||||
const route = paidUrl(plan);
|
||||
if (route === "/subscription") {
|
||||
window.location.href = route;
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
async function checkIsSubscribed(extUserId, contactId) {
|
||||
const isGuestSign = isGuestSignFlow || false;
|
||||
const res = await fetchSubscription(extUserId, contactId, isGuestSign);
|
||||
@@ -248,7 +259,7 @@ function PdfRequestFiles(props) {
|
||||
if (isGuestSign) {
|
||||
setIsSubscriptionExpired(true);
|
||||
} else {
|
||||
window.location.href = "/subscription";
|
||||
handleNavigation(plan);
|
||||
}
|
||||
}
|
||||
} else if (isGuestSign) {
|
||||
@@ -262,7 +273,7 @@ function PdfRequestFiles(props) {
|
||||
if (isGuestSign) {
|
||||
setIsSubscriptionExpired(true);
|
||||
} else {
|
||||
window.location.href = "/subscription";
|
||||
handleNavigation(res.plan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ import {
|
||||
copytoData,
|
||||
fetchSubscription,
|
||||
convertPdfArrayBuffer,
|
||||
getContainerScale
|
||||
getContainerScale,
|
||||
openInNewTab
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -53,6 +54,7 @@ import Loader from "../primitives/Loader";
|
||||
import { useSelector } from "react-redux";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import LottieWithLoader from "../primitives/DotLottieReact";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function PlaceHolderSign() {
|
||||
@@ -233,22 +235,29 @@ function PlaceHolderSign() {
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current, isHeader]);
|
||||
|
||||
const handleNavigation = (plan) => {
|
||||
const route = paidUrl(plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
async function checkIsSubscribed() {
|
||||
const res = await fetchSubscription();
|
||||
const freeplan = res.plan;
|
||||
const plan = res.plan;
|
||||
const billingDate = res.billingDate;
|
||||
if (freeplan === "freeplan") {
|
||||
if (plan === "freeplan") {
|
||||
return true;
|
||||
} else if (billingDate) {
|
||||
if (new Date(billingDate) > new Date()) {
|
||||
setIsSubscribe(true);
|
||||
return true;
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handleNavigation(plan);
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handleNavigation(plan);
|
||||
}
|
||||
}
|
||||
//function for get document details
|
||||
@@ -1048,11 +1057,7 @@ function PlaceHolderSign() {
|
||||
className="flex flex-row justify-between items-center mb-1"
|
||||
key={ind}
|
||||
>
|
||||
{copied && (
|
||||
<Alert type="success">
|
||||
<div className="ml-3">{t("copied")}</div>
|
||||
</Alert>
|
||||
)}
|
||||
{copied && <Alert type="success">{t("copied")}</Alert>}
|
||||
<span className="w-[220px] md:w-[300px] whitespace-nowrap overflow-hidden text-ellipsis ">
|
||||
{data.signerEmail}
|
||||
</span>
|
||||
|
||||
@@ -53,12 +53,6 @@ const PlanSubscriptions = () => {
|
||||
? "&mobile=" + encodeURIComponent(userDetails.phone)
|
||||
: "";
|
||||
|
||||
const details =
|
||||
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
||||
name +
|
||||
email +
|
||||
company +
|
||||
phone;
|
||||
useEffect(() => {
|
||||
setIsLoader(false);
|
||||
detectLanguage();
|
||||
@@ -72,6 +66,30 @@ const PlanSubscriptions = () => {
|
||||
|
||||
const handleFreePlan = async (item) => {
|
||||
if (item.url) {
|
||||
const code = yearlyVisible ? item.code.yearly : item.code.monthly;
|
||||
const allowedUsers = localStorage.getItem("allowedUsers")
|
||||
? localStorage.getItem("allowedUsers") - 1
|
||||
: "";
|
||||
const teamperiod = {
|
||||
"team-weekly": "monthly",
|
||||
"team-yearly": "yearly",
|
||||
"teams-monthly": "monthly",
|
||||
"teams-yearly": "yearly"
|
||||
};
|
||||
const period = teamperiod[code] || "";
|
||||
|
||||
const quantity =
|
||||
allowedUsers && period
|
||||
? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&`
|
||||
: "";
|
||||
|
||||
const details =
|
||||
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
||||
quantity +
|
||||
name +
|
||||
email +
|
||||
company +
|
||||
phone;
|
||||
const url = yearlyVisible ? item.yearlyUrl + details : item.url + details;
|
||||
if (user) {
|
||||
localStorage.setItem("userDetails", JSON.stringify(user));
|
||||
|
||||
@@ -3,11 +3,12 @@ import { useLocation, useNavigate } from "react-router-dom";
|
||||
import Parse from "parse";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { fetchSubscription } from "../constant/Utils";
|
||||
import { fetchSubscription, openInNewTab } from "../constant/Utils";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const SSOVerify = () => {
|
||||
@@ -50,6 +51,14 @@ const SSOVerify = () => {
|
||||
console.log("err", err.message);
|
||||
}
|
||||
};
|
||||
const handlePaidRoute = (plan) => {
|
||||
const route = paidUrl(plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
const checkExtUser = async (ssosign) => {
|
||||
const params = { email: ssosign?.email };
|
||||
try {
|
||||
@@ -196,10 +205,10 @@ const SSOVerify = () => {
|
||||
localStorage.removeItem("userDetails");
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
handlePaidRoute(plan);
|
||||
}
|
||||
} else {
|
||||
navigate(redirectUrl);
|
||||
|
||||
@@ -748,7 +748,7 @@ function SignYourSelf() {
|
||||
if (
|
||||
tenantDetails?.CompletionBody &&
|
||||
tenantDetails?.CompletionSubject &&
|
||||
getIsSubscribe
|
||||
getIsSubscribe.isValid
|
||||
) {
|
||||
isCustomCompletionMail = true;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ import ModalUi from "../primitives/ModalUi";
|
||||
import pad from "../assets/images/pad.svg";
|
||||
import AddTeam from "../components/AddTeam";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribedTeam } from "../constant/Utils";
|
||||
import { checkIsSubscribed } from "../constant/Utils";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
import Title from "../components/Title";
|
||||
import { validplan } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const heading = ["Sr.No", "Name", "Parent Team", "Active"];
|
||||
@@ -38,7 +39,7 @@ const TeamList = () => {
|
||||
const [isActiveModal, setIsActiveModal] = useState({});
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isActLoader, setIsActLoader] = useState({});
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false });
|
||||
const [isEditModal, setIsEditModal] = useState({});
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||
@@ -103,8 +104,8 @@ const TeamList = () => {
|
||||
try {
|
||||
setIsLoader(true);
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe);
|
||||
}
|
||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
if (extUser) {
|
||||
@@ -225,15 +226,11 @@ const TeamList = () => {
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{isSubscribe && isEnableSubscription && !isLoader && (
|
||||
{validplan[isSubscribe.plan] && isEnableSubscription && !isLoader && (
|
||||
<>
|
||||
{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">
|
||||
{t("report-name.Teams")}
|
||||
@@ -470,9 +467,13 @@ const TeamList = () => {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isSubscribe && isEnableSubscription && !isLoader && (
|
||||
{!validplan[isSubscribe.plan] && isEnableSubscription && !isLoader && (
|
||||
<div data-tut="apisubscribe">
|
||||
<SubscribeCard plan={"TEAMS"} price={"20"} />
|
||||
<SubscribeCard
|
||||
plan={"TEAMS"}
|
||||
price={"20"}
|
||||
plan_code={isSubscribe.plan}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,8 @@ import {
|
||||
textInputWidget,
|
||||
radioButtonWidget,
|
||||
fetchSubscription,
|
||||
getContainerScale
|
||||
getContainerScale,
|
||||
openInNewTab
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import "../styles/AddUser.css";
|
||||
@@ -40,6 +41,7 @@ import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||
import Parse from "parse";
|
||||
import { useSelector } from "react-redux";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const TemplatePlaceholder = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -181,21 +183,30 @@ const TemplatePlaceholder = () => {
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current, isHeader]);
|
||||
|
||||
const handleNavigation = (plan) => {
|
||||
const route = paidUrl(plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
async function checkIsSubscribed() {
|
||||
const res = await fetchSubscription();
|
||||
const freeplan = res.plan;
|
||||
const plan = res.plan;
|
||||
const billingDate = res.billingDate;
|
||||
if (freeplan === "freeplan") {
|
||||
if (plan === "freeplan") {
|
||||
return true;
|
||||
} else if (billingDate) {
|
||||
if (new Date(billingDate) > new Date()) {
|
||||
setIsSubscribe(true);
|
||||
return true;
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handleNavigation(plan);
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
handleNavigation(plan);
|
||||
}
|
||||
}
|
||||
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
||||
|
||||
@@ -65,12 +65,8 @@ 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>
|
||||
)}
|
||||
<Title title={"Add Admin"} />
|
||||
{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 />
|
||||
|
||||
@@ -9,8 +9,9 @@ import Tooltip from "../primitives/Tooltip";
|
||||
import AddUser from "../components/AddUser";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribedTeam } from "../constant/Utils";
|
||||
import { checkIsSubscribed } from "../constant/Utils";
|
||||
import Title from "../components/Title";
|
||||
import { validplan } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||
// const actions = [];
|
||||
@@ -26,7 +27,7 @@ const UserList = () => {
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isActiveModal, setIsActiveModal] = useState({});
|
||||
const [isActLoader, setIsActLoader] = useState({});
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false });
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const recordperPage = 10;
|
||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||
@@ -91,10 +92,10 @@ const UserList = () => {
|
||||
try {
|
||||
setIsLoader(true);
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe);
|
||||
} else {
|
||||
setIsSubscribe(true);
|
||||
setIsSubscribe({ plan: "teams-yearly", isValid: true });
|
||||
}
|
||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
if (extUser) {
|
||||
@@ -197,15 +198,11 @@ const UserList = () => {
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{isSubscribe && !isLoader && (
|
||||
{validplan[isSubscribe.plan] && !isLoader && (
|
||||
<>
|
||||
{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">
|
||||
{t("report-name.Users")}
|
||||
@@ -396,17 +393,12 @@ const UserList = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<ModalUi
|
||||
title={t("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">
|
||||
@@ -422,9 +414,13 @@ const UserList = () => {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isSubscribe && isEnableSubscription && !isLoader && (
|
||||
{!validplan[isSubscribe.plan] && isEnableSubscription && !isLoader && (
|
||||
<div data-tut="apisubscribe">
|
||||
<SubscribeCard plan={"TEAMS"} price={"20"} />
|
||||
<SubscribeCard
|
||||
plan={"TEAMS"}
|
||||
price={"20"}
|
||||
plan_code={isSubscribe.plan}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,6 @@ import Tooltip from "../primitives/Tooltip";
|
||||
import { isEnableSubscription, isStaging } from "../constant/const";
|
||||
import {
|
||||
checkIsSubscribed,
|
||||
checkIsSubscribedTeam,
|
||||
copytoData,
|
||||
handleSendOTP,
|
||||
openInNewTab
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
import Upgrade from "../primitives/Upgrade";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { paidUrl, validplan } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||
import { RWebShare } from "react-web-share";
|
||||
@@ -39,7 +39,7 @@ function UserProfile() {
|
||||
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isUpgrade, setIsUpgrade] = useState(false);
|
||||
const [isAlert, setIsAlert] = useState({});
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", message: "" });
|
||||
const [publicUserName, setPublicUserName] = useState(
|
||||
extendUser && extendUser?.[0]?.UserName
|
||||
);
|
||||
@@ -57,7 +57,7 @@ function UserProfile() {
|
||||
const [tagLine, setTagLine] = useState(
|
||||
extendUser && extendUser?.[0]?.Tagline
|
||||
);
|
||||
const [isTeam, setIsTeam] = useState(false);
|
||||
const [isPlan, setIsPlan] = useState({ plan: "", isValid: false });
|
||||
const getPublicUrl = isStaging
|
||||
? `https://staging.opensign.me/${extendUser?.[0]?.UserName}`
|
||||
: `https://opensign.me/${extendUser?.[0]?.UserName}`;
|
||||
@@ -72,10 +72,9 @@ function UserProfile() {
|
||||
const jsonSender = JSON.parse(extClass);
|
||||
const HeaderDocId = jsonSender[0]?.HeaderDocId;
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
const getIsTeam = await checkIsSubscribedTeam();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
setIsTeam(getIsTeam);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe.isValid);
|
||||
setIsPlan(subscribe);
|
||||
}
|
||||
if (HeaderDocId) {
|
||||
setIsDisableDocId(HeaderDocId);
|
||||
@@ -109,13 +108,8 @@ function UserProfile() {
|
||||
});
|
||||
if (res) {
|
||||
setIsLoader(false);
|
||||
setIsAlert({
|
||||
type: "danger",
|
||||
message: t("user-name-exist")
|
||||
});
|
||||
setTimeout(() => {
|
||||
setIsAlert({});
|
||||
}, 3000);
|
||||
setIsAlert({ type: "danger", message: t("user-name-exist") });
|
||||
setTimeout(() => setIsAlert({}), 3000);
|
||||
return res;
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -320,15 +314,19 @@ function UserProfile() {
|
||||
setJobTitle(extendUser?.[0]?.JobTitle);
|
||||
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
|
||||
};
|
||||
const handlePaidRoute = () => {
|
||||
const route = paidUrl(isPlan.plan);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
|
||||
const copytoclipboard = () => {
|
||||
copytoData(getPublicUrl);
|
||||
setIsAlert({
|
||||
type: "success",
|
||||
message: t("copied")
|
||||
});
|
||||
setTimeout(() => {
|
||||
setIsAlert({});
|
||||
}, 3000);
|
||||
setIsAlert({ type: "success", message: t("copied") });
|
||||
setTimeout(() => setIsAlert({}), 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -340,12 +338,11 @@ function UserProfile() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-center items-center w-full relative">
|
||||
{isAlert && (
|
||||
{isAlert.message && (
|
||||
<Alert className="z-[1000] fixed top-[10%]" type={isAlert.type}>
|
||||
{isAlert.message}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]">
|
||||
<div className="flex flex-col justify-center items-center my-4">
|
||||
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
|
||||
@@ -516,9 +513,7 @@ function UserProfile() {
|
||||
<span
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
onClick={() => {
|
||||
openInNewTab(getPublicUrl);
|
||||
}}
|
||||
onClick={() => openInNewTab(getPublicUrl)}
|
||||
className="cursor-pointer underline hover:text-blue-800 w-[200px] md:w-[150px] whitespace-nowrap overflow-hidden text-ellipsis"
|
||||
>
|
||||
{isStaging
|
||||
@@ -527,10 +522,7 @@ function UserProfile() {
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<RWebShare
|
||||
data={{
|
||||
url: getPublicUrl,
|
||||
title: "Sign url"
|
||||
}}
|
||||
data={{ url: getPublicUrl, title: "Sign url" }}
|
||||
>
|
||||
<button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm ">
|
||||
<i className="fa-light fa-share-from-square"></i>{" "}
|
||||
@@ -581,7 +573,9 @@ function UserProfile() {
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span
|
||||
className={
|
||||
isTeam ? "font-semibold" : "font-semibold text-gray-300"
|
||||
validplan[isPlan.plan]
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
{t("disable-documentId")} :{" "}
|
||||
@@ -590,17 +584,21 @@ function UserProfile() {
|
||||
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||
}
|
||||
/>
|
||||
{!isTeam && isEnableSubscription && <Upgrade />}
|
||||
{!validplan[isPlan.plan] && isEnableSubscription && (
|
||||
<Upgrade />
|
||||
)}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isTeam
|
||||
validplan[isPlan.plan]
|
||||
? `${editmode ? "cursor-pointer" : ""}`
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
disabled={isTeam ? false : true}
|
||||
disabled={
|
||||
validplan[isPlan.plan] && editmode ? false : true
|
||||
}
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={isDisableDocId}
|
||||
@@ -708,7 +706,7 @@ function UserProfile() {
|
||||
<p>{t("user-name-limit-char")}</p>
|
||||
<div className="op-card-actions justify-end">
|
||||
<button
|
||||
onClick={() => navigate("/subscription")}
|
||||
onClick={() => handlePaidRoute()}
|
||||
className="op-btn op-btn-accent"
|
||||
>
|
||||
{t("upgrade-now")}
|
||||
|
||||
@@ -10,6 +10,7 @@ import Tooltip from "../primitives/Tooltip";
|
||||
import Loader from "../primitives/Loader";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
import Tour from "reactour";
|
||||
import { validplan } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function Webhook() {
|
||||
@@ -19,7 +20,7 @@ function Webhook() {
|
||||
const [webhook, setWebhook] = useState();
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: true });
|
||||
const [error, setError] = useState("");
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isTour, setIsTour] = useState(false);
|
||||
@@ -35,8 +36,8 @@ function Webhook() {
|
||||
];
|
||||
const fetchWebhook = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe);
|
||||
}
|
||||
try {
|
||||
const extRes = await Parse.Cloud.run("getUserDetails");
|
||||
@@ -89,7 +90,7 @@ function Webhook() {
|
||||
};
|
||||
|
||||
const handleModal = () => {
|
||||
if (!isSubscribe && isEnableSubscription) {
|
||||
if (!validplan[isSubscribe.plan] && isEnableSubscription) {
|
||||
setIsTour(true);
|
||||
} else {
|
||||
setIsModal(!isModal);
|
||||
@@ -177,9 +178,9 @@ function Webhook() {
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
{!validplan[isSubscribe.plan] && isEnableSubscription && (
|
||||
<div data-tut="webhooksubscribe">
|
||||
<SubscribeCard />
|
||||
<SubscribeCard plan_code={isSubscribe.plan} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -25,8 +25,8 @@ const Alert = ({ children, type, className }) => {
|
||||
: "z-[1000] fixed top-20 left-1/2 transform -translate-x-1/2 text-sm"
|
||||
} `}
|
||||
>
|
||||
<div className={`op-alert ${textcolor} flex items-center`}>
|
||||
<span>{children}</span>
|
||||
<div className={`op-alert ${textcolor}`}>
|
||||
<span className="ml-3">{children}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import { RWebShare } from "react-web-share";
|
||||
import Tour from "reactour";
|
||||
import Parse from "parse";
|
||||
import {
|
||||
checkIsSubscribedTeam,
|
||||
checkIsSubscribed,
|
||||
copytoData,
|
||||
fetchUrl,
|
||||
replaceMailVaribles
|
||||
@@ -27,6 +27,7 @@ import BulkSendUi from "../components/BulkSendUi";
|
||||
import Loader from "./Loader";
|
||||
import Select from "react-select";
|
||||
import SubscribeCard from "./SubscribeCard";
|
||||
import { validplan } from "../json/plansArr";
|
||||
import { serverUrl_fn } from "../constant/appinfo";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@@ -355,10 +356,10 @@ const ReportTable = (props) => {
|
||||
handleBulkSend(item);
|
||||
} else if (act.action === "sharewith") {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
const subscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(subscribe);
|
||||
} else {
|
||||
setIsSubscribe(true);
|
||||
setIsSubscribe({ plan: "teams-yearly", isValid: true });
|
||||
}
|
||||
if (item?.SharedWith && item?.SharedWith.length > 0) {
|
||||
// below code is used to get existing sharewith teams and formated them as per react-select
|
||||
@@ -396,7 +397,7 @@ const ReportTable = (props) => {
|
||||
Templates: "contracts_Template"
|
||||
};
|
||||
try {
|
||||
const serverUrl = serverUrl_fn()
|
||||
const serverUrl = serverUrl_fn();
|
||||
const cls = clsObj[props.ReportName] || "contracts_Document";
|
||||
const url = serverUrl + `/classes/${cls}/`;
|
||||
const body =
|
||||
@@ -1478,114 +1479,120 @@ const ReportTable = (props) => {
|
||||
{isShareWith[item.objectId] && (
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||
{isSubscribe && isEnableSubscription && (
|
||||
<>
|
||||
{item?.Signers?.length > 0 ? (
|
||||
<div className="h-[150px] flex justify-center items-center mx-2">
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
{validplan[isSubscribe.plan] &&
|
||||
isEnableSubscription && (
|
||||
<>
|
||||
{item?.Signers?.length > 0 ? (
|
||||
<div className="h-[150px] flex justify-center items-center mx-2">
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<div className="text-base-content text-base text-center">
|
||||
{t("share-with-alert")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-base-content text-base text-center">
|
||||
{t("share-with-alert")}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{t("share-with")}
|
||||
</h3>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<form
|
||||
className="h-full w-full z-[1300] px-2 mt-3"
|
||||
onSubmit={(e) =>
|
||||
handleShareWith(e, item)
|
||||
}
|
||||
>
|
||||
<Select
|
||||
// onSortEnd={onSortEnd}
|
||||
distance={4}
|
||||
isMulti
|
||||
options={teamList}
|
||||
value={selectedTeam}
|
||||
onChange={onChange}
|
||||
closeMenuOnSelect
|
||||
required={true}
|
||||
noOptionsMessage={() =>
|
||||
t("team-not-found")
|
||||
) : (
|
||||
<>
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{t("share-with")}
|
||||
</h3>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<form
|
||||
className="h-full w-full z-[1300] px-2 mt-3"
|
||||
onSubmit={(e) =>
|
||||
handleShareWith(e, item)
|
||||
}
|
||||
unstyled
|
||||
classNames={{
|
||||
control: () =>
|
||||
"op-input op-input-bordered op-input-sm border-gray-400 focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
||||
valueContainer: () =>
|
||||
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
||||
multiValue: () =>
|
||||
"op-badge op-badge-primary h-full text-[11px]",
|
||||
multiValueLabel: () => "mb-[2px]",
|
||||
menu: () =>
|
||||
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||
menuList: () =>
|
||||
"shadow-md rounded-lg overflow-hidden",
|
||||
option: () =>
|
||||
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||
noOptionsMessage: () =>
|
||||
"p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||
}}
|
||||
/>
|
||||
<button className="op-btn op-btn-primary ml-[10px] my-3">
|
||||
{t("submit")}
|
||||
</button>
|
||||
</form>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<SubscribeCard
|
||||
plan={"TEAMS"}
|
||||
price={"20"}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{isSubscribe && !isEnableSubscription && (
|
||||
<>
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{t("share-with")}
|
||||
</h3>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<div className="px-2 mt-3 w-full h-full">
|
||||
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
||||
{selectedTeam?.[0]?.label}
|
||||
>
|
||||
<Select
|
||||
// onSortEnd={onSortEnd}
|
||||
distance={4}
|
||||
isMulti
|
||||
options={teamList}
|
||||
value={selectedTeam}
|
||||
onChange={onChange}
|
||||
closeMenuOnSelect
|
||||
required={true}
|
||||
noOptionsMessage={() =>
|
||||
t("team-not-found")
|
||||
}
|
||||
unstyled
|
||||
classNames={{
|
||||
control: () =>
|
||||
"op-input op-input-bordered op-input-sm border-gray-400 focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
||||
valueContainer: () =>
|
||||
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
||||
multiValue: () =>
|
||||
"op-badge op-badge-primary h-full text-[11px]",
|
||||
multiValueLabel: () =>
|
||||
"mb-[2px]",
|
||||
menu: () =>
|
||||
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||
menuList: () =>
|
||||
"shadow-md rounded-lg overflow-hidden",
|
||||
option: () =>
|
||||
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||
noOptionsMessage: () =>
|
||||
"p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||
}}
|
||||
/>
|
||||
<button className="op-btn op-btn-primary ml-[10px] my-3">
|
||||
{t("submit")}
|
||||
</button>
|
||||
</form>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!validplan[isSubscribe.plan] &&
|
||||
isEnableSubscription && (
|
||||
<>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => handleShareWith(e, item)}
|
||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||
>
|
||||
{t("submit")}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<SubscribeCard
|
||||
plan={"TEAMS"}
|
||||
price={"20"}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{validplan[isSubscribe.plan] &&
|
||||
!isEnableSubscription && (
|
||||
<>
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{t("share-with")}
|
||||
</h3>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<div className="px-2 mt-3 w-full h-full">
|
||||
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
||||
{selectedTeam?.[0]?.label}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) =>
|
||||
handleShareWith(e, item)
|
||||
}
|
||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||
>
|
||||
{t("submit")}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { openInNewTab } from "../constant/Utils";
|
||||
|
||||
const SubscribeCard = ({ plan, price }) => {
|
||||
const SubscribeCard = ({ plan, price, plan_code }) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const handlePaidRoute = () => {
|
||||
const route = paidUrl(plan_code);
|
||||
if (route === "/subscription") {
|
||||
navigate(route);
|
||||
} else {
|
||||
openInNewTab(route, "_self");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||
<div className="op-card-body">
|
||||
@@ -16,7 +26,7 @@ const SubscribeCard = ({ plan, price }) => {
|
||||
</p>
|
||||
<div className="op-card-actions justify-end">
|
||||
<button
|
||||
onClick={() => navigate("/subscription")}
|
||||
onClick={() => handlePaidRoute()}
|
||||
className="op-btn op-btn-accent"
|
||||
>
|
||||
{t("upgrade-now")}
|
||||
|
||||
@@ -4,7 +4,8 @@ export default async function saveSubscription(request, response) {
|
||||
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 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);
|
||||
@@ -28,6 +29,7 @@ export default async function saveSubscription(request, response) {
|
||||
updateSubscription.unset('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 {
|
||||
@@ -55,6 +57,7 @@ export default async function saveSubscription(request, response) {
|
||||
createSubscription.unset('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!' });
|
||||
}
|
||||
|
||||
@@ -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 { status: 'success', addon: allowedUsers };
|
||||
} 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);
|
||||
|
||||
@@ -31,14 +31,17 @@ export default async function saveSubscription(request) {
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
const subscription = await subcriptionCls.first({ useMasterKey: true });
|
||||
if (subscription) {
|
||||
const resSubscription = await subcriptionCls.first({ useMasterKey: true });
|
||||
const addons = subscription?.data?.subscription?.addons || [];
|
||||
const existAddon = addons.reduce((acc, curr) => acc + curr.quantity, 1);
|
||||
if (resSubscription) {
|
||||
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
updateSubscription.id = subscription.id;
|
||||
updateSubscription.id = resSubscription.id;
|
||||
updateSubscription.set('SubscriptionId', SubscriptionId);
|
||||
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!' };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user