Skip to content

Commit

Permalink
feat: domain gift page
Browse files Browse the repository at this point in the history
  • Loading branch information
Marchand-Nicolas committed May 22, 2024
1 parent d80ca1b commit ba22ed4
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 11 deletions.
9 changes: 9 additions & 0 deletions components/discount/discountCheckoutScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ type DiscountCheckoutScreenProps = {
price: string;
goBack: () => void;
mailGroupId: string;
couponCode?: boolean;
couponHelper?: string;
banner?: string;
};

const DiscountCheckoutScreen: FunctionComponent<
Expand All @@ -22,6 +25,9 @@ const DiscountCheckoutScreen: FunctionComponent<
price,
goBack,
mailGroupId,
couponCode,
couponHelper,
banner,
}) => {
return (
<div className={styles.container}>
Expand All @@ -36,6 +42,9 @@ const DiscountCheckoutScreen: FunctionComponent<
mailGroupId,
]} // Second group is the special group for discount group
goBack={goBack}
couponCode={couponCode}
couponHelper={couponHelper}
banner={banner}
/>
</div>
);
Expand Down
47 changes: 47 additions & 0 deletions components/discount/discountOfferScreenVariant.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { FunctionComponent } from "react";
import styles from "../../styles/discount.module.css";
import SearchBar from "../UI/searchBar";
import Timer from "../UI/timer";

type DiscountOfferScreenVariantProps = {
setSearchResult: (searchResult: SearchResult) => void;
setScreen: (screen: number) => void;
title: { desc: string; catch: string; descAfter?: string };
desc: string;
image: string;
expiry: number;
};

const DiscountOfferScreenVariant: FunctionComponent<
DiscountOfferScreenVariantProps
> = ({ 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} />
</div>
</div>
<div className={styles.illustrationContainerVariant}>
<img src={image} className={styles.illustrationVariant} />
<Timer expiry={expiry} fixed />
</div>
</div>
</div>
);
};

export default DiscountOfferScreenVariant;
34 changes: 32 additions & 2 deletions components/discount/registerDiscount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type RegisterDiscountProps = {
priceInEth: string;
mailGroups: string[];
goBack: () => void;
couponCode?: boolean;
couponHelper?: string;
banner?: string;
};

const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
Expand All @@ -59,6 +62,9 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
priceInEth,
mailGroups,
goBack,
couponCode,
couponHelper,
banner = "/visuals/register.webp",
}) => {
const [targetAddress, setTargetAddress] = useState<string>("");
const [email, setEmail] = useState<string>("");
Expand Down Expand Up @@ -89,6 +95,8 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
const [domainsMinting, setDomainsMinting] = useState<Map<string, boolean>>(
new Map()
);
const [coupon, setCoupon] = useState<string>("");
const [couponError, setCouponError] = useState<boolean>(true);
const { addTransaction } = useNotificationManager();
const needsAllowance = useAllowanceCheck(displayedCurrency, address);
const tokenBalances = useBalances(address); // fetch the user balances for all whitelisted tokens
Expand Down Expand Up @@ -322,6 +330,11 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
setEmailError(isValidEmail(value) ? false : true);
}

function changeCoupon(value: string): void {
setCoupon(value);
setCouponError(value.length === 0);
}

