-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: domain gift page * feat: API & contract interactions * fix: only 5+ length domains accepted * Update utils/campaignService.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * cleaning the code * cleaning the code * Update pages/freeregistration.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat: cleaning the code + better UX * fixing build * Update components/discount/registerFree.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/discount/registerFree.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * using local storage for signature * Update components/discount/registerFree.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: duplicate import * fix: removing coupon from starknet call * Adding identity mint * cleaning the code * fix: gift image * Update components/discount/FreeRegisterPresentation.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/discount/FreeRegisterPresentation.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/discount/FreeRegisterPresentation.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * cleaning the code * cleaning the code --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Loading branch information
1 parent
468f089
commit df74337
Showing
20 changed files
with
658 additions
and
123 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
import React from "react"; | ||
import type { FunctionComponent } from "react"; | ||
import { useEffect, useState } from "react"; | ||
import type { Call } from "starknet"; | ||
import Button from "../UI/button"; | ||
import { useAccount, useContractWrite } from "@starknet-react/core"; | ||
import { utils } from "starknetid.js"; | ||
import { getDomainWithStark } from "../../utils/stringService"; | ||
import { numberToFixedString } from "../../utils/feltService"; | ||
import { posthog } from "posthog-js"; | ||
import styles from "../../styles/components/registerV2.module.css"; | ||
import TextField from "../UI/textField"; | ||
import { Divider } from "@mui/material"; | ||
import RegisterSummary from "../domains/registerSummary"; | ||
import registrationCalls from "../../utils/callData/registrationCalls"; | ||
import { computeMetadataHash, generateSalt } from "../../utils/userDataService"; | ||
import BackButton from "../UI/backButton"; | ||
import { useNotificationManager } from "../../hooks/useNotificationManager"; | ||
import { NotificationType, TransactionType } from "../../utils/constants"; | ||
import ConnectButton from "../UI/connectButton"; | ||
import { getFreeDomain } from "@/utils/campaignService"; | ||
import TermCheckbox from "../domains/termCheckbox"; | ||
import { useRouter } from "next/router"; | ||
|
||
type FreeRegisterCheckoutProps = { | ||
domain: string; | ||
duration: number; | ||
customMessage: string; | ||
goBack: () => void; | ||
couponCode?: boolean; | ||
couponHelper?: string; | ||
banner: string; | ||
}; | ||
|
||
const FreeRegisterCheckout: FunctionComponent<FreeRegisterCheckoutProps> = ({ | ||
domain, | ||
duration, | ||
customMessage, | ||
goBack, | ||
couponCode, | ||
couponHelper, | ||
banner, | ||
}) => { | ||
const [targetAddress, setTargetAddress] = useState<string>(""); | ||
const [callData, setCallData] = useState<Call[]>([]); | ||
const [salt, setSalt] = useState<string | undefined>(); | ||
const encodedDomain = utils | ||
.encodeDomain(domain) | ||
.map((element) => element.toString())[0]; | ||
const [termsBox, setTermsBox] = useState<boolean>(true); | ||
const [metadataHash, setMetadataHash] = useState<string | undefined>(); | ||
const { account, address } = useAccount(); | ||
const { writeAsync: execute, data: registerData } = useContractWrite({ | ||
calls: callData, | ||
}); | ||
const [domainsMinting, setDomainsMinting] = useState<Map<string, boolean>>( | ||
new Map() | ||
); | ||
const router = useRouter(); | ||
const [tokenId, setTokenId] = useState<number>(0); | ||
const [coupon, setCoupon] = useState<string>(""); | ||
const [couponError, setCouponError] = useState<string>(""); | ||
const [signature, setSignature] = useState<string[]>(["", ""]); | ||
const [loadingCoupon, setLoadingCoupon] = useState<boolean>(false); | ||
const { addTransaction } = useNotificationManager(); | ||
|
||
// on first load, we generate a salt | ||
useEffect(() => { | ||
setSalt(generateSalt()); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (address) setTargetAddress(address); | ||
}, [address]); | ||
|
||
useEffect(() => { | ||
// salt must not be empty to preserve privacy | ||
if (!salt) return; | ||
(async () => { | ||
setMetadataHash(await computeMetadataHash("none", "none", salt)); | ||
})(); | ||
}, [salt]); | ||
|
||
useEffect(() => { | ||
// Variables | ||
const newTokenId: number = Math.floor(Math.random() * 1000000000000); | ||
setTokenId(newTokenId); | ||
const txMetadataHash = `0x${metadataHash}` as HexString; | ||
|
||
const freeRegisterCalls = registrationCalls.getFreeRegistrationCalls( | ||
newTokenId, | ||
encodedDomain, | ||
signature, | ||
txMetadataHash | ||
); | ||
return setCallData(freeRegisterCalls); | ||
}, [metadataHash, encodedDomain, signature]); | ||
|
||
function changeCoupon(value: string): void { | ||
setCoupon(value); | ||
setLoadingCoupon(true); | ||
} | ||
|
||
useEffect(() => { | ||
if (!registerData?.transaction_hash) return; | ||
posthog?.capture("register"); | ||
addTransaction({ | ||
timestamp: Date.now(), | ||
subtext: "Domain registration", | ||
type: NotificationType.TRANSACTION, | ||
data: { | ||
type: TransactionType.BUY_DOMAIN, | ||
hash: registerData.transaction_hash, | ||
status: "pending", | ||
}, | ||
}); | ||
|
||
router.push(`/confirmation?tokenId=${tokenId}`); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [registerData, tokenId]); | ||
|
||
useEffect(() => { | ||
if (!coupon) { | ||
setCouponError("Please enter a coupon code"); | ||
setLoadingCoupon(false); | ||
return; | ||
} | ||
const lastSuccessCoupon = localStorage.getItem("lastSuccessCoupon"); | ||
if (coupon === lastSuccessCoupon) { | ||
setCouponError(""); | ||
setLoadingCoupon(false); | ||
const signature = JSON.parse( | ||
localStorage.getItem("couponSignature") as string | ||
); | ||
setSignature(signature); | ||
return; | ||
} | ||
if (!address) return; | ||
getFreeDomain(address, `${domain}.stark`, coupon).then((res) => { | ||
if (res.error) | ||
setCouponError( | ||
typeof res.error === "string" ? res.error : JSON.stringify(res.error) | ||
); | ||
else { | ||
const signature = [res.r, res.s]; | ||
setSignature(signature); | ||
setCouponError(""); | ||
// Write in local storage | ||
localStorage.setItem("lastSuccessCoupon", coupon); | ||
localStorage.setItem("couponSignature", JSON.stringify(signature)); | ||
} | ||
setLoadingCoupon(false); | ||
}); | ||
}, [coupon, domain, address]); | ||
|
||
const handleRegister = () => | ||
execute().then(() => | ||
setDomainsMinting((prev) => | ||
new Map(prev).set(encodedDomain.toString(), true) | ||
) | ||
); | ||
|
||
return ( | ||
<div className={styles.container}> | ||
<div className={styles.card}> | ||
<div className={styles.form}> | ||
<BackButton onClick={() => goBack()} /> | ||
<div className="flex flex-col items-start gap-4 self-stretch"> | ||
<p className={styles.legend}>Your registration</p> | ||
<h3 className={styles.domain}>{getDomainWithStark(domain)}</h3> | ||
</div> | ||
<div className="flex flex-col items-start gap-6 self-stretch"> | ||
{couponCode ? ( | ||
<TextField | ||
helperText={couponHelper} | ||
label="Coupon code" | ||
value={coupon} | ||
onChange={(e) => changeCoupon(e.target.value)} | ||
color="secondary" | ||
error={Boolean(couponError)} | ||
errorMessage={couponError} | ||
/> | ||
) : null} | ||
</div> | ||
</div> | ||
<div className={styles.summary}> | ||
<RegisterSummary | ||
duration={Number(numberToFixedString(duration / 365))} | ||
renewalBox={false} | ||
customMessage={customMessage} | ||
isFree={true} | ||
/> | ||
<Divider className="w-full" /> | ||
<TermCheckbox | ||
checked={termsBox} | ||
onChange={() => setTermsBox(!termsBox)} | ||
/> | ||
{address ? ( | ||
<Button | ||
onClick={handleRegister} | ||
disabled={ | ||
(domainsMinting.get(encodedDomain) as boolean) || | ||
!account || | ||
!duration || | ||
!targetAddress || | ||
!termsBox || | ||
Boolean(couponError) || | ||
loadingCoupon | ||
} | ||
> | ||
{!termsBox | ||
? "Please accept terms & policies" | ||
: couponError | ||
? "Enter a valid Coupon" | ||
: "Register my domain"} | ||
</Button> | ||
) : ( | ||
<ConnectButton /> | ||
)} | ||
</div> | ||
</div> | ||
<div | ||
className={styles.image} | ||
style={{ | ||
backgroundImage: `url(${banner})`, | ||
}} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
export default FreeRegisterCheckout; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import React from "react"; | ||
import type { FunctionComponent } from "react"; | ||
import styles from "../../styles/discount.module.css"; | ||
import SearchBar from "../UI/searchBar"; | ||
import Timer from "../UI/timer"; | ||
|
||
type FreeRegisterPresentationProps = { | ||
setSearchResult: (searchResult: SearchResult) => void; | ||
setScreen: (screen: number) => void; | ||
title: { desc: string; catch: string; descAfter?: string }; | ||
desc: string; | ||
image: string; | ||
expiry: number; | ||
}; | ||
|
||
const FreeRegisterPresentation: FunctionComponent< | ||
FreeRegisterPresentationProps | ||
> = ({ setSearchResult, setScreen, title, desc, image, expiry }) => { | ||
function onSearch(searchResult: SearchResult) { | ||
setSearchResult(searchResult); | ||
setScreen(2); | ||
} | ||
|
||
return ( | ||
<div className={styles.wrapperScreen}> | ||
<div className={styles.containerVariant}> | ||
<div className="max-w-4xl flex flex-col items-start justify-start gap-5 mx-5 mb-5"> | ||
<div className="flex flex-col lg:items-start items-center text-center sm:text-start gap-3"> | ||
<h1 className={styles.titleVariant}> | ||
{title.desc} <span className="text-primary">{title.catch}</span> | ||
{title.descAfter && ` ${title.descAfter}`} | ||
</h1> | ||
<p className={styles.descriptionVariant}>{desc}</p> | ||
</div> | ||
<div className={styles.searchBarVariant}> | ||
<SearchBar onSearch={onSearch} showHistory={false} is5LettersOnly /> | ||
</div> | ||
</div> | ||
<div className={styles.illustrationContainerVariant}> | ||
<img | ||
src={image} | ||
className={styles.illustrationVariant} | ||
alt="Registration illustration" | ||
/> | ||
<Timer expiry={expiry} fixed /> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default FreeRegisterPresentation; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.