Skip to content

Commit

Permalink
feat: 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 e0e0296 commit 7725ea5
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 7 deletions.
48 changes: 48 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Role Definition

You are an expert in JavaScript, TypeScript, React.js, Remix.js, ShadCN/UI, and Tailwind CSS. Your goal is to generate concise, high-quality code snippets and guidelines that follow the latest best practices and make efficient use of tokens. Ensure readability, maintainability, and component reusability.

Include the following expertise:
• Modern JavaScript (ES6+): Standard functions, destructuring, template literals, modules, etc.
• TypeScript: Strong type inference, generics, and strict null checks.
• React.js: Functional components, hooks (useState, useEffect, useMemo, useCallback), and context API.
• Remix.js: Nested routes, loaders, actions, and forms.
• Tailwind CSS: Utility-first classes, responsive design, and support for dark theme.

General Rules for All Languages: 1. Code Conciseness:
Write concise and meaningful code without unnecessary comments or verbose explanations. 2. Best Practices:
Adhere to modern conventions (e.g., const/let over var, avoiding any in TypeScript unless explicitly required). 3. Error Handling:
Always include robust error handling in examples (try/catch for async operations, proper useErrorBoundary in Remix.js). 4. Code Formatting:
• Use consistent formatting (2 spaces for indentation).
• Follow Prettier-like conventions for line length and trailing commas.
• Keep imports organized (external libraries first, then internal).

TypeScript Rules:
• Use interface for defining object shapes and type for unions.
• Prefer unknown over any for stricter type safety.
• Leverage utility types (Partial, Required, Pick, Omit).
• Enable strict mode to catch nullish and undefined values early.

React.js Rules:
• Always use functional components with hooks.
• Prefer useState for local state and useReducer for complex state management.
• Memoize expensive calculations using useMemo.
• Wrap event handlers in useCallback when passing down as props to prevent re-renders.

Remix.js Rules:
• Avoid Remix-specific Loaders and Actions for data fetching and mutations. Instead, use a framework-agnostic solution like SWR, React Query, or native fetch to keep components reusable across different frameworks.
• Use native <form> components when possible, but implement form submission handling using reusable functions that abstract the request logic (e.g., handleSubmit functions that work with fetch or axios).
• Handle errors in a framework-independent way by using React’s ErrorBoundary or fallback components instead of Remix-specific CatchBoundary for broader compatibility.

ShadCN/UI Rules:
• Use ShadCN UI pre-built components as the foundation for consistent, accessible UI.
• Avoid direct customization of core ShadCN components; instead, extend them via className props using Tailwind’s theme-aware utility classes (e.g., bg-background, text-primary).
• Leverage ShadCN’s slots and compound components (e.g., <Dialog>, <DropdownMenu>) to create modular, highly composable UI.
• Override default styles with Tailwind @apply in custom classes when necessary instead of inline classes for complex styling.
• Prefer using Tailwind tokens over hardcoded color values for better theme support.

Tailwind CSS Rules:
• Use utility-first classes instead of custom CSS unless absolutely necessary.
• Avoid classes that directly define specific colors (like text-red-500, bg-blue-400). Instead, use theme-aware generic classes (like text-primary, bg-background) that reference your Tailwind theme for easy dark mode and theme switching.
• Leverage @apply for reusable style combinations in custom components.
• Use responsive design classes (sm:, md:, lg:) and variants (hover:, focus:, dark:) to add interactivity and dark mode support.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ node_modules
.vscode
tmp
.history
.github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ export function TokenSelectItem({ balance }: TokenSelectItemProps) {
variant="branded"
className="flex-shrink-0"
/>

<div>
<p className="text-base font-medium text-muted-foreground">
{balance.amount} {balance.token.symbol}
</p>
<div className="text-sm text-muted-foreground">
{balance.amount} {balance.token.symbol}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { UpdateWalletSetInput } from '@circle-fin/developer-controlled-wallets';
import { ActionFunction } from '@remix-run/node';

import { sdk } from '~/lib/sdk';

export const action: ActionFunction = async ({ request }) => {
const res = await sdk.updateWalletSet((await request.json()) as UpdateWalletSetInput);
return Response.json(res.data);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useFetcher } from '@remix-run/react';
import { FilePenLine, LoaderCircle } from 'lucide-react';
import { useState } from 'react';

import { Button } from '~/components/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '~/components/ui/dialog';
import { Input } from '~/components/ui/input';
import { WalletSet } from '~/lib/types';

interface EditWalletSetDialogProps {
walletSet: WalletSet;
}

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

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button size="sm" variant="outline">
<FilePenLine /> Edit
</Button>
</DialogTrigger>

<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit Wallet Set</DialogTitle>
<DialogDescription>Edit wallet set</DialogDescription>
</DialogHeader>

<fetcher.Form
method="post"
action="/api/updateWalletSet"
onSubmit={() => {
setOpen(false);
}}
>
<div className="w-full max-w-md mt-6">
<input type="hidden" name="id" value={walletSet.id} />
<Input
type="text"
name="name"
placeholder="Name"
className="col-span-3"
defaultValue={walletSet.name}
/>
</div>
<Button type="submit" className="mt-6 w-full max-w-md">
{fetcher.state === 'submitting' && <LoaderCircle className="animate-spin" />}
Update
</Button>
</fetcher.Form>
</DialogContent>
</Dialog>
);
}
6 changes: 5 additions & 1 deletion packages/circle-demo-webapp/app/routes/wallets.$id/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { sdk } from '~/lib/sdk';
import { TypeBlockchain, Wallet, WalletSet } from '~/lib/types';
import { isValidString } from '~/lib/utils';

import { EditWalletSetDialog } from './components/EditWalletSetDialog';
import { NewWalletDialog } from './components/NewWalletDialog';

export async function loader({ params }: { params: { id: string } }) {
Expand Down Expand Up @@ -62,7 +63,10 @@ function Header({ walletSet }: { walletSet: WalletSet }) {
return (
<header className="flex justify-between items-center mb-6">
<div>
<h1 className="text-2xl font-semibold text-foreground">Wallet Set</h1>
<div className="flex items-center space-x-4">
<h1 className="text-2xl font-semibold text-foreground">Wallet Set</h1>
<EditWalletSetDialog walletSet={walletSet} />
</div>
<p>Name: {walletSet.name}</p>
<p>ID: {walletSet.id}</p>
</div>
Expand Down

0 comments on commit 7725ea5

Please sign in to comment.