Merge pull request #1063 from OpenSignLabs/validation

This commit is contained in:
Amol
2024-08-14 20:24:25 +05:30
committed by GitHub
7 changed files with 320 additions and 243 deletions
+217 -223
View File
@@ -4,7 +4,6 @@ import Title from "./Title";
import Loader from "../primitives/Loader";
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 =
@@ -48,6 +47,7 @@ const AddUser = (props) => {
useEffect(() => {
getTeamList();
// eslint-disable-next-line
}, []);
const getTeamList = async () => {
@@ -73,6 +73,13 @@ const AddUser = (props) => {
const res = await Parse.Cloud.run("allowedusers", {
tenantId: extUser?.TenantId?.objectId
});
if (props.setFormHeader) {
if (res > 0) {
props.setFormHeader(t("add-user"));
} else {
props.setFormHeader(t("Add-seats"));
}
}
setAllowedUser(res);
} else {
setAllowedUser(0);
@@ -121,9 +128,7 @@ const AddUser = (props) => {
if (res) {
props.setIsAlert({ type: "danger", msg: t("user-already-exist") });
setIsFormLoader(false);
setTimeout(() => {
props.setIsAlert({ type: "success", msg: "" });
}, 1000);
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1000);
} else {
try {
const extUser = new Parse.Object("contracts_Users");
@@ -276,10 +281,7 @@ const AddUser = (props) => {
if (name === "email") {
value = value?.toLowerCase()?.replace(/\s/g, "");
}
setFormdata((prev) => ({
...prev,
[name]: value
}));
setFormdata((prev) => ({ ...prev, [name]: value }));
};
const copytoclipboard = (text) => {
@@ -313,172 +315,134 @@ const AddUser = (props) => {
if (resAddon) {
const _resAddon = JSON.parse(JSON.stringify(resAddon));
if (_resAddon.status === "success") {
setAllowedUser(_resAddon.addon);
setAllowedUser(amount.quantity);
setPlanInfo((obj) => ({ ...obj, totalAllowedUser: _resAddon.addon }));
}
}
} catch (err) {
console.log("Err in buy addon", err);
props.setIsAlert({
type: "danger",
msg: t("something-went-wrong-mssg")
});
props.setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
} finally {
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 2000);
setIsFormLoader(false);
}
};
return (
<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>
)}
{!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 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>
)}
{!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="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 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("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")}
{t("team")}
<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.role}
name="team"
value={formdata.team}
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"))
@@ -489,81 +453,111 @@ const AddUser = (props) => {
<option defaultValue={""} value={""}>
{t("Select")}
</option>
{role.length > 0 &&
role.map((x) => (
<option key={x} value={x}>
{x}
{teamList.length > 0 &&
teamList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</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")}
)}
<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>
</form>
)}
</div>
)}
</>
) : (
<div className="w-full h-[200px] inset-0 flex justify-center items-center z-50">
<Loader />
</div>
)}
</div>
</ModalUi>
<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>
);
};
+5 -3
View File
@@ -211,9 +211,11 @@ export const paidUrl = (plan) => {
: "";
const phone =
user && user.phone ? "&mobile=" + encodeURIComponent(user.phone) : "";
const allowedUsers = localStorage.getItem("allowedUsers")
? localStorage.getItem("allowedUsers") - 1
: "";
const allowedUsers =
localStorage.getItem("allowedUsers") &&
localStorage.getItem("allowedUsers") > 0
? localStorage.getItem("allowedUsers") - 1
: "";
const quantity = allowedUsers
? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&`
: "";
+5 -3
View File
@@ -67,9 +67,11 @@ 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 allowedUsers =
localStorage.getItem("allowedUsers") &&
localStorage.getItem("allowedUsers") > 0
? localStorage.getItem("allowedUsers") - 1
: "";
const teamperiod = {
"team-weekly": "monthly",
"team-yearly": "yearly",
+12 -5
View File
@@ -29,6 +29,7 @@ const UserList = () => {
const [isActLoader, setIsActLoader] = useState({});
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false });
const [isAdmin, setIsAdmin] = useState(false);
const [formHeader, setFormHeader] = useState(t("add-user"));
const recordperPage = 10;
const startIndex = (currentPage - 1) * recordperPage; // user per page
@@ -393,12 +394,18 @@ const UserList = () => {
</div>
</div>
)}
<AddUser
<ModalUi
isOpen={isModal}
setIsAlert={setIsAlert}
handleUserData={handleUserData}
closePopup={handleFormModal}
/>
title={formHeader}
handleClose={handleFormModal}
>
<AddUser
setIsAlert={setIsAlert}
handleUserData={handleUserData}
closePopup={handleFormModal}
setFormHeader={setFormHeader}
/>
</ModalUi>
</div>
) : (
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
@@ -5,7 +5,27 @@ export default async function saveSubscription(request, response) {
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);
let existAddon = 0;
if (addons?.length > 0) {
let allowedUsersMonthly = 0;
let allowedUsersYearly = 0;
addons?.forEach(item => {
if (item.addon_code === 'extra-teams-users-monthly') {
allowedUsersMonthly += item.quantity;
} else if (item.addon_code === 'extra-teams-users-yearly') {
allowedUsersYearly += item.quantity;
} else if (item.addon_code === 'extra-users') {
allowedUsersMonthly += item.quantity;
}
});
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
existAddon = allowedUsersMonthly + allowedUsersYearly + 1;
}
} else {
if (planCode === 'teams-yearly' || planCode === 'teams-monthly' || planCode === 'team-weekly') {
existAddon = 1;
}
}
try {
const extUserCls = new Parse.Query('contracts_Users');
extUserCls.equalTo('Email', Email);
@@ -29,7 +49,9 @@ export default async function saveSubscription(request, response) {
updateSubscription.unset('Next_billing_date');
}
updateSubscription.set('PlanCode', planCode);
updateSubscription.set('AllowedUsers', parseInt(existAddon));
if (existAddon > 0) {
updateSubscription.set('AllowedUsers', parseInt(existAddon));
}
await updateSubscription.save(null, { useMasterKey: true });
return response.status(200).json({ status: 'update subscription!' });
} else {
@@ -57,7 +79,9 @@ export default async function saveSubscription(request, response) {
createSubscription.unset('Next_billing_date');
}
createSubscription.set('PlanCode', planCode);
createSubscription.set('AllowedUsers', parseInt(existAddon));
if (existAddon > 0) {
createSubscription.set('AllowedUsers', parseInt(existAddon));
}
await createSubscription.save(null, { useMasterKey: true });
return response.status(200).json({ status: 'create subscription!' });
}
@@ -36,13 +36,32 @@ export default async function Buyaddon(request) {
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);
let addon = 0;
if (addonsArr?.length > 0) {
let allowedUsersMonthly = 0;
let allowedUsersYearly = 0;
addonsArr?.forEach(item => {
if (item.addon_code === 'extra-teams-users-monthly') {
allowedUsersMonthly += item.quantity;
} else if (item.addon_code === 'extra-teams-users-yearly') {
allowedUsersYearly += item.quantity;
} else if (item.addon_code === 'extra-users') {
allowedUsersMonthly += item.quantity;
}
});
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
addon = allowedUsersMonthly + allowedUsersYearly;
}
}
const quantity = parseInt(users) + parseInt(addon);
const addoncode = plan_code.includes('yearly')
? 'extra-teams-users-yearly'
: 'extra-teams-users-monthly';
const data = JSON.stringify({
plan: { plan_code: plan_code },
addons: [
{
addon_code: 'extra-users',
addon_code: addoncode,
addon_description: 'Extra users',
price: price,
quantity: quantity,
@@ -8,7 +8,7 @@ export default async function saveSubscription(request) {
const body = subscription;
const Next_billing_date = subscription.data.subscription.next_billing_at;
const planCode = subscription.data.subscription.plan.plan_code;
let existAddon = 0;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
@@ -33,7 +33,32 @@ export default async function saveSubscription(request) {
});
const resSubscription = await subcriptionCls.first({ useMasterKey: true });
const addons = subscription?.data?.subscription?.addons || [];
const existAddon = addons.reduce((acc, curr) => acc + curr.quantity, 1);
if (addons?.length > 0) {
let allowedUsersMonthly = 0;
let allowedUsersYearly = 0;
addons?.forEach(item => {
if (item.addon_code === 'extra-teams-users-monthly') {
allowedUsersMonthly += item.quantity;
} else if (item.addon_code === 'extra-teams-users-yearly') {
allowedUsersYearly += item.quantity;
} else if (item.addon_code === 'extra-users') {
allowedUsersMonthly += item.quantity;
}
});
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
existAddon = allowedUsersMonthly + allowedUsersYearly + 1;
}
} else {
if (
planCode === 'teams-yearly' ||
planCode === 'teams-monthly' ||
planCode === 'team-weekly'
) {
existAddon = 1;
}
}
// const existAddon = addons.reduce((acc, curr) => acc + curr.quantity, 1);
if (resSubscription) {
const updateSubscription = new Parse.Object('contracts_Subscriptions');
updateSubscription.id = resSubscription.id;
@@ -41,7 +66,9 @@ 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));
if (existAddon > 0) {
updateSubscription.set('AllowedUsers', parseInt(existAddon));
}
await updateSubscription.save(null, { useMasterKey: true });
return { status: 'update subscription!' };
} else {
@@ -65,7 +92,9 @@ 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));
if (existAddon > 0) {
createSubscription.set('AllowedUsers', parseInt(existAddon));
}
await createSubscription.save(null, { useMasterKey: true });
return { status: 'create subscription!' };
}