useEffect(() => {
if (isSwissResident) {
setSalesTaxRate(swissVatRate);
Expand All @@ -347,6 +360,8 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
setDisplayedCurrency(type);
};

const isFree = priceInEth === "0";

return (
<div className={styles.container}>
<div className={styles.card}>
Expand All @@ -370,6 +385,17 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
isSwissResident={isSwissResident}
onSwissResidentChange={() => setIsSwissResident(!isSwissResident)}
/>
{couponCode ? (
<TextField
helperText={couponHelper}
label="Coupon code"
value={coupon}
onChange={(e) => changeCoupon(e.target.value)}
color="secondary"
error={couponError}
errorMessage="A coupon code is required to proceed"
/>
) : null}
</div>
</div>
<div className={styles.summary}>
Expand All @@ -384,6 +410,7 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
onCurrencySwitch={onCurrencySwitch}
customMessage={customMessage}
loadingPrice={loadingPrice}
isFree={isFree}
/>
<Divider className="w-full" />
<RegisterCheckboxes
Expand All @@ -408,7 +435,8 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
!targetAddress ||
invalidBalance ||
!termsBox ||
emailError
emailError ||
couponError
}
>
{!termsBox
Expand All @@ -417,14 +445,16 @@ const RegisterDiscount: FunctionComponent<RegisterDiscountProps> = ({
? `You don't have enough ${displayedCurrency}`
: emailError
? "Enter a valid Email"
: couponError
? "Enter a valid Coupon"
: "Register my domain"}
</Button>
) : (
<ConnectButton />
)}
</div>
</div>
<img className={styles.image} src="/visuals/register.webp" />
<img className={styles.image} src={banner} />
<TxConfirmationModal
txHash={registerData?.transaction_hash}
isTxModalOpen={isTxModalOpen}
Expand Down
18 changes: 13 additions & 5 deletions components/domains/registerSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type RegisterSummaryProps = {
discountedPrice?: string; // price the user will pay after discount
discountedDuration?: number; // years the user will have the domain for after discount
areArCurrenciesEnabled?: boolean;
isFree?: boolean;
};

const RegisterSummary: FunctionComponent<RegisterSummaryProps> = ({
Expand All @@ -46,6 +47,7 @@ const RegisterSummary: FunctionComponent<RegisterSummaryProps> = ({
discountedPrice,
discountedDuration,
areArCurrenciesEnabled = false,
isFree = false,
}) => {
const [ethUsdPrice, setEthUsdPrice] = useState<string>("0"); // price of 1ETH in USD
const [usdRegistrationPrice, setUsdRegistrationPrice] = useState<string>("0");
Expand Down Expand Up @@ -150,15 +152,21 @@ const RegisterSummary: FunctionComponent<RegisterSummaryProps> = ({
<h4 className={styles.totalDueTitle}>Total due:</h4>
<div className={styles.priceContainer}>
<p className={styles.legend}>{getMessage()}</p>
{loadingPrice ? (
<Skeleton variant="text" width="150px" height="24px" />
{isFree ? (
"Free"
) : (
displayTokenPrice()
<>
{loadingPrice ? (
<Skeleton variant="text" width="150px" height="24px" />
) : (
displayTokenPrice()
)}
<p className={styles.legend}>≈ ${usdRegistrationPrice}</p>
</>
)}
<p className={styles.legend}>≈ ${usdRegistrationPrice}</p>
</div>
</div>
{areArCurrenciesEnabled ? (
{isFree ? null : areArCurrenciesEnabled ? (
<ArCurrencyDropdown
displayedCurrency={displayedCurrency as CurrencyType[]} // as CurrencyType[] is safe here cause we know the value is a CurrencyType[]
onCurrencySwitch={onCurrencySwitch as (type: CurrencyType[]) => void}
Expand Down
62 changes: 62 additions & 0 deletions pages/domain-gift.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { useEffect, useState } from "react";
import type { NextPage } from "next";
import homeStyles from "../styles/Home.module.css";
import DiscountEndScreen from "../components/discount/discountEndScreen";
import DiscountCheckoutScreen from "../components/discount/discountCheckoutScreen";

// Create a new discount in utils to create a new discount campaign
import { domainGift } from "../utils/discounts/domainGift";
import DiscountOfferScreenVariant from "@/components/discount/discountOfferScreenVariant";

const DomainGift: NextPage = () => {
const [searchResult, setSearchResult] = useState<SearchResult | undefined>();
const [screen, setScreen] = useState<number>(1);

useEffect(() => {
const currentDate = new Date();
const timestamp = currentDate.getTime();

if (timestamp >= domainGift.expiry) setScreen(0);
}, []);

function goBack() {
setScreen(screen - 1);
}

return (
<div className={homeStyles.screen}>
{screen === 0 ? (
<DiscountEndScreen
title={`${domainGift.name} discount has ended`}
image={domainGift.image}
/>
) : null}
{screen === 1 ? (
<DiscountOfferScreenVariant
title={domainGift.offer.title}
desc={domainGift.offer.desc}
image={domainGift.offer.image ?? domainGift.image}
setSearchResult={setSearchResult}
setScreen={setScreen}
expiry={domainGift.expiry}
/>
) : null}
{screen === 2 ? (
<DiscountCheckoutScreen
domain={searchResult?.name ?? ""}
duration={domainGift.offer.duration}
discountId={domainGift.offer.discountId}
customMessage={domainGift.offer.customMessage}
price={domainGift.offer.price}
goBack={goBack}
mailGroupId={domainGift.discountMailGroupId}
couponCode={domainGift.offer.couponCode}
couponHelper={domainGift.offer.couponHelper}
banner={domainGift.image}
/>
) : null}
</div>
);
};

export default DomainGift;
Binary file added public/visuals/gift.webp
Binary file not shown.
Loading

0 comments on commit ba22ed4

Please sign in to comment.