Skip to content

Commit

Permalink
Merge pull request #4 from hypercerts-org/feature/store-polish
Browse files Browse the repository at this point in the history
store polish
  • Loading branch information
Jipperism authored Sep 9, 2023
2 parents 6d0609d + 1c89b9e commit 9a47d8a
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 121 deletions.
124 changes: 66 additions & 58 deletions components/ftc-board.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { Center, Flex, Spinner } from "@chakra-ui/react";
import { Hyperboard } from "@/components/hyperboard";
import * as React from "react";
import Head from "next/head";

export const FtcBoard = ({ registryId }: { registryId: string }) => {
const containerRef = useRef<HTMLDivElement | null>(null);
Expand All @@ -16,9 +17,11 @@ export const FtcBoard = ({ registryId }: { registryId: string }) => {
"sponsors" | "speakers" | "all"
>("all");

const { data, isLoading } = useRegistryContents(registryId);
const { data: results, isLoading } = useRegistryContents(registryId);

const sponsors = Object.values(data || {}).filter(
const data = results?.content || {};

const sponsors = Object.values(data).filter(
(x) =>
x.displayData?.type === "person" || x.displayData?.type === "company",
);
Expand Down Expand Up @@ -49,61 +52,66 @@ export const FtcBoard = ({ registryId }: { registryId: string }) => {
}, [displayBoards]);

return (
<Center width={"100%"} paddingX={"80px"}>
<Flex
width={"100%"}
ref={containerRef}
overflow={"hidden"}
backgroundColor={"black"}
aspectRatio={"16 / 9"}
>
{isLoading ? (
<Center paddingY={"80px"} width={"100%"}>
<Spinner />
</Center>
) : (
<>
<Flex
width={sponsorWidth}
minWidth={sponsorWidth}
transition={"all 0.5s ease-out"}
overflow={"hidden"}
>
<Hyperboard
onClickLabel={() =>
setDisplayBoards((val) =>
val === "all" ? "sponsors" : "all",
)
}
label="Sponsors"
height={height}
data={sponsors.map((x) =>
registryContentItemToHyperboardEntry(x),
)}
/>
</Flex>
<Flex
width={speakerWidth}
minWidth={speakerWidth}
transition={"all 0.5s ease-out"}
overflow={"hidden"}
>
<Hyperboard
onClickLabel={() =>
setDisplayBoards((val) =>
val === "all" ? "speakers" : "all",
)
}
label="Speakers"
height={height}
data={speakers.map((x) =>
registryContentItemToHyperboardEntry(x),
)}
/>
</Flex>
</>
)}
</Flex>
</Center>
<>
<Head>
<title>Hyperboards - {results?.registry.name || "Loading"}</title>
</Head>
<Center width={"100%"} paddingX={"80px"}>
<Flex
width={"100%"}
ref={containerRef}
overflow={"hidden"}
backgroundColor={"black"}
aspectRatio={"16 / 9"}
>
{isLoading ? (
<Center paddingY={"80px"} width={"100%"}>
<Spinner />
</Center>
) : (
<>
<Flex
width={sponsorWidth}
minWidth={sponsorWidth}
transition={"all 0.5s ease-out"}
overflow={"hidden"}
>
<Hyperboard
onClickLabel={() =>
setDisplayBoards((val) =>
val === "all" ? "sponsors" : "all",
)
}
label="Sponsors"
height={height}
data={sponsors.map((x) =>
registryContentItemToHyperboardEntry(x),
)}
/>
</Flex>
<Flex
width={speakerWidth}
minWidth={speakerWidth}
transition={"all 0.5s ease-out"}
overflow={"hidden"}
>
<Hyperboard
onClickLabel={() =>
setDisplayBoards((val) =>
val === "all" ? "speakers" : "all",
)
}
label="Speakers"
height={height}
data={speakers.map((x) =>
registryContentItemToHyperboardEntry(x),
)}
/>
</Flex>
</>
)}
</Flex>
</Center>
</>
);
};
125 changes: 89 additions & 36 deletions components/store/buy-hypercert-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,36 @@ import {
Box,
Button,
Flex,
Heading,
Image,
Input,
InputGroup,
InputRightAddon,
Slider,
SliderFilledTrack,
SliderThumb,
SliderTrack,
Text,
Tooltip,
useToast,
VStack,
} from "@chakra-ui/react";
import { useState } from "react";
import { HypercertMetadata } from "@hypercerts-org/sdk";
import { Offer, OfferFromContract } from "@/hooks/store";
import { useBuyFraction } from "@/hooks/useBuyFraction";
import { formatEther } from "viem";

export const BuyHypercertTile = ({
metaData,
offer,
offerFromContract,
totalUnits,
}: {
metaData: HypercertMetadata;
offer?: Offer;
offerFromContract?: OfferFromContract;
totalUnits: number;
}) => {
const toast = useToast();
const buyFraction = useBuyFraction();
Expand Down Expand Up @@ -56,42 +64,87 @@ export const BuyHypercertTile = ({
);
const [showTooltip, setShowTooltip] = useState(false);

return (
<Flex flexDirection={"column"}>
<Image src={metaData?.image} alt={"Hypercert display image"} />
<Text>{metaData.name}</Text>
{!offer ? (
const percentageAvailable =
(Number(offerFromContract?.unitsAvailable.toString()) / totalUnits) * 100;

const totalPrice = offerFromContract
? formatEther(
sliderValue * offerFromContract?.acceptedTokens[0].minimumAmountPerUnit,
)
: "unknown";

if (!offer || !offerFromContract) {
return (
<Flex flexDirection={"column"}>
<Image src={metaData?.image} alt={"Hypercert display image"} />
<Text>{metaData.name}</Text>
<div>Offer unknown</div>
) : (
<>
<Box minHeight={"30px"}>
<Slider
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
min={Number(offer.minUnitsPerTrade.toString())}
max={Number(offer.unitsAvailable.toString())}
value={Number(sliderValue.toString())}
aria-label="buy fractions slider"
onChange={(v) => setSliderValue(BigInt(v))}
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<Tooltip
hasArrow
bg="teal.500"
color="white"
placement="top"
isOpen={showTooltip}
label={`${sliderValue} units`}
>
<SliderThumb />
</Tooltip>
</Slider>
</Box>
<Button onClick={handleWrite}>BUY</Button>
</>
)}
</Flex>
</Flex>
);
}

const minValue = Number(offer.minUnitsPerTrade.toString());
const maxValue = Number(offerFromContract.unitsAvailable.toString());

const currentPercentageValue =
(Number(sliderValue.toString()) / totalUnits) * 100;

return (
<VStack alignItems={"flex-start"} flexDirection={"column"} width={"100%"}>
<Image
src={metaData?.image}
alt={"Hypercert display image"}
minWidth={"100%"}
height={"auto"}
mb={4}
/>
<Heading fontFamily={"Switzer"} size={"md"}>
{metaData.name}
</Heading>
<InputGroup size="sm">
<Input
min={0}
max={percentageAvailable}
value={currentPercentageValue}
type={"number"}
placeholder={`${percentageAvailable}% available`}
readOnly
/>
<InputRightAddon>%</InputRightAddon>
</InputGroup>
<Box minHeight={"30px"} width={"100%"}>
<Slider
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
min={minValue}
max={maxValue}
value={Number(sliderValue.toString())}
aria-label="buy fractions slider"
onChange={(v) => {
setSliderValue(BigInt(v));
}}
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<Tooltip
hasArrow
bg="teal.500"
color="white"
placement="top"
isOpen={showTooltip}
label={`${currentPercentageValue.toFixed(
2,
)}% (${sliderValue} units)`}
>
<SliderThumb />
</Tooltip>
</Slider>
</Box>
<Text>Price: {totalPrice} ETH</Text>
<Button onClick={handleWrite} width={"100%"}>
BUY
</Button>
</VStack>
);
};
4 changes: 4 additions & 0 deletions components/store/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { GridItem, SimpleGrid } from "@chakra-ui/react";
import { BuyHypercertTile } from "@/components/store/buy-hypercert-tile";
import { useStoreHypercerts } from "@/hooks/store";
import _ from "lodash";

export const Store = () => {
const { data } = useStoreHypercerts();
Expand All @@ -15,6 +16,9 @@ export const Store = () => {
metaData={x.metadata}
offer={x.offer}
offerFromContract={x.offerFromContract}
totalUnits={_.sum(
x.fractions.map((fraction) => parseInt(fraction.units)),
)}
/>
</GridItem>
))}
Expand Down
8 changes: 7 additions & 1 deletion hooks/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { client } from "@/lib/hypercert-client";

interface RegistryWithClaims {
id: string;
name: string;
"hyperboard-claims": {
id: string;
hypercert_id: string;
Expand Down Expand Up @@ -66,7 +67,7 @@ export const useRegistryContents = (registryId: string) => {
);

// Group by owner, merge with display data and calculate total value of all fractions per owner
return _.chain(fractions)
const content = _.chain(fractions)
.groupBy((fraction) => fraction.owner)
.mapValues((fractionsPerOwner, owner) => {
return {
Expand All @@ -78,6 +79,11 @@ export const useRegistryContents = (registryId: string) => {
};
})
.value();

return {
registry: registry.data,
content,
};
});
});
};
Expand Down
1 change: 1 addition & 0 deletions hooks/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export const useStoreHypercerts = () => {
return supabase
.from("hypercerts-store")
.select("*")
.neq("hidden", true)
.then(async (res) => {
if (!res.data) {
return;
Expand Down
Loading

0 comments on commit 9a47d8a

Please sign in to comment.