Skip to content

Commit b9b8509

Browse files
committed
feat: spclub joining and showing
1 parent 9e6468c commit b9b8509

File tree

7 files changed

+223
-58
lines changed

7 files changed

+223
-58
lines changed

src/App.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ function App() {
3333
}
3434
useEffect(() => {
3535
const handlePassport = async () => {
36+
if (!CoNET_Data?.profiles[0]?.keyID) return
37+
3638
await tryToRequireFreePassport();
37-
const info = await getCurrentPassportInfo();
39+
40+
const info = await getCurrentPassportInfo(CoNET_Data?.profiles[0]?.keyID);
3841

3942
const tmpData = CoNET_Data;
4043

@@ -86,7 +89,7 @@ function App() {
8689

8790
getAllNodes(allRegions, setClosestRegion, (allNodes: nodes_info[]) => {
8891
setSOlanaRPC(allNodes)
89-
setaAllNodes(allNodes)
92+
setaAllNodes(allNodes)
9093
const randomIndex = Math.floor(Math.random() * (allNodes.length - 1))
9194
setRandomSolanaRPC(allNodes[randomIndex])
9295
if (!CoNET_Data || !CoNET_Data?.profiles) {

src/api/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ export const getServerIpAddress = async (): Promise<AxiosResponse<any>> => {
4949

5050
export const joinSpClub = async (
5151
conetProfile: profile,
52-
solanaProfile: profile
52+
solanaProfile: profile,
53+
referrer: string
5354
) => {
5455
const message = JSON.stringify({
5556
walletAddress: conetProfile.keyID,
5657
solanaWallet: solanaProfile.keyID,
57-
referrer: "",
58+
referrer: referrer,
5859
});
5960

6061
const wallet = new ethers.Wallet(conetProfile.privateKeyArmor);

src/components/AccountList/ReferralProgram.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ export default function ReferralProgram() {
4343

4444
return (
4545
<div className={`account-wrapper ${isOpen ? 'active' : ''}`}>
46-
{/* <div className="account-main-card" onClick={() => setIsOpen((prev) => !prev)}> */}
47-
<div className="disabled account-main-card">
46+
<div className="account-main-card" onClick={() => setIsOpen((prev) => !prev)}>
47+
{/* <div className="disabled account-main-card"> */}
4848
<div className="name">
4949
<h3>Referral Program</h3>
5050
<img height='16px' width='16px' className="chevron" src="./assets/right-chevron.svg" />
@@ -112,15 +112,18 @@ export default function ReferralProgram() {
112112
<Separator />
113113

114114
<div className="info-wrapper" style={{ maxHeight: '200px', overflowY: 'auto', }}>
115-
<p>History</p>
115+
<p>Invitees</p>
116116
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px', width: '100%', paddingLeft: '16px' }}>
117-
{profiles?.[0]?.spClub?.referees
118-
? profiles?.[0]?.spClub.referees?.map((referee: any) =>
119-
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', width: '100%', gap: '8px' }}>
120-
<p style={{ width: 'auto', fontSize: '16px', color: '#989899', fontWeight: 400 }}>{referee?.slice(0, 5) + '...' + referee?.slice(-5)}</p>
121-
<p style={{ width: 'auto', fontSize: '16px', color: '#9FBFE5FE', fontWeight: 400 }}>+ {SP_EARNED_FROM_REFERRAL} $SP</p>
122-
</div>
123-
)
117+
{profiles?.[0]?.spClub
118+
?
119+
profiles.spClub?.totalReferees > 0 ?
120+
profiles?.[0]?.spClub.referees?.map((referee: any) =>
121+
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', width: '100%', gap: '8px' }}>
122+
<p style={{ width: 'auto', fontSize: '16px', color: '#FFFFFF', fontWeight: 400 }}>{referee.activePlan}</p>
123+
<p style={{ width: 'auto', fontSize: '16px', color: '#989899', fontWeight: 400 }}>{referee.walletAddress?.slice(0, 5) + '...' + referee?.slice(-5)}</p>
124+
</div>
125+
) :
126+
<p>No invitees</p>
124127
: <Skeleton width={'100%'} height={'20px'} />}
125128
</div>
126129
</div>

src/components/AccountList/SpClub.tsx

Lines changed: 90 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,115 @@ import SpClubCongratsPopup from '../SpClubCongratsPopup';
55
import SimpleLoadingRing from '../SimpleLoadingRing';
66
import { joinSpClub } from '../../api';
77
import { useDaemonContext } from '../../providers/DaemonProvider';
8+
import { getSpClubMemberId } from '../../services/wallets';
9+
import { isPassportValid } from '../../utils/utils';
810

911
export default function SpClub() {
1012
const [isOpen, setIsOpen] = useState<boolean>(false);
11-
const [walletAddress, setWalletAddress] = useState('');
1213
const [isCongratsPopupOpen, setIsCongratsPopupOpen] = useState<boolean>(false);
1314
const [isLoading, setIsLoading] = useState<boolean>(false);
15+
const [memberId, setMemberId] = useState<string>('0');
16+
const [referrer, setReferrer] = useState<string>('');
1417

1518
const { profiles } = useDaemonContext();
1619

20+
const fetchMemberIdWithRetry = async (startTime = Date.now()): Promise<string | null> => {
21+
const _memberId = await getSpClubMemberId(profiles[0]);
22+
23+
if (_memberId.toString() !== '0') {
24+
return _memberId.toString();
25+
}
26+
27+
if (Date.now() - startTime >= 60000) { // Stop after 1 minute
28+
return null;
29+
}
30+
31+
await new Promise((resolve) => setTimeout(resolve, 2000));
32+
return fetchMemberIdWithRetry(startTime); // Recursive call with startTime
33+
};
34+
1735
const handleJoinClub = async () => {
1836
setIsLoading(true)
1937

2038
try {
21-
const result = await joinSpClub(profiles[0], profiles[1]);
39+
const result = await joinSpClub(profiles[0], profiles[1], referrer);
2240

23-
if (result !== false)
41+
if (result !== false) {
42+
const _memberId = await fetchMemberIdWithRetry()
43+
44+
if (_memberId === null) throw new Error("Couldn't fetch memberId")
45+
46+
setMemberId(_memberId);
2447
setIsCongratsPopupOpen(true)
48+
}
2549
} catch (error) {
2650
console.log(error);
2751
}
2852

2953
setTimeout(() => setIsLoading(false), 2000)
3054
}
3155

56+
const renderCardContent = () => {
57+
if (profiles?.[0]?.spClub?.memberId && profiles?.[0]?.spClub?.memberId !== '0') {
58+
return (
59+
<div className="info-wrapper" style={{
60+
gap: '16px'
61+
}}>
62+
<div>
63+
<p style={{ fontSize: '14px', color: '#FFFFFF' }}>Member ID</p>
64+
<p style={{ fontSize: '16px', color: '#989899' }}>{profiles?.[0]?.spClub?.memberId.toString()}</p>
65+
</div>
66+
67+
{
68+
profiles?.[0]?.spClub?.inviter &&
69+
<div>
70+
<p style={{ fontSize: '14px', color: '#FFFFFF' }}>Inviter</p>
71+
<p style={{ fontSize: '16px', color: '#989899' }}>{profiles?.[0]?.spClub?.inviter?.toString()}</p>
72+
</div>
73+
}
74+
75+
{
76+
!isPassportValid(parseInt(profiles?.[0]?.spClub?.expires)) &&
77+
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
78+
<p style={{ fontSize: '16px', color: '#FFFFFF', textAlign: 'center' }}>Passport Expired.</p>
79+
<p style={{ fontSize: '12px', color: '#989899', textAlign: 'center' }}>Buy another passport to reactivate your club membership.</p>
80+
</div>
81+
}
82+
</div>
83+
)
84+
}
85+
86+
return (
87+
<div className="info-wrapper" style={{ gap: '24px' }}>
88+
<div>
89+
<p>Input you inviter's wallet address</p>
90+
<input value={referrer} onChange={(e) => setReferrer(e.target.value)} placeholder="wallet address" style={{ color: '#FFFFFF' }} />
91+
</div>
92+
93+
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', gap: '24px', flexDirection: 'row', alignItems: 'center' }}>
94+
<div style={{ width: '100%', height: '1px', background: '#FFFFFF' }} />
95+
96+
<div>
97+
<p style={{ fontSize: '20px' }}>or</p>
98+
</div>
99+
100+
<div style={{ width: '100%', height: '1px', background: '#FFFFFF' }} />
101+
102+
</div>
103+
104+
<div style={{ width: '100%' }}>
105+
<p style={{ width: '100%', textAlign: 'center', fontSize: '16px' }}>Get Silent Pass Passport and join the club</p>
106+
</div>
107+
108+
<button style={{ cursor: 'pointer' }} onClick={handleJoinClub}>
109+
{isLoading ? <SimpleLoadingRing /> :
110+
<p>Join Club</p>
111+
}
112+
</button>
113+
</div>
114+
)
115+
}
116+
32117
return (
33118
<>
34119
<div className={`account-wrapper referral-program ${isOpen ? 'active' : ''}`}>
@@ -40,39 +125,14 @@ export default function SpClub() {
40125
</div>
41126
</div>
42127
<div className="info-card">
43-
<div className="info-wrapper">
44-
<div>
45-
<p>Input you inviter wallet address</p>
46-
<input value={walletAddress} onChange={(e) => setWalletAddress(e.target.value)} placeholder="wallet address" />
47-
</div>
48-
49-
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', gap: '24px', flexDirection: 'row', alignItems: 'center' }}>
50-
<div style={{ width: '100%', height: '1px', background: '#FFFFFF' }} />
51-
52-
<div>
53-
<p style={{ fontSize: '20px' }}>or</p>
54-
</div>
55-
56-
<div style={{ width: '100%', height: '1px', background: '#FFFFFF' }} />
57128

58-
</div>
59-
60-
<div style={{ width: '100%' }}>
61-
<p style={{ width: '100%', textAlign: 'center', fontSize: '16px' }}>Get Silent Pass Passport and join the club</p>
62-
</div>
63-
64-
<button onClick={handleJoinClub}>
65-
{isLoading ? <SimpleLoadingRing /> :
66-
<p>Join Club</p>
67-
}
68-
</button>
69-
</div>
129+
{renderCardContent()}
70130
</div>
71131
</div>
72132

73133
{
74134
isCongratsPopupOpen && (
75-
<SpClubCongratsPopup setIsCongratsPopupOpen={setIsCongratsPopupOpen} />
135+
<SpClubCongratsPopup setIsCongratsPopupOpen={setIsCongratsPopupOpen} memberId={memberId} />
76136
)
77137
}
78138
</>

src/services/wallets.ts

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,10 @@ const requireFreePassport = async () => {
288288
}
289289
};
290290

291-
const getCurrentPassportInfoInChain = async (chain: string) => {
291+
const getCurrentPassportInfoInChain = async (
292+
walletAddress: string,
293+
chain: string
294+
) => {
292295
if (!CoNET_Data) {
293296
return;
294297
}
@@ -318,7 +321,7 @@ const getCurrentPassportInfoInChain = async (chain: string) => {
318321
);
319322

320323
try {
321-
const result = await passportContract.getCurrentPassport(wallet.address);
324+
const result = await passportContract.getCurrentPassport(walletAddress);
322325
return result;
323326
} catch (ex) {
324327
console.log(ex);
@@ -415,18 +418,20 @@ const estimateChangeNFTGasFee = async (chain: string, nftId: string) => {
415418
}
416419
};
417420

418-
const getCurrentPassportInfo = async () => {
419-
if (!CoNET_Data) {
420-
return;
421-
}
422-
423-
const resultMainnet = await getCurrentPassportInfoInChain("mainnet");
421+
const getCurrentPassportInfo = async (walletAddress: string) => {
422+
const resultMainnet = await getCurrentPassportInfoInChain(
423+
walletAddress,
424+
"mainnet"
425+
);
424426

425427
if (resultMainnet?.nftIDs?.toString() !== "0") {
426428
return resultMainnet;
427429
}
428430

429-
const resultCancun = await getCurrentPassportInfoInChain("cancun");
431+
const resultCancun = await getCurrentPassportInfoInChain(
432+
walletAddress,
433+
"cancun"
434+
);
430435

431436
return resultCancun;
432437
};
@@ -572,7 +577,7 @@ const getPassportsInfoForProfile = async (profile: profile): Promise<void> => {
572577
const tmpCancunPassports = await getPassportsInfo(profile, "cancun");
573578
const tmpMainnetPassports = await getPassportsInfo(profile, "mainnet");
574579

575-
const _currentPassport = await getCurrentPassportInfo();
580+
const _currentPassport = await getCurrentPassportInfo(profile.keyID);
576581

577582
profile = {
578583
...profile,
@@ -774,16 +779,94 @@ const getSpClubInfo = async (profile: profile) => {
774779
console.log(error);
775780
}
776781

782+
if (profile.spClub.memberId) {
783+
try {
784+
const referrerResult = await contract.getReferer(profile.keyID);
785+
786+
if (
787+
referrerResult.referrer !== "0x0000000000000000000000000000000000000000"
788+
)
789+
profile.spClub.referrer = referrerResult.referrer;
790+
} catch (error) {
791+
console.log(error);
792+
}
793+
794+
try {
795+
const refereesResult = await contract.getReferees(profile.keyID, 0);
796+
profile.spClub.totalReferees = refereesResult._total_length;
797+
798+
if (
799+
refereesResult?.referees?.length > 0 &&
800+
refereesResult?.referees?.[0] ===
801+
"0x0000000000000000000000000000000000000000"
802+
)
803+
profile.spClub.totalReferees = 0;
804+
805+
refereesResult.referees
806+
.filter(
807+
(referee: string) =>
808+
referee !== "0x0000000000000000000000000000000000000000"
809+
)
810+
.forEach(async (referee: string) => {
811+
const _activePassport = await getCurrentPassportInfo(referee);
812+
813+
const activePassport = {
814+
nftID: _activePassport?.nftIDs?.toString(),
815+
expires: _activePassport?.expires?.toString(),
816+
expiresDays: _activePassport?.expiresDays?.toString(),
817+
premium: _activePassport?.premium,
818+
};
819+
820+
const _referee = {
821+
walletAddress: referee,
822+
activePassport: activePassport,
823+
};
824+
825+
profile.spClub?.referees.push(_referee);
826+
});
827+
} catch (error) {
828+
console.log(error);
829+
}
830+
}
831+
832+
temp.profiles[0] = profile;
833+
setCoNET_Data(temp);
834+
};
835+
836+
const getSpClubMemberId = async (profile: profile) => {
837+
const wallet = new ethers.Wallet(profile.privateKeyArmor, conetDepinProvider);
838+
const contract = new ethers.Contract(
839+
contracts.SpClub.address,
840+
contracts.SpClub.abi,
841+
wallet
842+
);
843+
844+
if (!profile.spClub) {
845+
profile.spClub = {
846+
memberId: "0",
847+
referrer: "",
848+
referees: [],
849+
totalReferees: 0,
850+
};
851+
}
852+
777853
try {
778-
const result = await contract.getReferees(profile.keyID, 0);
779-
profile.spClub.referees = result.referees;
780-
profile.spClub.totalReferees = result._total_length;
854+
const result = await contract.membership(profile.keyID);
855+
profile.spClub.memberId = result;
781856
} catch (error) {
782857
console.log(error);
783858
}
784859

860+
const temp = CoNET_Data;
861+
862+
if (!temp) {
863+
return "0";
864+
}
865+
785866
temp.profiles[0] = profile;
786867
setCoNET_Data(temp);
868+
869+
return profile.spClub.memberId;
787870
};
788871

789872
export {
@@ -801,4 +884,5 @@ export {
801884
getPassportsInfoForProfile,
802885
refreshSolanaBalances,
803886
getSpClubInfo,
887+
getSpClubMemberId,
804888
};

0 commit comments

Comments
 (0)