diff --git a/src/App.jsx b/src/App.jsx index 0a0c562..bec22f1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -22,10 +22,12 @@ import CustomerMenuPage from './Pages/Reports/MenuQRCode/CustomerMenuPage.jsx'; import WeightScaleApp from './Pages/BookingScreen/WeightscaleApp.jsx'; import useSubscriptionManager from './useSubscriptionManager.js'; import useSessionManager from './useSessionManager.js'; +import ExtendSubscriptionModal from './Pages/ExtentedModal/ExtendSubscriptionModal.jsx'; + const AppRoutes = () => { const ItemCard = useSelector(GlobalItemCard); - // const { sessionData, logout } = useSessionManager(ItemCard); - // useSubscriptionManager(sessionData, logout); + const { sessionData, logout } = useSessionManager(ItemCard); + const { remainingDays, handleCancel, handlePay, freeExtend, extendModel } = useSubscriptionManager(sessionData, logout); useEffect(() => { const handlePopState = () => { @@ -62,6 +64,16 @@ const AppRoutes = () => { return () => clearInterval(timer); }, []); + + if (extendModel) { + return ( + + ); + } return ( Loading…}> diff --git a/src/Pages/ExtentedModal/ExtendSubscriptionModal.jsx b/src/Pages/ExtentedModal/ExtendSubscriptionModal.jsx new file mode 100644 index 0000000..2dd1d48 --- /dev/null +++ b/src/Pages/ExtentedModal/ExtendSubscriptionModal.jsx @@ -0,0 +1,48 @@ +import { Tooltip } from "antd"; +import "./extendSubscribtionModel.scss"; +import { IoClose } from "react-icons/io5"; + +const ExtendSubscriptionModal = ({ + onClose, + onPayNow, + onContinueWithCredits +}) => { + return ( + + + + Subscription Expired + + + + + + + Your plan has expired. Please extend to continue using the app. + + + + + Continue with Credits + + + + Pay Now + + + + + ); +}; + +export default ExtendSubscriptionModal; \ No newline at end of file diff --git a/src/Pages/ExtentedModal/extendSubscribtionModel.scss b/src/Pages/ExtentedModal/extendSubscribtionModel.scss new file mode 100644 index 0000000..c2df053 --- /dev/null +++ b/src/Pages/ExtentedModal/extendSubscribtionModel.scss @@ -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; + } +} \ No newline at end of file diff --git a/src/useSubscriptionManager.js b/src/useSubscriptionManager.js index b2ffd99..baea704 100644 --- a/src/useSubscriptionManager.js +++ b/src/useSubscriptionManager.js @@ -5,12 +5,112 @@ import { changeHeightforExpDate, getAppSubscriptionDate, } 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 dispatch = useDispatch(); + const navigate = useNavigate(); const prevRemainingDays = useRef(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(() => { if (!sessionData) return; @@ -49,7 +149,7 @@ const useSubscriptionManager = (sessionData, logout) => { return () => clearInterval(interval); }, [sessionData]); - return remainingDays; + return { remainingDays, handleCancel, handlePay, freeExtend, extendModel }; }; export default useSubscriptionManager;
+ Your plan has expired. Please extend to continue using the app. +