Merge pull request 'extendedModal' (#127) from enhancement/entryandquickadd into main
Reviewed-on: Pozomind/pozo-retail-app#127
This commit is contained in:
commit
3ddd3ca045
16
src/App.jsx
16
src/App.jsx
|
|
@ -22,10 +22,12 @@ import CustomerMenuPage from './Pages/Reports/MenuQRCode/CustomerMenuPage.jsx';
|
||||||
import WeightScaleApp from './Pages/BookingScreen/WeightscaleApp.jsx';
|
import WeightScaleApp from './Pages/BookingScreen/WeightscaleApp.jsx';
|
||||||
import useSubscriptionManager from './useSubscriptionManager.js';
|
import useSubscriptionManager from './useSubscriptionManager.js';
|
||||||
import useSessionManager from './useSessionManager.js';
|
import useSessionManager from './useSessionManager.js';
|
||||||
|
import ExtendSubscriptionModal from './Pages/ExtentedModal/ExtendSubscriptionModal.jsx';
|
||||||
|
|
||||||
const AppRoutes = () => {
|
const AppRoutes = () => {
|
||||||
const ItemCard = useSelector(GlobalItemCard);
|
const ItemCard = useSelector(GlobalItemCard);
|
||||||
// const { sessionData, logout } = useSessionManager(ItemCard);
|
const { sessionData, logout } = useSessionManager(ItemCard);
|
||||||
// useSubscriptionManager(sessionData, logout);
|
const { remainingDays, handleCancel, handlePay, freeExtend, extendModel } = useSubscriptionManager(sessionData, logout);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handlePopState = () => {
|
const handlePopState = () => {
|
||||||
|
|
@ -62,6 +64,16 @@ const AppRoutes = () => {
|
||||||
return () => clearInterval(timer);
|
return () => clearInterval(timer);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
if (extendModel) {
|
||||||
|
return (
|
||||||
|
<ExtendSubscriptionModal
|
||||||
|
onClose={handleCancel}
|
||||||
|
onPayNow={handlePay}
|
||||||
|
onContinueWithCredits={freeExtend}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div>Loading…</div>}>
|
<Suspense fallback={<div>Loading…</div>}>
|
||||||
<Routes>
|
<Routes>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { Tooltip } from "antd";
|
||||||
|
import "./extendSubscribtionModel.scss";
|
||||||
|
import { IoClose } from "react-icons/io5";
|
||||||
|
|
||||||
|
const ExtendSubscriptionModal = ({
|
||||||
|
onClose,
|
||||||
|
onPayNow,
|
||||||
|
onContinueWithCredits
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="extendmodal-backdrop">
|
||||||
|
<div className="extendmodal">
|
||||||
|
<div className="extendModalheader">
|
||||||
|
<h2>Subscription Expired</h2>
|
||||||
|
<Tooltip placement="left" title="Close">
|
||||||
|
<IoClose
|
||||||
|
onClick={onClose}
|
||||||
|
className="extendModalClose"
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your plan has expired. Please extend to continue using the app.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="extendmodal-actions">
|
||||||
|
<button
|
||||||
|
className="CreditsBTN"
|
||||||
|
onClick={onContinueWithCredits}
|
||||||
|
>
|
||||||
|
Continue with Credits
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="PayNowBTN"
|
||||||
|
onClick={onPayNow}
|
||||||
|
>
|
||||||
|
Pay Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExtendSubscriptionModal;
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
.extendmodal-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extendmodal {
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 450px;
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #555;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
width: 90% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.extendModalheader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extendModalClose {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 3px;
|
||||||
|
background-color: #ffecec;
|
||||||
|
color: #ef4444;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #ffd5d5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.extendmodal-actions {
|
||||||
|
margin: 2rem 0 1rem 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common button style */
|
||||||
|
.PayNowBTN,
|
||||||
|
.CreditsBTN {
|
||||||
|
padding: 8px 14px;
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pay Now */
|
||||||
|
.PayNowBTN {
|
||||||
|
background-color: #10b981;
|
||||||
|
color: #fff;
|
||||||
|
padding: 8px 22px;
|
||||||
|
animation: payNowPulse 1.8s ease-in-out infinite;
|
||||||
|
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
||||||
|
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #10b981;
|
||||||
|
animation-play-state: paused;
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Continue with Credits */
|
||||||
|
.CreditsBTN {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
color: #111;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Attention animation */
|
||||||
|
@keyframes payNowPulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
box-shadow: 0 0 0 0 #05c283;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.07);
|
||||||
|
box-shadow: 0 0 0 8px #1292ee00;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
box-shadow: 0 0 0 0 #1292ee00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,12 +5,112 @@ import {
|
||||||
changeHeightforExpDate,
|
changeHeightforExpDate,
|
||||||
getAppSubscriptionDate,
|
getAppSubscriptionDate,
|
||||||
} from './Features/BookingScreen/BookingData/BookingData.js';
|
} from './Features/BookingScreen/BookingData/BookingData.js';
|
||||||
|
import { sendSms } from './Features/Payment/PaymentDetails/PaymentDetails.js';
|
||||||
|
import { getPurchasedAppDetails, postInvoice } from './Features/BookingScreen/Pricing/Pricing.js';
|
||||||
|
import { getSession } from './Services/Others.js';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
const useSubscriptionManager = (sessionData, logout) => {
|
const useSubscriptionManager = (sessionData, logout) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const navigate = useNavigate();
|
||||||
const prevRemainingDays = useRef(null);
|
const prevRemainingDays = useRef(null);
|
||||||
const [remainingDays, setRemainingDays] = useState(null);
|
const [remainingDays, setRemainingDays] = useState(null);
|
||||||
|
const [extendModel, setExtendModel] = useState(false);
|
||||||
|
const handleCancel = () => {
|
||||||
|
logout();
|
||||||
|
setExtendModel(false)
|
||||||
|
|
||||||
|
}
|
||||||
|
const handlePay = () => {
|
||||||
|
setExtendModel(false)
|
||||||
|
let AppName = getSession("AppName")
|
||||||
|
navigate(`${subDirectory}PricingPage`, { state: { AppName: AppName } });
|
||||||
|
}
|
||||||
|
function formatDate(date) {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
const hours = String(date.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||||
|
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
||||||
|
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDays(dateString, days) {
|
||||||
|
// Make it ISO-safe for iOS / WebView
|
||||||
|
const isoDate = dateString.replace(' ', 'T');
|
||||||
|
const currentDate = new Date(isoDate);
|
||||||
|
|
||||||
|
currentDate.setDate(currentDate.getDate() + Number(days));
|
||||||
|
|
||||||
|
return formatDate(currentDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- MAIN FUNCTION ----------------
|
||||||
|
const freeExtend = async () => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const UserId = getSession('UserId');
|
||||||
|
const AppId = getSession('UserId')
|
||||||
|
// Current date
|
||||||
|
const now = new Date();
|
||||||
|
const currentDate = formatDate(now);
|
||||||
|
|
||||||
|
// 1️⃣ Get purchased app details
|
||||||
|
const response1 = await dispatch(
|
||||||
|
getPurchasedAppDetails({ AppId, UserId })
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
const PurchasedDetails = response1?.data?.data;
|
||||||
|
|
||||||
|
if (!PurchasedDetails || !PurchasedDetails.length) {
|
||||||
|
console.error('No purchased details found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2️⃣ Prepare post data
|
||||||
|
const postData = {
|
||||||
|
UserId: UserId,
|
||||||
|
AppId: AppId,
|
||||||
|
PricingId: PurchasedDetails[0]?.PricingId,
|
||||||
|
PurDate: currentDate,
|
||||||
|
NoofDays: 30,
|
||||||
|
PaymentMode: 27,
|
||||||
|
PaymentStatus: 'S',
|
||||||
|
LicenseStatus: PurchasedDetails[0]?.LicenseStatus,
|
||||||
|
Price: PurchasedDetails[0]?.Price ?? 0,
|
||||||
|
TaxId: PurchasedDetails[0]?.TaxId ?? 0,
|
||||||
|
NetPrice: PurchasedDetails[0]?.ExistingPlanNetPrice ?? 0,
|
||||||
|
ValidityStart: currentDate,
|
||||||
|
ValidityEnd: addDays(
|
||||||
|
currentDate,
|
||||||
|
PurchasedDetails[0]?.NoOfDays
|
||||||
|
),
|
||||||
|
CreatedBy: UserId,
|
||||||
|
TaxAmount: PurchasedDetails[0]?.TaxAmount ?? 0,
|
||||||
|
MobileNo: getSession('MobileNo'),
|
||||||
|
MailId: 'ts@gmmail.com',
|
||||||
|
Type: "FreeExtend"
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3️⃣ Post invoice
|
||||||
|
const response = await dispatch(postInvoice(postData)).unwrap();
|
||||||
|
|
||||||
|
// 4️⃣ Send SMS if required
|
||||||
|
if (response?.data?.statusCode === 1 && response?.data?.SMSbody) {
|
||||||
|
await dispatch(
|
||||||
|
sendSms({ body: response.data.SMSbody })
|
||||||
|
);
|
||||||
|
setExtendModel(false)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('freeExtend error:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!sessionData) return;
|
if (!sessionData) return;
|
||||||
|
|
||||||
|
|
@ -49,7 +149,7 @@ const useSubscriptionManager = (sessionData, logout) => {
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [sessionData]);
|
}, [sessionData]);
|
||||||
|
|
||||||
return remainingDays;
|
return { remainingDays, handleCancel, handlePay, freeExtend, extendModel };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useSubscriptionManager;
|
export default useSubscriptionManager;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue