Skip to content

Commit

Permalink
Merge pull request #229 from hackdays-io/issue/190
Browse files Browse the repository at this point in the history
Issue/190
  • Loading branch information
yu23ki14 authored Dec 29, 2024
2 parents 3904bcf + 7feff77 commit 2ea2ca0
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 164 deletions.
1 change: 0 additions & 1 deletion pkgs/frontend/app/components/common/CommonButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Button, ButtonProps } from "~/components/ui/button";
interface CommonButtonProps extends Omit<ButtonProps, "width"> {
children: React.ReactNode;
width?: "full" | number;
size?: "sm" | "md" | "lg";
backgroundColor?: string;
color?: string;
}
Expand Down
52 changes: 52 additions & 0 deletions pkgs/frontend/app/components/splits/SplitRecipientsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Box, Flex, Text } from "@chakra-ui/react";
import { useNamesByAddresses } from "hooks/useENS";
import { FC, useMemo } from "react";
import { UserIcon } from "../icon/UserIcon";
import { ipfs2https } from "utils/ipfs";
import { abbreviateAddress } from "utils/wallet";

interface SplitRecipientsListProps {
recipients: { address: string; percentAllocation: number }[];
}

export const SplitRecipientsList: FC<SplitRecipientsListProps> = ({
recipients,
}) => {
const addresses = useMemo(() => {
return recipients.map((r) => r.address);
}, [recipients]);
const { names } = useNamesByAddresses(addresses);

const totalAllocation = useMemo(() => {
return recipients.reduce((acc, r) => acc + r.percentAllocation, 0);
}, [recipients]);

return (
<>
{recipients.map((recipient) => {
const name = names.find(
(name) => name[0]?.address === recipient.address
)?.[0];
return (
<Flex key={recipient.address} my={2} alignItems="center" gap={2}>
<UserIcon
size="40px"
userImageUrl={ipfs2https(name?.text_records?.avatar)}
/>
<Box flexGrow={1}>
<Text textStyle="sm">{name?.name}</Text>
<Text textStyle="sm">
{abbreviateAddress(name?.address || "")}
</Text>
</Box>
{(
(Number(recipient.percentAllocation) / totalAllocation) *
100
).toFixed(2)}{" "}
%
</Flex>
);
})}
</>
);
};
210 changes: 137 additions & 73 deletions pkgs/frontend/app/routes/$treeId_.splits._index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,49 @@
import { type MouseEvent } from "react";
import { Box, Collapsible, Flex, Text } from "@chakra-ui/react";
import { useParams } from "@remix-run/react";
import { useTreeInfo } from "hooks/useHats";
import { useEffect, useMemo, type MouseEvent } from "react";
import { Box, Collapsible, Flex, Text, VStack } from "@chakra-ui/react";
import { Link, useParams } from "@remix-run/react";
import { FC, useCallback, useState } from "react";
import { CommonButton } from "~/components/common/CommonButton";
import { FaAngleDown, FaRegCopy } from "react-icons/fa6";
import { UserIcon } from "~/components/icon/UserIcon";
import { useCopyToClipboard } from "hooks/useCopyToClipboard";
import { useGetWorkspace } from "hooks/useWorkspace";
import { useSplitsCreatorRelatedSplits } from "hooks/useSplitsCreator";
import { Address } from "viem";
import { Split } from "@0xsplits/splits-sdk";
import { abbreviateAddress } from "utils/wallet";
import { currentChain, publicClient } from "hooks/useViem";
import dayjs from "dayjs";
import { SplitRecipientsList } from "~/components/splits/SplitRecipientsList";

interface SplitInfoItemProps {
split: Split;
}

