Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/259 #274

Merged
merged 2 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion pkgs/frontend/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ import { Container } from "@chakra-ui/react";
import { withEmotionCache } from "@emotion/react";
import { PrivyProvider } from "@privy-io/react-auth";
import {
type ClientLoaderFunctionArgs,
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
data,
useLoaderData,
} from "@remix-run/react";
import { currentChain } from "hooks/useViem";
import { useEffect } from "react";
import { ToastContainer, toast as notify } from "react-toastify";
import toastStyles from "react-toastify/ReactToastify.css?url";
import { getToast } from "remix-toast";
import { goldskyClient } from "utils/apollo";
import { Header } from "./components/Header";
import { SwitchNetwork } from "./components/SwitchNetwork";
Expand Down Expand Up @@ -45,14 +52,33 @@ export const Layout = withEmotionCache((props: LayoutProps, cache) => {
);
});

// Add the toast stylesheet
export const links = () => [{ rel: "stylesheet", href: toastStyles }];
// Implemented from above
export const loader = async ({ request }: ClientLoaderFunctionArgs) => {
const { toast, headers } = await getToast(request);
return data({ toast }, { headers });
};

export default function App() {
const {
data: { toast },
} = useLoaderData<typeof loader>();
// Hook to show the toasts
useEffect(() => {
if (toast) {
// notify on a toast message
notify(toast.message, { type: toast.type });
}
}, [toast]);

return (
<ApolloProvider client={goldskyClient}>
<PrivyProvider
appId={import.meta.env.VITE_PRIVY_APP_ID}
config={{
appearance: {
walletList: ["coinbase_wallet"],
walletList: ["coinbase_wallet", "metamask"],
},
embeddedWallets: {
createOnLogin: "users-without-wallets",
Expand All @@ -77,6 +103,7 @@ export default function App() {
<Header />
<Outlet />
</Container>
<ToastContainer />
</ChakraProvider>
</PrivyProvider>
</ApolloProvider>
Expand Down
222 changes: 115 additions & 107 deletions pkgs/frontend/app/routes/$treeId_.$hatId_.$address_.assistcredit.send.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Box,
Button,
Flex,
Float,
Grid,
Expand All @@ -24,6 +25,7 @@ import { useTreeInfo } from "hooks/useHats";
import { type NameData, TextRecords } from "namestone-sdk";
import { type FC, useCallback, useEffect, useMemo, useState } from "react";
import { FaArrowRight } from "react-icons/fa6";
import { toast } from "react-toastify";
import { ipfs2https } from "utils/ipfs";
import { abbreviateAddress } from "utils/wallet";
import type { Address } from "viem";
Expand Down Expand Up @@ -93,7 +95,9 @@ const AssistCreditSend: FC = () => {
receiver.address as Address,
BigInt(amount),
);
res && navigate(`/${treeId}/${hatId}/${address}`);
console.log(res);
res?.error && toast.error(res.error);
res?.txHash && navigate(`/${treeId}/${hatId}/${address}`);
} catch (error) {
console.error(error);
}
Expand All @@ -110,117 +114,121 @@ const AssistCreditSend: FC = () => {
]);

return (
<Grid
gridTemplateRows={!receiver ? "auto auto auto 1fr" : "auto auto 1fr auto"}
minH="calc(100vh - 100px)"
>
<PageHeader
title={
receiver
? `${receiver.name || `${abbreviateAddress(receiver.address)}に送信`}`
: "アシストクレジット送信"
<>
<Grid
gridTemplateRows={
!receiver ? "auto auto auto 1fr" : "auto auto 1fr auto"
}
backLink={
receiver &&
(() => {
setReceiver(undefined);
setAmount(0);
})
}
/>

<HStack my={2}>
<RoleIcon size="50px" />
<Text>掃除当番(残高: {balanceOfToken?.toLocaleString()})</Text>
</HStack>

{!receiver ? (
<>
<Field label="ユーザー名 or ウォレットアドレスで検索">
<CommonInput
value={searchText}
onChange={(e) => {
setSearchText(e.target.value);
}}
placeholder="ユーザー名 or ウォレットアドレス"
/>
</Field>

<List.Root listStyle="none" my={10} gap={3}>
{users?.flat().map((user, index) => (
<List.Item
key={`${user.name}u`}
onClick={() => setReceiver(user)}
>
<HStack>
minH="calc(100vh - 100px)"
>
<PageHeader
title={
receiver
? `${receiver.name || `${abbreviateAddress(receiver.address)}に送信`}`
: "アシストクレジット送信"
}
backLink={
receiver &&
(() => {
setReceiver(undefined);
setAmount(0);
})
}
/>

<HStack my={2}>
<RoleIcon size="50px" />
<Text>掃除当番(残高: {balanceOfToken?.toLocaleString()})</Text>
</HStack>

{!receiver ? (
<>
<Field label="ユーザー名 or ウォレットアドレスで検索">
<CommonInput
value={searchText}
onChange={(e) => {
setSearchText(e.target.value);
}}
placeholder="ユーザー名 or ウォレットアドレス"
/>
</Field>

<List.Root listStyle="none" my={10} gap={3}>
{users?.flat().map((user, index) => (
<List.Item
key={`${user.name}u`}
onClick={() => setReceiver(user)}
>
<HStack>
<UserIcon
userImageUrl={ipfs2https(user.text_records?.avatar)}
size={10}
/>
<Text lineBreak="anywhere">
{user.name
? `${user.name} (${user.address.slice(0, 6)}...${user.address.slice(-4)})`
: user.address}
</Text>
</HStack>
</List.Item>
))}
</List.Root>
</>
) : (
<>
<Field label="送信量" alignItems="center" justifyContent="center">
<Input
p={2}
pb={4}
fontSize="60px"
size="2xl"
border="none"
borderBottom="2px solid"
borderRadius="0"
w="auto"
type="number"
textAlign="center"
min={0}
max={9999}
style={{
WebkitAppearance: "none",
}}
value={amount}
onChange={(e) => setAmount(Number(e.target.value))}
/>
</Field>

<Flex width="100%" flexDirection="column" alignItems="center">
<HStack columnGap={3} mb={4}>
<Box textAlign="center">
<UserIcon
size={10}
userImageUrl={ipfs2https(me.identity?.text_records?.avatar)}
/>
<Text fontSize="xs">{me.identity?.name}</Text>
</Box>
<VStack textAlign="center">
<Text>{amount}</Text>
<FaArrowRight size="20px" />
</VStack>
<Box>
<UserIcon
userImageUrl={ipfs2https(user.text_records?.avatar)}
size={10}
userImageUrl={ipfs2https(receiver.text_records?.avatar)}
/>
<Text lineBreak="anywhere">
{user.name
? `${user.name} (${user.address.slice(0, 6)}...${user.address.slice(-4)})`
: user.address}
<Text fontSize="xs">
{receiver.name || abbreviateAddress(receiver.address)}
</Text>
</HStack>
</List.Item>
))}
</List.Root>
</>
) : (
<>
<Field label="送信量" alignItems="center" justifyContent="center">
<Input
p={2}
pb={4}
fontSize="60px"
size="2xl"
border="none"
borderBottom="2px solid"
borderRadius="0"
w="auto"
type="number"
textAlign="center"
min={0}
max={9999}
style={{
WebkitAppearance: "none",
}}
value={amount}
onChange={(e) => setAmount(Number(e.target.value))}
/>
</Field>

<Flex width="100%" flexDirection="column" alignItems="center">
<HStack columnGap={3} mb={4}>
<Box textAlign="center">
<UserIcon
size={10}
userImageUrl={ipfs2https(me.identity?.text_records?.avatar)}
/>
<Text fontSize="xs">{me.identity?.name}</Text>
</Box>
<VStack textAlign="center">
<Text>{amount}</Text>
<FaArrowRight size="20px" />
</VStack>
<Box>
<UserIcon
size={10}
userImageUrl={ipfs2https(receiver.text_records?.avatar)}
/>
<Text fontSize="xs">
{receiver.name || abbreviateAddress(receiver.address)}
</Text>
</Box>
</HStack>
<BasicButton loading={isLoading} onClick={send} mb={5}>
送信
</BasicButton>
</Flex>
</>
)}
</Grid>
</Box>
</HStack>
<BasicButton loading={isLoading} onClick={send} mb={5}>
送信
</BasicButton>
</Flex>
</>
)}
</Grid>
</>
);
};

Expand Down
11 changes: 6 additions & 5 deletions pkgs/frontend/hooks/useFractionToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,15 +465,16 @@ export const useTransferFractionToken = (hatId: bigint, wearer: Address) => {
setIsLoading(true);

let txHash: `0x${string}` | undefined = undefined;
let error: string | undefined = undefined;
if (initialized) {
try {
txHash = await wallet.writeContract({
...fractionTokenBaseConfig,
functionName: "safeTransferFrom",
args: [wallet.account.address, to, tokenId, amount, "0x"],
});
} catch (_) {
setIsLoading(false);
} catch {
error = "アシストクレジットの送信に失敗しました";
} finally {
setIsLoading(false);
}
Expand All @@ -499,18 +500,18 @@ export const useTransferFractionToken = (hatId: bigint, wearer: Address) => {
});
} catch (error) {
console.error(error);
setIsLoading(false);
} finally {
await publicClient.waitForTransactionReceipt({
hash: txHash ?? "0x",
});
setIsLoading(false);
}
} else {
console.error("FractionToken is not initialized");
setIsLoading(false);
error = "この役割についてあなたはアシストクレジットの送信ができません";
}

return txHash;
return { txHash, error };
},
[wallet, initialized, tokenId, hatId, wearer],
);
Expand Down
2 changes: 2 additions & 0 deletions pkgs/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-icons": "^5.4.0",
"react-toastify": "^11.0.3",
"remix-toast": "1.2.2",
"viem": "^2.21.51"
},
"devDependencies": {
Expand Down
Loading
Loading