Skip to content

Commit

Permalink
finish with edit wallet set dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysu committed Jan 9, 2025
1 parent 11605ad commit 019f0b0
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 71 deletions.
48 changes: 0 additions & 48 deletions .github/copilot-instructions.md

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
.vscode
tmp
.history
.github/copilot-instructions.md
8 changes: 4 additions & 4 deletions packages/circle-demo-webapp/app/hooks/useTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ interface UseTransactionsResult {
refetch: () => Promise<void>;
}

const url = '/api/listTransactions';

export const useTransactions = (walletId: string): UseTransactionsResult => {
const { data, error, isLoading } = useSWR<Transaction[], Error>(
`/api/listTransactions/${walletId}`,
);
const { data, error, isLoading } = useSWR<Transaction[], Error>(`${url}/${walletId}`);

const refetch = () => mutate(`/api/listTransactions/${walletId}`);
const refetch = () => mutate(`${url}/${walletId}`);

return {
data,
Expand Down
41 changes: 41 additions & 0 deletions packages/circle-demo-webapp/app/hooks/useUpdateWalletSet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useState } from 'react';

interface UpdateWalletSetArgs {
id: string;
name: string;
}

interface UseUpdateWalletSetResult {
error: Error | undefined;
isLoading: boolean;
updateWalletSet: (args: UpdateWalletSetArgs) => Promise<void>;
}

export const useUpdateWalletSet = (): UseUpdateWalletSetResult => {
const [error, setError] = useState<Error | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(false);

const updateWalletSet = async ({ id, name }: UpdateWalletSetArgs) => {
setIsLoading(true);
setError(undefined);
try {
await fetch('/api/updateWalletSet', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id, name }),
});
} catch (err) {
setError(err as Error);
} finally {
setIsLoading(false);
}
};

return {
error,
isLoading,
updateWalletSet,
};
};
3 changes: 1 addition & 2 deletions packages/circle-demo-webapp/app/routes/api.faucet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ActionFunctionArgs } from '@remix-run/node';
import { json } from '@remix-run/node';

import { sdk } from '~/lib/sdk';
import { ErrorResponseObject, TypeTestnetBlockchain } from '~/lib/types';
Expand Down Expand Up @@ -28,7 +27,7 @@ export async function action({ request }: ActionFunctionArgs) {
native: true,
usdc: true,
});
return json({ message: 'Tokens requested successfully' });
return Response.json({ message: 'Success' });
} catch (e: unknown) {
return Response.json({ error: (e as ErrorResponseObject)?.response?.data });
}
Expand Down
33 changes: 30 additions & 3 deletions packages/circle-demo-webapp/app/routes/api.updateWalletSet.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
import { UpdateWalletSetInput } from '@circle-fin/developer-controlled-wallets';
import { ActionFunctionArgs } from '@remix-run/node';

import { invalidateCache } from '~/lib/cache';
import { sdk } from '~/lib/sdk';
import { ErrorResponseObject } from '~/lib/types';
import { isValidString } from '~/lib/utils';

interface RequestBody {
id: string;
name: string;
}

export async function action({ request }: ActionFunctionArgs) {
const res = await sdk.updateWalletSet((await request.json()) as UpdateWalletSetInput);
return Response.json(res.data);
const { id, name } = (await request.json()) as RequestBody;

if (!isValidString(id)) {
return Response.json({ error: 'Invalid wallet set id' });
}

if (!isValidString(name)) {
return Response.json({ error: 'Invalid name' });
}

try {
await sdk.updateWalletSet({
id,
name,
});

invalidateCache('walletSets');

return Response.json({ message: 'Success' });
} catch (e: unknown) {
return Response.json({ error: (e as ErrorResponseObject)?.response?.data });
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useFetcher } from '@remix-run/react';
import { FilePenLine, LoaderCircle } from 'lucide-react';
import { useState } from 'react';
import { FormEvent, useState } from 'react';

import { Button } from '~/components/ui/button';
import {
Expand All @@ -12,15 +11,34 @@ import {
DialogTrigger,
} from '~/components/ui/dialog';
import { Input } from '~/components/ui/input';
import { useUpdateWalletSet } from '~/hooks/useUpdateWalletSet';
import { WalletSet } from '~/lib/types';

interface EditWalletSetDialogProps {
walletSet: WalletSet;
onSuccess: () => void;
}

export function EditWalletSetDialog({ walletSet }: EditWalletSetDialogProps) {
export function EditWalletSetDialog({ walletSet, onSuccess }: EditWalletSetDialogProps) {
const [open, setOpen] = useState(false);
const fetcher = useFetcher();
const { updateWalletSet, isLoading, error } = useUpdateWalletSet();

const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();

const formData = new FormData(event.currentTarget);
const id = formData.get('id') as string;
const name = formData.get('name') as string;

await updateWalletSet({ id, name });

if (!isLoading && !error) {
setOpen(false);
if (typeof onSuccess === 'function') {
onSuccess();
}
}
};

return (
<Dialog open={open} onOpenChange={setOpen}>
Expand All @@ -36,12 +54,11 @@ export function EditWalletSetDialog({ walletSet }: EditWalletSetDialogProps) {
<DialogDescription>Edit wallet set</DialogDescription>
</DialogHeader>

<fetcher.Form
method="post"
action="/api/updateWalletSet"
onSubmit={() => {
setOpen(false);
<form
onSubmit={(event) => {
void handleSubmit(event);
}}
className="space-y-4"
>
<div className="w-full max-w-md mt-6">
<input type="hidden" name="id" value={walletSet.id} />
Expand All @@ -54,10 +71,11 @@ export function EditWalletSetDialog({ walletSet }: EditWalletSetDialogProps) {
/>
</div>
<Button type="submit" className="mt-6 w-full max-w-md">
{fetcher.state === 'submitting' && <LoaderCircle className="animate-spin" />}
{isLoading && <LoaderCircle className="animate-spin" />}
Update
</Button>
</fetcher.Form>
{error && <p className="text-red-500">{error.message}</p>}
</form>
</DialogContent>
</Dialog>
);
Expand Down
12 changes: 9 additions & 3 deletions packages/circle-demo-webapp/app/routes/wallets.$id/route.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ActionFunctionArgs } from '@remix-run/node';
import { Link, useLoaderData, useParams } from '@remix-run/react';
import { Link, useLoaderData, useParams, useRevalidator } from '@remix-run/react';

import { Button } from '~/components/ui/button';
import { Card } from '~/components/ui/card';
Expand Down Expand Up @@ -47,7 +47,7 @@ export async function action({ request }: ActionFunctionArgs) {

await sdk.createWallets({
walletSetId,
count: 1, // @todo: allow user to specify count
count: 1,
blockchains: [blockchain as TypeBlockchain],
metadata: [
{
Expand All @@ -60,12 +60,18 @@ export async function action({ request }: ActionFunctionArgs) {
}

function Header({ walletSet }: { walletSet: WalletSet }) {
const revalidator = useRevalidator();

const refreshWalletSet = () => {
revalidator.revalidate();
};

return (
<header className="flex justify-between items-center mb-6">
<div>
<div className="flex items-center space-x-4">
<h1 className="text-2xl font-semibold text-foreground">Wallet Set</h1>
<EditWalletSetDialog walletSet={walletSet} />
<EditWalletSetDialog walletSet={walletSet} onSuccess={refreshWalletSet} />
</div>
<p>Name: {walletSet.name}</p>
<p>ID: {walletSet.id}</p>
Expand Down

0 comments on commit 019f0b0

Please sign in to comment.