const SplitInfoItem: FC<SplitInfoItemProps> = ({ split }) => {
const [createdTime, setCreatedTime] = useState<string>();

const consolidatedRecipients = useMemo(() => {
const consolidated = split.recipients.reduce(
(acc, recipient) => {
const address = recipient.recipient.address;
acc[address] =
(acc[address] || 0) + Number(recipient.percentAllocation);
return acc;
},
{} as Record<string, number>
);

return Object.entries(consolidated).map(([address, percentAllocation]) => ({
address,
percentAllocation,
}));
}, [split.recipients]);

const SplitInfoItem = () => {
const dummyFromAddress = "0xabc89dsakdfasdfasdd123sdafsdfasdf";
const [open, setOpen] = useState(false);
const onOpen = useCallback(() => {
setOpen(true);
}, [setOpen]);

const { copyToClipboardAction } = useCopyToClipboard(dummyFromAddress);
const { copyToClipboardAction } = useCopyToClipboard(split.address);

const onClickCopyButton = useCallback(
(event: MouseEvent<HTMLButtonElement>) => {
Expand All @@ -25,88 +53,124 @@ const SplitInfoItem = () => {
[copyToClipboardAction]
);

const dummyRatioBreakdown = [
{ name: "Ryoma", address: "0x12344sdfasdfadfaweifsd", ratio: 0.2 },
{ name: "Taro", address: "0x12344sdfasdfadfaweifsd", ratio: 0.8 },
];
useEffect(() => {
const fetch = async () => {
const data = await publicClient.getBlock({
blockNumber: BigInt(split.createdBlock),
});

setCreatedTime(
dayjs(Number(data.timestamp) * 1000).format("YYYY/MM/DD HH:mm:ss")
);
};
fetch();
}, [split]);

return (
<Collapsible.Root disabled={open} onOpenChange={onOpen}>
<Collapsible.Trigger w="full" textAlign={"start"} cursor="pointer">
<Flex mb={2}>
<Text as="span" textStyle="xs">
Optimism
</Text>
</Flex>
<Text textStyle="md">2024Q3_Rewards</Text>
<Text textStyle="sm">Created at 2024/7/11</Text>
<Flex mt={4} placeItems="center">
<Text textStyle="sm" flexGrow={1}>
{dummyFromAddress}
</Text>
<CommonButton
color="#333"
background="transparent"
w="auto"
h="auto"
p="4px"
minW="unset"
onClick={onClickCopyButton}
>
<FaRegCopy
style={{ width: "16px", height: "16px", objectFit: "cover" }}
/>
</CommonButton>
</Flex>
{open || (
<CommonButton color="#333" background="transparent" w="full" h="auto">
<FaAngleDown
style={{ width: "16px", height: "16px", objectFit: "cover" }}
/>
</CommonButton>
)}
</Collapsible.Trigger>
<Collapsible.Content>
<Box
mx={2}
my={4}
borderTop="1px solid #868e96"
role="presentation"
></Box>
{dummyRatioBreakdown.map((breakdown) => (
<Flex key={breakdown.name} my={2} alignItems="center" gap={2}>
<UserIcon size="40px" />
<Box flexGrow={1}>
<Text textStyle="sm">{breakdown.name}</Text>
<Text textStyle="sm">{breakdown.address}</Text>
</Box>
{breakdown.ratio * 100} %
<Box
w="100%"
px={4}
py={4}
borderRadius={8}
border="1px solid #333"
bg="white"
>
<Collapsible.Root disabled={open} onOpenChange={onOpen}>
<Collapsible.Trigger w="full" textAlign={"start"} cursor="pointer">
<Flex alignItems="center" justifyContent="space-between">
<Text textStyle="md">{abbreviateAddress(split.address)}</Text>
<Link
target="_blank"
to={`https://app.splits.org/accounts/${split.address}/?chainId=${currentChain.id}`}
>
<CommonButton size="xs" w="100" bgColor="blue.400">
詳細を確認
</CommonButton>
</Link>
</Flex>
))}
</Collapsible.Content>
</Collapsible.Root>
<Text textStyle="sm">Created at {createdTime}</Text>
<Flex mt={4} placeItems="center">
<Text textStyle="sm" flexGrow={1}>
{split.address}
</Text>
<CommonButton
color="#333"
background="transparent"
w="auto"
h="auto"
p="4px"
minW="unset"
onClick={onClickCopyButton}
>
<FaRegCopy
style={{ width: "16px", height: "16px", objectFit: "cover" }}
/>
</CommonButton>
</Flex>
{open || (
<CommonButton
color="#333"
background="transparent"
w="full"
h="auto"
>
<FaAngleDown
style={{ width: "16px", height: "16px", objectFit: "cover" }}
/>
</CommonButton>
)}
</Collapsible.Trigger>
<Collapsible.Content>
<Box
mx={2}
my={4}
borderTop="1px solid #868e96"
role="presentation"
></Box>
<SplitRecipientsList recipients={consolidatedRecipients} />
</Collapsible.Content>
</Collapsible.Root>
</Box>
);
};

const SplitsIndex: FC = () => {
const { treeId } = useParams();

treeId;
// const tree = useTreeInfo(Number(treeId));
const { data } = useGetWorkspace(treeId);

const splitCreatorAddress = useMemo(() => {
return data?.workspace?.splitCreator as Address;
}, [data]);

const { splits, isLoading } =
useSplitsCreatorRelatedSplits(splitCreatorAddress);

return (
<Box w="100%">
<Flex my={4} placeItems="center">
<Text fontSize="lg" flexGrow={1}>
Splits
</Text>
<CommonButton w={"auto"} size="sm">
Create New
</CommonButton>
<Link to={`/${treeId}/splits/new`}>
<CommonButton w={"auto"} size="sm">
Create New
</CommonButton>
</Link>
</Flex>
<Box px={4} py={4} borderRadius={8} border="1px solid #333">
<SplitInfoItem />
</Box>

{isLoading ? (
<></>
) : (
<VStack gap={3} mb={10}>
{splits
.slice()
.sort((a, b) => Number(b.createdBlock) - Number(a.createdBlock))
.map((split) => (
<SplitInfoItem key={split.address} split={split} />
))}
</VStack>
)}
</Box>
);
};
Expand Down
Loading

0 comments on commit 2ea2ca0

Please sign in to comment.