diff --git a/src/App.tsx b/src/App.tsx index c83cbdf..d4ec254 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,6 +31,7 @@ function App() { const randomIndex = Math.floor(Math.random() * (allNodes.length - 1)) setRandomSolanaRPC(allNodes[randomIndex]) } + useEffect(() => { const handlePassport = async () => { if (!CoNET_Data?.profiles[0]?.keyID) return @@ -123,7 +124,9 @@ function App() { setServerPort('3002'); setIsLocalProxy(true) } catch (ex) { - setIsIOS(true) + if (window?.webkit) { + setIsIOS(true) + } setIsLocalProxy(false) } }; diff --git a/src/components/AccountList/index.tsx b/src/components/AccountList/index.tsx index adecfd4..7726dac 100644 --- a/src/components/AccountList/index.tsx +++ b/src/components/AccountList/index.tsx @@ -117,8 +117,8 @@ export default function AccountList({ showMainWallet = true, simplifiedView = fa simplifiedView && (
{ - profiles?.[0].keyID ? ( -

{profiles?.[0]?.keyID?.slice(0, 5)}...{profiles?.[0]?.keyID?.slice(-5)}

+ profiles[0]?.keyID?.slice ? ( +

{profiles[0].keyID?.slice(0, 5)}...{profiles?.[0]?.keyID?.slice(-5)}

) : ( ) @@ -223,8 +223,8 @@ export default function AccountList({ showMainWallet = true, simplifiedView = fa simplifiedView && (
{ - profiles?.[1].keyID ? ( -

{profiles?.[1]?.keyID?.slice(0, 5)}...{profiles?.[1]?.keyID?.slice(-5)}

+ profiles[1]?.keyID?.slice ? ( +

{profiles[1].keyID.slice(0, 5)}...{profiles[1].keyID.slice(-5)}

) : ( ) diff --git a/src/components/AffiliateOptions/assets/paypal.svg b/src/components/AffiliateOptions/assets/paypal.svg new file mode 100644 index 0000000..b25c063 --- /dev/null +++ b/src/components/AffiliateOptions/assets/paypal.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/AffiliateOptions/assets/stripe.png b/src/components/AffiliateOptions/assets/stripe.png new file mode 100644 index 0000000..bfc1039 Binary files /dev/null and b/src/components/AffiliateOptions/assets/stripe.png differ diff --git a/src/components/AffiliateOptions/index.css b/src/components/AffiliateOptions/index.css new file mode 100644 index 0000000..cd24f0a --- /dev/null +++ b/src/components/AffiliateOptions/index.css @@ -0,0 +1,64 @@ +.affiliate-options { + display: flex; + flex-direction: column; + justify-content: space-between; + + flex: 1; +} + +.affiliate-options button { + width: 100%; + height: 60px; + border-radius: 16px; + + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + + font-weight: 700; + font-size: 18px; + + cursor: pointer; +} + +.affiliate-options button:disabled { + color: #5B5B5B!important; + background: #262626!important; + cursor: not-allowed!important; +} + + +.affiliate-options .sp-buy-button { + color: #FFFFFF; + background: #4E72B6; +} + +.affiliate-options .paypal-buy-button { + color: #FFFFFF; + background: #253B80; +} + +.affiliate-options .stripe-buy-button { + color: #FFFFFF; + background: #635BFF; +} + +.affiliate-options .stripe-buy-button img { + width: initial; + height: 30px; +} + +.affiliate-footer { + display: flex; + flex-direction: column; + gap: 16px; +} + +.affiliate-footer > p { + font-size: 12px; + color: #989899; +} +p{ + width: initial; +} \ No newline at end of file diff --git a/src/components/AffiliateOptions/index.tsx b/src/components/AffiliateOptions/index.tsx new file mode 100644 index 0000000..8a7bf5a --- /dev/null +++ b/src/components/AffiliateOptions/index.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react'; +import './index.css' +import { useDaemonContext } from '../../providers/DaemonProvider'; +import { useNavigate } from 'react-router-dom'; +import ChoosePlan from '../ChoosePlan'; + +import { ReactComponent as PaypalIcon } from './assets/paypal.svg'; +import StripeIcon from './assets/stripe.png'; + + + +export default function AffiliateOptions() { + const navigate = useNavigate(); + const { purchasingPlan, profiles, setPaymentKind } = useDaemonContext(); + + function subscribe(val: number) { + setPaymentKind(val) + } + + function subscribePaypal() {} + + return ( +
+ + +
+ + + +
+
+ ) +} \ No newline at end of file diff --git a/src/components/ChoosePlan/index.css b/src/components/ChoosePlan/index.css new file mode 100644 index 0000000..512f83f --- /dev/null +++ b/src/components/ChoosePlan/index.css @@ -0,0 +1,79 @@ +.choose-plan-container { + width: 100%; + + display: flex; + flex-direction: column; + gap: 20px; + } + + .choose-plan-container h2 { + text-align: left; + } + + .choose-plan-options { + display: flex; + flex-direction: column; + gap: 8px; + } + + .plan-option { + display: flex; + justify-content: space-between; + + background: #191919; + padding: 16px; + border-radius: 16px; + } + + .plan-option { + text-align: left; + } + + .plan-option div p { + color: #FFFFFF; + font-size: 24px; + } + + .plan-option div span { + color: #989899; + font-size: 14px; + } + + .plan-option div:nth-child(1) { + width: 90px; + } + + .plan-option div:nth-child(3) { + width: 65px; + } + + .plan-option div:nth-child(2) { + display: flex; + align-items: center; + gap: 16px; + } + + .plan-option div:nth-child(2) button { + border-radius: 4px; + + color: #FFFFFF; + background: #9FBFE5FE; + + width: 32px; + height: 32px; + + display: flex; + justify-content: center; + align-items: center; + + font-size: 18px; + font-weight: 700; + + cursor: pointer; + } + + .plan-option div:nth-child(2) button:disabled { + color: #5B5B5B; + background: #262626; + cursor: not-allowed!important; + } \ No newline at end of file diff --git a/src/components/ChoosePlan/index.tsx b/src/components/ChoosePlan/index.tsx new file mode 100644 index 0000000..b759860 --- /dev/null +++ b/src/components/ChoosePlan/index.tsx @@ -0,0 +1,67 @@ +import { useEffect, useState } from 'react'; +import { useDaemonContext } from '../../providers/DaemonProvider'; + +export default function ChoosePlan() { + const { purchasingPlan, setPurchasingPlan, purchasingPlanPaymentTime, setPurchasingPlanPaymentTime } = useDaemonContext(); + + const [standard, setStandard] = useState(0); + const [premium, setPremium] = useState(0); + + const [standardPrice, setStandardPrice] = useState('2.49'); + const [premiumPrice, setPremiumPrice] = useState('9.99'); + + useEffect(() => { + if (purchasingPlanPaymentTime === 'monthly') { + setStandardPrice('2.99'); + setPremiumPrice('24.99'); + } else { + setStandardPrice('24.99'); + setPremiumPrice('99.99'); + } + + }, [purchasingPlanPaymentTime]); + + return ( +
+

Choose plan

+ {/*
+ + +
*/} +
+
setPurchasingPlan('standard')}> +
+

Monthly

+ 1 device +
+
+ {/* +
{standard}
+ */} +
+
+ $USD +

{standardPrice}

+ {/* paid {purchasingPlanPaymentTime} */} +
+
+
setPurchasingPlan('premium')}> +
+

Annual

+ 1 devices +
+
+ {/* +
{premium}
+ */} +
+
+ $USD +

{premiumPrice}

+ {/* Annual */} +
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/RedeemPassport/index.tsx b/src/components/RedeemPassport/index.tsx index deb821c..0362963 100644 --- a/src/components/RedeemPassport/index.tsx +++ b/src/components/RedeemPassport/index.tsx @@ -1,10 +1,12 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import "./index.css"; // Import external CSS file import SuccessModal from './SuccessModal'; import { RealizationRedeem } from '../../services/wallets'; import SimpleLoadingRing from '../SimpleLoadingRing'; import { useDaemonContext } from "../../providers/DaemonProvider"; +import {stripe_pay_Annual, stripe_pay_monthly} from '../../utils/constants' +import AffiliateOptions from '../../components/AffiliateOptions'; interface plan { total: string publicKey: string @@ -18,10 +20,29 @@ export default function RedeemPassport() { const [anErrorOccurred, setAnErrorOccurred] = useState(false); const [isRedeemProcessLoading, setIsRedeemProcessLoading] = useState(false); const [selectedPlan, setSelectedPlan] = useState<'12' | '1'>('12'); - const [successNFTID, setSuccessNFTID] = useState(0); - const { isIOS, profiles } = useDaemonContext(); + + const { isIOS, profiles, paymentKind, purchasingPlan, successNFTID, setSuccessNFTID } = useDaemonContext(); const navigate = useNavigate(); + useEffect(() => { + const processVisa = async () => { + if (paymentKind !== 0) { + navigate('/Subscription') + } + } + processVisa() + + }, [paymentKind]); + + useEffect(() => { + if (successNFTID > 100) { + setAnErrorOccurred(true); + setIsSuccessModalOpen(true); + setRedeemCode('') + } + + }, [successNFTID]) + async function handlePassportRedeem() { setIsRedeemProcessLoading(true); @@ -70,97 +91,107 @@ export default function RedeemPassport() {
{ - isIOS ? - : + !isRedeemProcessLoading && + <> + { + isIOS ? + : + } + + setRedeemCode(e.target.value)} + /> + } - - setRedeemCode(e.target.value)} - /> + {anErrorOccurred && An error occurred, try again later.} { - isIOS && + !isRedeemProcessLoading && <> -
-
- or -
-
-
-
setSelectedPlan('12')} - > -
-
-
-
12 months plan
-
$2.71/month, billed annually
-
(Save 18%)
+ { + isIOS && + <> +
+
+ or +
-
-
7-Day Free Trial
-
+
+
setSelectedPlan('12')} + > +
+
+
+
12 months plan
+
$2.71/month, billed annually
+
(Save 18%)
+
+
+
7-Day Free Trial
+
-
setSelectedPlan('1')} - > -
-
-
-
1 month plan
-
$3.29/month
+
setSelectedPlan('1')} + > +
+
+
+
1 month plan
+
$3.29/month
+
+
+
No Free Trial
+
-
-
No Free Trial
-
-
-
-
-
-
-

7 day free,
then get 12 months for $32.49

- -
-

Subscription details:

-
    -
  • Your Apple ID account will be charged on the last day of your free trial.
  • -
  • Your subscription will automatically renew at the end of each billing period unless it is canceled at least 24 hours before the expiry date.
  • -
  • You can manage and cancel your subscriptions by going to your App Store account settings after purchase.
  • -
  • Any unused portion of a free trial period, if offered, will be forfeited when you purchase a subscription.
  • -
  • By subscribing, you agree to the Terms of Service and Privacy Policy.
  • -
-
-
- - } - { - !isIOS && - <>
- or -
- - +
+

7 day free,
then get 12 months for $32.49

+ +
+

Subscription details:

+
    +
  • Your Apple ID account will be charged on the last day of your free trial.
  • +
  • Your subscription will automatically renew at the end of each billing period unless it is canceled at least 24 hours before the expiry date.
  • +
  • You can manage and cancel your subscriptions by going to your App Store account settings after purchase.
  • +
  • Any unused portion of a free trial period, if offered, will be forfeited when you purchase a subscription.
  • +
  • By subscribing, you agree to the Terms of Service and Privacy Policy.
  • +
+
+
+ + } + { + !isIOS && + <> +
+
+ or +
+
+ < AffiliateOptions/> + + } + } +
{/* Success Modal */} - {isSuccessModalOpen && setIsSuccessModalOpen(false)} />} + {isSuccessModalOpen && setIsSuccessModalOpen(false)} />} ); } diff --git a/src/components/SelectActivePassportPopup/index.css b/src/components/SelectActivePassportPopup/index.css index f6ed820..4bdf848 100644 --- a/src/components/SelectActivePassportPopup/index.css +++ b/src/components/SelectActivePassportPopup/index.css @@ -76,7 +76,7 @@ .home-buttons button:first-child:disabled { background-color: #333; color: #ddd; - cursor: not-allowed + cursor: not-allowed!important; } .home-buttons button:last-child { diff --git a/src/components/SpClubCongratsPopup/index.css b/src/components/SpClubCongratsPopup/index.css index f6ed820..4bdf848 100644 --- a/src/components/SpClubCongratsPopup/index.css +++ b/src/components/SpClubCongratsPopup/index.css @@ -76,7 +76,7 @@ .home-buttons button:first-child:disabled { background-color: #333; color: #ddd; - cursor: not-allowed + cursor: not-allowed!important; } .home-buttons button:last-child { diff --git a/src/pages/Subscription/index.css b/src/pages/Subscription/index.css index 79caf46..5b48494 100644 --- a/src/pages/Subscription/index.css +++ b/src/pages/Subscription/index.css @@ -59,6 +59,10 @@ font-weight: 700; } +.subscription-footer button.step-4 { + margin-top: 24px; +} + .subscription-footer button.step-3 svg { animation: rotate 1.4s linear infinite; } @@ -101,10 +105,6 @@ width: fit-content; } -.buy-more { - margin-bottom: 30px; -} - .buy-more h3 { text-align: left; font-size: 24px; @@ -119,7 +119,7 @@ .plan-options { width: fit-content; - margin: 24px auto; + margin: 14px auto; display: flex; background-color: #191919; @@ -129,13 +129,14 @@ gap: 2px; } -.plan-options button { +.affiliate-options .plan-options button { flex: 1; color: #ffffff; padding: 4px 16px; border-radius: 4px; width: 88px; + height: 40px; display: flex; justify-content: center; @@ -143,11 +144,11 @@ cursor: pointer; } -.plan-options button:not(.active):hover { +.affiliate-options .plan-options button:not(.active):hover { background-color: #282828; } -.plan-options button.active { +.affiliate-options .plan-options button.active { background-color: #3f3f40; } @@ -156,6 +157,7 @@ flex-direction: column; gap: 8px; margin-bottom: 16px; + padding-top: 1rem; } .plan-cards .plan { @@ -163,7 +165,7 @@ justify-content: space-between; background: #191919; - padding: 16px; + padding: 12px 16px; border-radius: 16px; text-align: left; @@ -357,3 +359,35 @@ color: #9fbfe5fe; font-weight: 700; } + +.plan > div:nth-child(2) { + display: flex; + flex-direction: row; + align-items: center; + gap: 16px; +} + +.plan > div:nth-child(2) button { + border-radius: 4px; + + color: #FFFFFF; + background: #9FBFE5FE; + + width: 32px; + height: 32px; + + display: flex; + justify-content: center; + align-items: center; + + font-size: 18px; + font-weight: 700; + + cursor: pointer; +} + +.plan > div:nth-child(2) button:disabled { + color: #5B5B5B; + background: #262626; + cursor: not-allowed!important; +} \ No newline at end of file diff --git a/src/pages/Subscription/index.tsx b/src/pages/Subscription/index.tsx index 95e38ea..b38c5c0 100644 --- a/src/pages/Subscription/index.tsx +++ b/src/pages/Subscription/index.tsx @@ -8,102 +8,69 @@ import SecondStep from './page-components/SecondStep'; import FourthStep from './page-components/FourthStep'; import './index.css'; -import { getOracle, purchasePassport } from '../../services/passportPurchase'; import { useDaemonContext } from '../../providers/DaemonProvider'; import Loading from '../../components/global-steps/Loading'; import Declined from '../../components/global-steps/Declined'; -import { Step } from '../../types/global-types'; +import {getPaymentUrl, waitingPaymentStatus} from '../../services/wallets' + +global.Buffer = require('buffer').Buffer; +export type Step = 2 | 3 | 4 | 5; export default function Subscription() { - const [step, setStep] = useState(1); + const { paymentKind, purchasingPlan, profiles, setSuccessNFTID, setPaymentKind } = useDaemonContext(); + const [step, setStep] = useState(2); const [price, setPriceInSp] = useState('0'); const [gasfee, setGasfee] = useState('0'); const [updateCounter, setUpdateCounter] = useState(0); const [spInUsd, setSpInUsd] = useState(0); const [solInUsd, setSolInUsd] = useState(0); - const [isLoading, setIsLoading] = useState(false); - const [oracleError, setOracleError] = useState(false); - const [sp249, setSp249] = useState('0'); - const [sp2499, setSp2499] = useState('0'); - const [sp999, setSp999] = useState('0'); - const [sp9999, setSp9999] = useState('0'); const [isSubmitButtonDisabled, setIsSubmitButtonDisabled] = useState(false); - const { profiles, purchasingPlan, purchasingPlanPaymentTime } = useDaemonContext(); - const navigate = useNavigate(); function nextStep() { if (step > 4) return; setStep((prev) => (prev + 1 as Step)); } - + let ffcus = false useEffect(() => { + if (ffcus) { + return + } + ffcus = true + const processVisa = async () => { + if (paymentKind !== 0) { + setStep(3) + const price = purchasingPlan === 'standard'? 299: 2499 + const result = await getPaymentUrl(price) + if (result === null || !result?.url) { + return setStep(5); + } + window.open(result.url, '_blank') + const re1 = await waitingPaymentStatus() + if (!re1) { + return setStep(5); + } + setSuccessNFTID(re1) + setPaymentKind(0) + return navigate('/wallet') + } + } + processVisa() const interval = setInterval(() => setUpdateCounter((prev) => prev - 1), 1000); return () => clearInterval(interval); }, []) - useEffect(() => { - const timeout = setTimeout(async () => { - if (isLoading) return - - setUpdateCounter(updateCounter - 1) - - if (updateCounter <= 0 || oracleError) { - setIsLoading(true) - const oracleData = await getOracle() - - if (oracleData && oracleData.data) { - setOracleError(false) - - setSp249(oracleData.data.sp249) - setSp2499(oracleData.data.sp2499) - setSp999(oracleData.data.sp999) - setSp9999(oracleData.data.sp9999) - - const _spInUsd = calcSpInUsd(oracleData.data.sp9999) - - setSolInUsd(parseFloat(oracleData.data.so)) - setSpInUsd(_spInUsd) - setUpdateCounter(60) - } else { - setOracleError(true) - } - - setIsLoading(false) - } - }, 1000); - - return () => clearTimeout(timeout); - }, [updateCounter]); - - useEffect(() => { - if (purchasingPlan === 'standard' && purchasingPlanPaymentTime === 'monthly') - setPriceInSp(sp249) - else if (purchasingPlan === 'standard' && purchasingPlanPaymentTime === 'yearly') - setPriceInSp(sp2499) - else if (purchasingPlan === 'premium' && purchasingPlanPaymentTime === 'monthly') - setPriceInSp(sp999) - else if (purchasingPlan === 'premium' && purchasingPlanPaymentTime === 'yearly') - setPriceInSp(sp9999) - }, [purchasingPlan, purchasingPlanPaymentTime, sp249, sp2499, sp999, sp9999]) - - const calcSpInUsd = (sp9999: string) => { - const sp9999Number = Number(sp9999) - const _spInUsd = 99.99 / sp9999Number - return _spInUsd - } async function handleButtonAction() { - if (step === 1) { + /* if (step === 1) { nextStep(); return; - } + } */ if (step === 2) { try { nextStep(); - await purchasePassport(profiles[1]?.privateKeyArmor, price); setStep(4); } catch (error) { setStep(5); @@ -114,16 +81,16 @@ export default function Subscription() { } if (step === 4 || step === 5) { - navigate("/wallet") + navigate("/") return; } } useEffect(() => { - if (step === 1) { + /* if (step === 1) { const result = (!profiles?.[1]?.tokens?.sp?.balance || Number(price) > profiles?.[1]?.tokens?.sp?.balance); return setIsSubmitButtonDisabled(result); - } + } */ if (step === 2) { const result = (!profiles?.[1]?.tokens?.sp?.balance || (Number(price) > profiles?.[1]?.tokens?.sp?.balance) || (Number(gasfee) > profiles?.[1]?.tokens?.sol?.balance)); @@ -139,7 +106,7 @@ export default function Subscription() {
- {step === 1 && } {/* Purchase payment */} + {/* {step === 1 && } */} {step === 2 && } {/* Purchase confirmation */} {step === 3 && } {/* Purchase loading */} {step === 4 && } {/* Purchase successful */} diff --git a/src/pages/Subscription/page-components/BuyMore.tsx b/src/pages/Subscription/page-components/BuyMore.tsx index 50df475..9a65473 100644 --- a/src/pages/Subscription/page-components/BuyMore.tsx +++ b/src/pages/Subscription/page-components/BuyMore.tsx @@ -1,54 +1,40 @@ -import { useEffect, useState } from 'react'; -import { useDaemonContext } from '../../../providers/DaemonProvider'; +import { useState } from 'react'; export default function BuyMore() { - const { purchasingPlan, setPurchasingPlan, purchasingPlanPaymentTime, setPurchasingPlanPaymentTime } = useDaemonContext(); - - const [standardPrice, setStandardPrice] = useState('2.49'); - const [premiumPrice, setPremiumPrice] = useState('9.99'); - - useEffect(() => { - if (purchasingPlanPaymentTime === 'monthly') { - setStandardPrice('2.49'); - setPremiumPrice('9.99'); - } else { - setStandardPrice('24.99'); - setPremiumPrice('99.99'); - } - - }, [purchasingPlanPaymentTime]); + const [choosenOption, setChoosenOption] = useState<'monthly' | 'yearly'>('yearly'); return (

Buy more

- - + +
-
setPurchasingPlan('standard')}> +
-

Standard

+

Premium

1 device
- $USD -

{standardPrice}

- paid {purchasingPlanPaymentTime} + $USDT +

24.99

+ paid {choosenOption}
-
setPurchasingPlan('premium')}> +
-

Premium

+

Platinum

5 devices
- $USD -

{premiumPrice}

- paid {purchasingPlanPaymentTime} + $USDT +

99.99

+ paid {choosenOption}
+

*If you are a Guardian or CoNETian, ​​transfer your NFT to your Main Account on Silent Pass VPN app.

) } \ No newline at end of file diff --git a/src/pages/Subscription/page-components/CurrentSubscription.tsx b/src/pages/Subscription/page-components/CurrentSubscription.tsx index 2a200d8..90629be 100644 --- a/src/pages/Subscription/page-components/CurrentSubscription.tsx +++ b/src/pages/Subscription/page-components/CurrentSubscription.tsx @@ -1,16 +1,11 @@ -import { useDaemonContext } from "../../../providers/DaemonProvider"; -import { getExpirationDate, getPassportTitle, getPlanDuration } from "../../../utils/utils"; - export default function CurrentSubscription() { - const { activePassport } = useDaemonContext(); - return (
-
-

{getPassportTitle(activePassport)} Passport

-

{getPlanDuration(activePassport)}

+
+

Platinum Silent Pass

+

Yearly plan

-

Expiration date: {getExpirationDate(activePassport)}

+

Expiration date: 15/01/2026

) } \ No newline at end of file diff --git a/src/pages/Subscription/page-components/Footer.tsx b/src/pages/Subscription/page-components/Footer.tsx index 20a2f50..71d8a8b 100644 --- a/src/pages/Subscription/page-components/Footer.tsx +++ b/src/pages/Subscription/page-components/Footer.tsx @@ -1,4 +1,4 @@ -import { Step } from '../../../types/global-types'; +import { Step } from '../'; import { ReactComponent as ProgressIcon } from "../assets/progress-activity.svg"; interface FooterProps { @@ -14,7 +14,7 @@ export default function Footer({ step, isSubmitButtonDisabled, handleButtonActio */} +
- -
+
{/*
*/}
- - {/*
- - -
*/} - +
diff --git a/src/providers/DaemonProvider.tsx b/src/providers/DaemonProvider.tsx index 62d7d38..05ebf12 100644 --- a/src/providers/DaemonProvider.tsx +++ b/src/providers/DaemonProvider.tsx @@ -46,6 +46,10 @@ type DaemonContext = { setIsLocalProxy: (val: boolean)=> void globalProxy: boolean, setGlobalProxy: (val: boolean)=> void + paymentKind: number, + setPaymentKind: (val: number) => void + successNFTID: number, + setSuccessNFTID: (val: number) => void }; type DaemonProps = { @@ -97,8 +101,11 @@ const defaultContextValue: DaemonContext = { isLocalProxy: false, setIsLocalProxy(val) {}, globalProxy: false, - setGlobalProxy: () => {} - + setGlobalProxy: () => {}, + paymentKind: 0, + setPaymentKind: () => {}, + successNFTID: 0, + setSuccessNFTID: () => {} }; const Daemon = createContext(defaultContextValue); @@ -132,6 +139,8 @@ export function DaemonProvider({ children }: DaemonProps) { const [randomSolanaRPC, setRandomSolanaRPC] = useState(null); const [isIOS, setIsIOS] = useState(false); const [isLocalProxy, setIsLocalProxy] = useState(false); + const [paymentKind, setPaymentKind] = useState(0) + const [successNFTID, setSuccessNFTID] = useState(0) useEffect(() => { { @@ -149,7 +158,8 @@ export function DaemonProvider({ children }: DaemonProps) { isPassportInfoPopupOpen, setIsPassportInfoPopupOpen, activePassportUpdated, setActivePassportUpdated, activePassport, setActivePassport, isSelectPassportPopupOpen, setIsSelectPassportPopupOpen, purchasingPlan, setPurchasingPlan, purchasingPlanPaymentTime, setPurchasingPlanPaymentTime, - setRandomSolanaRPC, randomSolanaRPC, isIOS, setIsIOS, isLocalProxy, setIsLocalProxy, globalProxy, setGlobalProxy }}>, + setRandomSolanaRPC, randomSolanaRPC, isIOS, setIsIOS, isLocalProxy, setIsLocalProxy, globalProxy, setGlobalProxy, + paymentKind, setPaymentKind, successNFTID, setSuccessNFTID }}>, {children} diff --git a/src/services/wallets.ts b/src/services/wallets.ts index db5b816..acf6bfa 100644 --- a/src/services/wallets.ts +++ b/src/services/wallets.ts @@ -13,6 +13,7 @@ import { localDatabaseName, rewardWalletAddress, solanaRpc, + payment_endpoint } from "../utils/constants"; import {} from './listeners' import contracts from "../utils/contracts"; @@ -1246,6 +1247,7 @@ const waitingNFT = (wallet: ethers.Wallet) => new Promise(async resolve => { } } } + conetDepinProvider.on('block', listenning) const _time = setTimeout(() => { // TimeOUT @@ -1320,6 +1322,63 @@ const checkFreePassport = async () => { return true } +const getPaymentUrl = async (price: number) => { + if (!CoNET_Data?.profiles?.length) { + return null; + } + const profile = CoNET_Data?.profiles[0] + const solanaWallet = CoNET_Data?.profiles[1].keyID + if (!solanaWallet||!profile) { + return null; + } + + const url = `${payment_endpoint}payment_stripe` + const message = JSON.stringify({ walletAddress: profile.keyID, solanaWallet, price}) + const wallet = new ethers.Wallet(profile.privateKeyArmor) + const signMessage = await wallet.signMessage(message) + const sendData = { + message, signMessage + } + const result = await postToEndpoint(url, true, sendData) + return result +} + +const waitingPaymentStatus = async (): Promise => { + if (!CoNET_Data?.profiles?.length) { + return false; + } + const profile = CoNET_Data?.profiles[0] + const solanaWallet = CoNET_Data?.profiles[1].keyID + if (!solanaWallet||!profile) { + return false; + } + + const url = `${payment_endpoint}payment_stripe_waiting` + const message = JSON.stringify({ walletAddress: profile.keyID}) + const wallet = new ethers.Wallet(profile.privateKeyArmor) + const signMessage = await wallet.signMessage(message) + const sendData = { + message, signMessage + } + + const waiting = async (): Promise => new Promise(async resolve => { + const result = await postToEndpoint(url, true, sendData) + if (!result || !result?.status) { + return resolve (false) + } + if (result.status < 100) { + return setTimeout(() => { + return waiting().then (jj => resolve(jj)) + }, 10 * 1000) + } + return resolve(result.status) + }) + const result = await waiting () + return result +} + + + export { createOrGetWallet, createGPGKey, @@ -1340,5 +1399,7 @@ export { getReceivedAmounts, RealizationRedeem, checkFreePassport, - checkFreePassportProcess + checkFreePassportProcess, + getPaymentUrl, + waitingPaymentStatus }; diff --git a/src/utils/abis.ts b/src/utils/abis.ts index 061fce9..f6436c6 100644 --- a/src/utils/abis.ts +++ b/src/utils/abis.ts @@ -5002,4 +5002,187 @@ export const Distributor = [ "stateMutability": "nonpayable", "type": "function" } +] +export const PaymentPassport = [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "status", + "type": "uint256" + } + ], + "name": "paymentStatus", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + } + ], + "name": "ChangePaymentStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "adminList", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bool", + "name": "monthly", + "type": "bool" + }, + { + "internalType": "string", + "name": "_payID", + "type": "string" + }, + { + "internalType": "uint256", + "name": "totalNFT", + "type": "uint256" + } + ], + "name": "batchMintPassport", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "changeAddressInAdminlist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "distributor", + "outputs": [ + { + "internalType": "contract SPPassportDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_payID", + "type": "string" + } + ], + "name": "getPayID", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiresDayes", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_payID", + "type": "string" + } + ], + "name": "mintPassport", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "payID", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } ] \ No newline at end of file diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 001c6cd..6d235ef 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -3,7 +3,8 @@ import { ethers } from "ethers"; const localDatabaseName = "conet"; const apiv3_endpoint = `https://apiv3.conet.network/api/`; const apiv4_endpoint = `https://apiv4.conet.network/api/`; -const XMLHttpRequestTimeout = 30 * 1000; +const payment_endpoint = `https://hooks.conet.network/api/`; +const XMLHttpRequestTimeout = 90 * 1000; const conetRpc = "https://cancun-rpc.conet.network"; const mainChain_rpc = "https://mainnet-rpc.conet.network"; const _ethRpc = [ @@ -15,6 +16,8 @@ const _ethRpc = [ const solanaRpc = "https://solana-rpc.conet.network"; const ethRpc = () => _ethRpc[Math.round(Math.random() * (_ethRpc.length - 1))]; const rewardWalletAddress = "GUq7PhyAUZko2mPhv3CupmdJKQ61LH8VyrdsRL25q7zg"; +const stripe_pay_monthly = 'https://buy.stripe.com/test_9AQ16b6Du82p0Ja9AG?client_reference_id=' +const stripe_pay_Annual ='https://buy.stripe.com/test_eVa2af5zqdmJ2Ri14b?client_reference_id=' const conetProvider = new ethers.JsonRpcProvider(conetRpc); let ethProvider = new ethers.JsonRpcProvider(ethRpc()); @@ -34,5 +37,8 @@ export { conetProvider, ethProvider, conetDepinProvider, - changeRPC + changeRPC, + stripe_pay_monthly, + stripe_pay_Annual, + payment_endpoint }; diff --git a/src/utils/contracts.ts b/src/utils/contracts.ts index b077a3d..36e5676 100644 --- a/src/utils/contracts.ts +++ b/src/utils/contracts.ts @@ -6,6 +6,7 @@ import { ConetStorageAbi, PassportCancunAbi, ConetDepinAbi, + PaymentPassport, PassportMainnetAbi, SpOracleAbi, PurchasePassportAbi, @@ -77,6 +78,11 @@ import { abi: SpClubAbi, network: "CONET DePIN", }, + PaymentPassport: { + address: '0xDa961275aAb40aCb1943D8969aB40efdA3719943', + network: "CONET DePIN", + abi: PaymentPassport + } }; export default contracts; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index f603226..e2b6ed5 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -76,7 +76,7 @@ export const initProfileTokens = () => { return ret; }; -export const postToEndpoint = (url: string, post: boolean, jsonData: any): Promise<""|boolean|{error: string}> => { +export const postToEndpoint = (url: string, post: boolean, jsonData: any): Promise<""|boolean|any> => { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = () => { @@ -111,18 +111,23 @@ export const postToEndpoint = (url: string, post: boolean, jsonData: any): Promi return resolve(false); }; - xhr.onerror = (err) => { - console.log(`xhr.onerror`, err); - clearTimeout(timeCount); - return reject(err); - }; - - xhr.open(post ? "POST" : "GET", url, true); - - xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); - - xhr.send(jsonData ? JSON.stringify(jsonData) : ""); - + // xhr.onerror = (err) => { + // console.log(`xhr.onerror`, err); + // clearTimeout(timeCount); + // return reject(err); + // } + + + xhr.onabort = ev => { + console.log(`ev`) + reject(ev) + } + xhr.onerror = err => { + reject (err) + } + xhr.open(post ? "POST" : "GET", url, true) + xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhr.send(jsonData ? JSON.stringify(jsonData) : "") const timeCount = setTimeout(() => { const Err = `Timeout!`; console.log(`postToEndpoint ${url} Timeout Error`, Err);