Skip to content

Commit f349585

Browse files
committed
repsonsive & multi-claim in drop
1 parent 77b63cd commit f349585

File tree

8 files changed

+178
-135
lines changed

8 files changed

+178
-135
lines changed

dev-iframe.html

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,38 @@
11
<!DOCTYPE html>
22
<html>
3-
<head> </head>
4-
<body style="font-family: sans-serif">
3+
<head>
4+
<meta name="viewport" content="width=device-width, initial-scale=1" />
5+
</head>
6+
<body style="font-family: sans-serif; background: #333;">
57
<div
68
style="
79
display: flex;
810
flex-direction: column;
911
gap: 20px;
1012
width: 100%;
11-
height: 100%;
12-
margin: 20px;
13+
height: 100%;
1314
align-items: center;
1415
"
1516
>
16-
<div style="gap: 5px; width: 600px;">
17+
<div style="gap: 5px; width: 600px; max-width: 100%;">
1718
<h2>Preview 600x600</h2>
1819
<iframe
19-
src="http://localhost:1234/?contract=0xe525ea4532903916782c7644c4a3D7d3020bf308&chainId=137"
20+
src="http://localhost:1234/?contract=0xF1205F654d52492909175E4564D80d4d83176d88&chainId=137"
2021
width="600px"
2122
height="600px"
23+
style="max-width: 100%;"
2224
frameborder="0"
2325
></iframe>
2426
</div>
25-
<div style="gap: 5px; width: 600px;">
27+
<div style="gap: 5px; width: 600px; max-width: 100%;">
2628
<h2>Properties</h2>
2729
<div>
2830
<div>
2931
<label style="gap: 5px;">
3032
<span>Contract:</span>
3133
<input
3234
type="text"
33-
value="0xe525ea4532903916782c7644c4a3D7d3020bf308"
35+
value="0xF1205F654d52492909175E4564D80d4d83176d88"
3436
style="width: 100%"
3537
/>
3638
</label>

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"dependencies": {
4141
"@3rdweb/hooks": "^1.3.3",
4242
"@3rdweb/react": "^1.3.1",
43-
"@3rdweb/sdk": "^1.24.0",
43+
"@3rdweb/sdk": "^1.27.0",
4444
"@chakra-ui/react": "^1.7.2",
4545
"@emotion/react": "^11",
4646
"@emotion/styled": "^11",

src/shared/nft-carousel.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const NftCarousel: React.FC<NftCarouselProps> = ({ metadata }) => {
4848
borderRadius="full"
4949
variant="outline"
5050
/>
51-
<AspectRatio ratio={1} w="400px">
51+
<AspectRatio ratio={1} w="69vw" maxW="400px">
5252
<Flex py={4} position="relative" overflow="hidden">
5353
{metadata.map((nft, idx) => (
5454
<Stack

src/shared/svg/drop.tsx

+7-7
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ export const DropSvg: React.FC = () => {
2828
y2="172.5"
2929
gradientUnits="userSpaceOnUse"
3030
>
31-
<stop stop-color="#E312A7" />
32-
<stop offset="0.424395" stop-color="#410AB6" />
33-
<stop offset="1" stop-color="#0A97B6" />
31+
<stop stopColor="#E312A7" />
32+
<stop offset="0.424395" stopColor="#410AB6" />
33+
<stop offset="1" stopColor="#0A97B6" />
3434
</linearGradient>
3535
<linearGradient
3636
id="paint1_linear_655_1218"
@@ -40,10 +40,10 @@ export const DropSvg: React.FC = () => {
4040
y2="9.1327"
4141
gradientUnits="userSpaceOnUse"
4242
>
43-
<stop stop-color="#00C2FF" />
44-
<stop offset="0.0001" stop-color="#00C2FF" />
45-
<stop offset="1" stop-color="#00C2FF" stop-opacity="0" />
46-
<stop offset="1" stop-color="#00C2FF" stop-opacity="0.7" />
43+
<stop stopColor="#00C2FF" />
44+
<stop offset="0.0001" stopColor="#00C2FF" />
45+
<stop offset="1" stopColor="#00C2FF" stopOpacity="0" />
46+
<stop offset="1" stopColor="#00C2FF" stopOpacity="0.7" />
4747
</linearGradient>
4848
</defs>
4949
</svg>

src/shared/theme/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const chakraTheme: Theme = extendTheme(
3535
Text,
3636
Button: {
3737
baseStyle: {
38-
borderRadius: "full",
38+
borderRadius: "md",
3939
},
4040
},
4141
Input: {
@@ -67,7 +67,7 @@ const chakraTheme: Theme = extendTheme(
6767
page: "1170px",
6868
},
6969
},
70-
}
70+
},
7171
// withDefaultColorScheme({ colorScheme: "primary" }),
7272
) as Theme;
7373

src/widgets/bundledrop.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ const InventoryPage: React.FC<ModuleInProps> = ({ module }) => {
377377
);
378378
}
379379

380-
if (!ownedDropsMetadata) {
380+
if (!ownedDropsMetadata?.length) {
381381
return (
382382
<Center w="100%" h="100%">
383383
<Stack direction="row" align="center">
@@ -495,7 +495,7 @@ const DropWidget: React.FC<DropWidgetProps> = ({
495495
}, [owned.data, isNotSoldOut]);
496496

497497
return (
498-
<AspectRatio ratio={1} w="600px">
498+
<AspectRatio ratio={{ base: 1 / 1.5, sm: 1 }} w="100%">
499499
<Flex
500500
flexDir="column"
501501
borderRadius="1rem"

src/widgets/drop.tsx

+83-28
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import {
1212
Heading,
1313
Icon,
1414
Image,
15+
NumberDecrementStepper,
16+
NumberIncrementStepper,
17+
NumberInput,
18+
NumberInputField,
19+
NumberInputStepper,
1520
Spinner,
1621
Stack,
1722
Tab,
@@ -138,6 +143,8 @@ const ConnectWalletButton: React.FC = () => (
138143
const ClaimButton: React.FC<ClaimPageProps> = ({ module, sdk, chainId }) => {
139144
const { address } = useWeb3();
140145

146+
const [quantity, setQuantity] = useState(1);
147+
141148
const [claimSuccess, setClaimSuccess] = useState(false);
142149

143150
const claimed = useQuery(
@@ -152,20 +159,39 @@ const ClaimButton: React.FC<ClaimPageProps> = ({ module, sdk, chainId }) => {
152159
{ enabled: !!module },
153160
);
154161

162+
const unclaimed = useQuery(
163+
["numbers", "available"],
164+
() => module?.totalUnclaimedSupply(),
165+
{ enabled: !!module },
166+
);
167+
155168
const claimCondition = useQuery(
156169
["claimcondition"],
157170
() => module?.getActiveClaimCondition(),
158171
{ enabled: !!module },
159172
);
160173

161-
const priceToMint = BigNumber.from(claimCondition?.data?.price || 0);
174+
const priceToMint = BigNumber.from(
175+
claimCondition?.data?.pricePerToken || 0,
176+
).mul(quantity);
162177
const currency = claimCondition?.data?.currency;
178+
const quantityLimit = claimCondition?.data?.quantityLimitPerTransaction || 1;
179+
180+
const quantityLimitBigNumber = useMemo(() => {
181+
const bn = BigNumber.from(quantityLimit);
182+
const unclaimedBn = BigNumber.from(unclaimed.data || 0);
183+
184+
if (unclaimedBn.lt(bn)) {
185+
return unclaimedBn;
186+
}
187+
return bn;
188+
}, [quantityLimit]);
163189

164190
const tokenModule = useMemo(() => {
165191
if (!currency || !sdk) {
166192
return undefined;
167193
}
168-
return sdk.getCurrencyModule(currency);
194+
return sdk.getTokenModule(currency);
169195
}, [currency, sdk]);
170196

171197
const formatedPrice = useFormatedValue(priceToMint, tokenModule, chainId);
@@ -184,10 +210,10 @@ const ClaimButton: React.FC<ClaimPageProps> = ({ module, sdk, chainId }) => {
184210
if (!address || !module) {
185211
throw new Error("No address or module");
186212
}
187-
return module.claim(1);
213+
return module.claim(quantity);
188214
},
189215
{
190-
onSuccess: () => queryClient.invalidateQueries("numbers"),
216+
onSuccess: () => queryClient.invalidateQueries(),
191217
onError: (err) => {
192218
const anyErr = err as any;
193219
let message = "";
@@ -214,31 +240,60 @@ const ClaimButton: React.FC<ClaimPageProps> = ({ module, sdk, chainId }) => {
214240

215241
const isLoading = totalAvailable.isLoading || claimed.isLoading;
216242

217-
const canClaim = isNotSoldOut && address;
243+
const canClaim = !!isNotSoldOut && !!address;
244+
245+
const showQuantityInput =
246+
canClaim &&
247+
quantityLimitBigNumber.gt(1) &&
248+
quantityLimitBigNumber.lte(1000);
218249

219250
return (
220251
<Stack spacing={4} align="center" w="100%">
221252
{address ? (
222-
<Button
223-
isLoading={isLoading || claimMutation.isLoading}
224-
isDisabled={!canClaim}
225-
leftIcon={<IoDiamondOutline />}
226-
onClick={() => claimMutation.mutate()}
227-
isFullWidth
228-
colorScheme="blue"
229-
>
230-
{!isNotSoldOut
231-
? "Sold out"
232-
: canClaim
233-
? `Mint${
234-
priceToMint.eq(0)
235-
? " (Free)"
236-
: formatedPrice
237-
? ` (${formatedPrice})`
238-
: ""
239-
}`
240-
: "Minting Unavailable"}
241-
</Button>
253+
<Flex w="100%" direction={{ base: "column", md: "row" }} gap={2}>
254+
{showQuantityInput && (
255+
<NumberInput
256+
inputMode="numeric"
257+
value={quantity}
258+
onChange={(stringValue, value) => {
259+
if (stringValue === "") {
260+
setQuantity(0);
261+
} else {
262+
setQuantity(value);
263+
}
264+
}}
265+
min={1}
266+
max={quantityLimitBigNumber.toNumber()}
267+
maxW={{ base: "100%", md: "100px" }}
268+
>
269+
<NumberInputField />
270+
<NumberInputStepper>
271+
<NumberIncrementStepper />
272+
<NumberDecrementStepper />
273+
</NumberInputStepper>
274+
</NumberInput>
275+
)}
276+
<Button
277+
isLoading={isLoading || claimMutation.isLoading}
278+
isDisabled={!canClaim}
279+
leftIcon={<IoDiamondOutline />}
280+
onClick={() => claimMutation.mutate()}
281+
isFullWidth
282+
colorScheme="blue"
283+
>
284+
{!isNotSoldOut
285+
? "Sold out"
286+
: canClaim
287+
? `Mint${showQuantityInput ? ` ${quantity}` : ""}${
288+
priceToMint.eq(0)
289+
? " (Free)"
290+
: formatedPrice
291+
? ` (${formatedPrice})`
292+
: ""
293+
}`
294+
: "Minting Unavailable"}
295+
</Button>
296+
</Flex>
242297
) : (
243298
<ConnectWalletButton />
244299
)}
@@ -250,7 +305,7 @@ const ClaimButton: React.FC<ClaimPageProps> = ({ module, sdk, chainId }) => {
250305
};
251306

252307
const ClaimPage: React.FC<ClaimPageProps> = ({ module, sdk, chainId }) => {
253-
const { data, isLoading, error } = useQuery(
308+
const { data, isLoading } = useQuery(
254309
"module_metadata",
255310
() => module?.getMetadata(),
256311
{ enabled: !!module },
@@ -339,7 +394,7 @@ const InventoryPage: React.FC<ModuleInProps> = ({ module }) => {
339394
);
340395
}
341396

342-
if (!ownedDropsMetadata) {
397+
if (!ownedDropsMetadata?.length) {
343398
return (
344399
<Center w="100%" h="100%">
345400
<Stack direction="row" align="center">
@@ -457,7 +512,7 @@ const DropWidget: React.FC<DropWidgetProps> = ({
457512
}, [owned.data, isSoldOut]);
458513

459514
return (
460-
<AspectRatio ratio={1} w="600px">
515+
<AspectRatio ratio={{ base: 1 / 1.5, sm: 1 }} w="100%">
461516
<Flex
462517
flexDir="column"
463518
borderRadius="1rem"

0 commit comments

Comments
 (0)