gaboesquivel opyn .cursorrules file for TypeScript

# Expertise Areas
- Solidity, TypeScript, Node.js, Next.js 14 App Router, React, Vite, Viem v2, Wagmi v2, Shadcn UI, Radix UI, Tailwind Aria

# Key Principles
- Write concise, technical responses with TypeScript examples
- Use functional, declarative programming; avoid classes
- Prefer iteration and modularization over duplication
- Use descriptive variable names with auxiliary verbs (e.g., isLoading)
- Use lowercase with dashes for directories (e.g., components/auth-wizard)
- Favor named exports for components
- Use the RORO (Receive an Object, Return an Object) pattern

# JavaScript/TypeScript
- Use "function" keyword for pure functions; omit semicolons
- Use TypeScript; prefer interfaces over types; avoid enums, use maps
- Structure files: Exported component, subcomponents, helpers, static content, types
- Avoid unnecessary curly braces in conditionals
- Use concise, one-line syntax for simple conditionals
- Prioritize error handling and edge cases:
  - Handle errors early; use early returns
  - Place happy path last for readability
  - Avoid unnecessary else statements; use if-return pattern
  - Use guard clauses for preconditions and invalid states
  - Implement proper error logging and user-friendly messages
  - Throw errors from @opyn/errors

# Dependencies
- Next.js 14 App Router, Wagmi v2, Viem v2

# React/Next.js
- Use functional components 
- Use TypeScript interfaces at the bottom of files
- Name everything semantically
- Use types from @opyn/supabase
- Use declarative JSX
- Use function, not const for components
- Use const for methods in components
- Use variables for static content at the bottom of files
- Use Shadcn UI, Radix, Tailwind Aria for styling importing components from @opyn/ui
- Implement responsive design with Tailwind CSS; mobile-first approach
- Use content variables for static content outside render functions
- Minimize 'use client', 'useEffect', 'setState'; favor RSC
- Use Zod for form validation
- Optimize images: WebP format, size data, lazy loading
- Use error boundaries for unexpected errors
- Use useActionState with react-hook-form for form validation with <Form>
- Use react functional components never render functions
- Use guard clauses and early returns for validation and preconditions
  ```typescript
  useEffect(() => {
    if (!watch) return
      refetch()
  }, [refetch, watch])
``` 

- Use next-safe-action for server actions:
  - Handle errors gracefully with captureAppError from @opyn/errors
  - Use ActionResult for consistent responses
- Use next-safe-action for all server actions:
  - Handle errors gracefully and return appropriate responses using captureAppError.
  - Implement consistent error handling and success responses using @lib/actions.ts
  - Example:
```typescript
'use server'

import { type ActionResult, success, failure } from '@opyn/lib'
import { createSupabaseNextClient } from '@/services/supabase'
import { type Tables, depositInsertSchema } from '@opyn/supabase'
import { createSafeActionClient } from 'next-safe-action'

// Stores a deposit intent in the database, creating a pending transaction and a deposit record.
export const saveDepositIntent = createSafeActionClient()
  .schema(depositInsertSchema)
  .action(
    async ({
      parsedInput: transfer,
    }): Promise<ActionResult<Tables<'presale_deposit'>>> => {
      try {
        const supabase = await createSupabaseNextClient()

        const transaction = await supabase
          .from('transaction')
          .upsert(
            {
              hash: transfer.deposit_hash,
              trx_type: 'presale_deposit',
              ...transfer,
            },
            { onConflict: 'hash' },
          )
          .select()

        if (transaction.error)
          return failure('DB_OP_FAILURE', transaction.error)

        return success(deposit.data[0])
      } catch (error) {
        return failure('UNEXPECTED_ERROR', error)
      }
    },
  )

```

# Key Next.js Conventions
1. Rely on Next.js App Router for state changes
2. Prioritize Web Vitals (LCP, CLS, FID)
3. Minimize 'use client' usage:
   - Prefer server components and Next.js SSR features
   - Use 'use client' only for Web API access in small components
   - Avoid 'use client' for data fetching or state management

# Reference
- Next.js documentation for Data Fetching, Rendering, and Routing best practices 
- Radix UI documentation for accessibility and component primitives
- Shadcn UI documentation for component system and starter kit


# UI Component Guidelines

## Icons and Design System
- Use Heroicons (https://heroicons.com/) for all icons
- Follow design system tokens in app/globals.css and tailwind.config.js
- Avoid default Tailwind colors to maintain brand consistency

## Styling Best Practices
- Always use `cn` utility function for conditional class names
- Add `className` prop to components for external styling overrides
- Use `cva` function for component variants to centralize styling
- Utilize CSS Flexbox and Grid for modern layouts
- Build fluid, responsive components with container queries
- Ensure mobile-first responsive design with Tailwind classes

## Component Architecture
- Use Radix UI's built-in functions (e.g. `onOpenChange`) over custom logic
- Style with Radix UI data attributes for interactivity
- Prioritize Radix UI data attributes for accessibility
- Use Tailwind CSS classes for styling
- Avoid JavaScript styling unless absolutely necessary

## Component Usage
- Use `<Form>` instead of native `<form>`
- Use shadcn/ui Sidebar for menu navigation
- Use shadcn/ui Sheet for contextual dialogs/panels
- Use shadcn/ui Skeleton in Suspense fallbacks
- Use Sonner for toast notifications

# Tools
- Use React-use for hooks
- Use date-fns for date manipulation

### Examples

#### Example 1: Styling a Tab Component
```tsx
<Tab
  data-state="active"
  className={cn(
    "text-sm font-medium",
    "data-[state=active]:text-brand-500",
    "data-[state=inactive]:text-brand-400"
  )}
>
  Tab 1
</Tab>
```

#### Example 2: Responsive Grid Layout
```tsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  <Card />
  <Card />
  <Card />
</div>
```

#### Example 3: Using Radix's `onOpenChange`
```tsx
<Dialog onOpenChange={(isOpen) => console.log(isOpen)}>
  <DialogTrigger asChild>
    <Button>Open Dialog</Button>
  </DialogTrigger>
  <DialogContent>Content goes here</DialogContent>
</Dialog>
```

# Viem Wagmi
- Use getAddress from viem to convert addresses to Address type, never as Address
- Use viem 2.x apis
- Use wagmi 2.x apis

# NextJS Services 

- never use try/catch in services instead use captureAppError from @opyn/errors
- use SupaApiParams type for supabase client
- return type guards for supabase queries and mutations
- return data type can never be null

```tsx
import { captureAppError } from '@opyn/errors'
import type { SupaApiParams } from '../types'

export async function getAssetByUuid({
  uuid,
  supabase,
}: SupaApiParams & {
  uuid: string
}) {
  const { data, error } = await supabase
    .from('token')
    .select()
    .eq('uuid', uuid)
    .single()

  if (error || !data) captureAppError('FETCH_ERROR', error)

  return data as NonNullable<typeof data>
}


export async function insertMarket({
  market,
  supabase,
}: SupaApiParams & {
  market: TablesInsert<'market'>
}) {
  const { data, error } = await supabase
    .from('market')
    .insert(market)
    .select()
    .single()

  if (error || !data) captureAppError('INSERT_ERROR', error)

  return data as NonNullable<typeof data>
}


```


# Trigger Hooks

```ts
import type { AlchemyActivity, AlchemyWebhookEvent } from '@opyn/alchemy'
import { logger, task } from '@trigger.dev/sdk/v3'
import { insertMarket } from '../../lib/supabase'

export const newMarketTask = task({
  id: 'collateral-deposit',
  run: async (payload: AlchemyWebhookEvent) => {
    const activity: AlchemyActivity[] = payload.event.activity

    try {
      const market = await insertCollateralDeposit({ market: dummyMarket })
      logger.info('Inserted dummy market', { market })
    } catch (error) {
      logger.error('Failed to insert dummy market', { error })
    }
  },
})

```
css
golang
html
java
javascript
less
next.js
plpgsql
+8 more

First Time Repository

TypeScript

Languages:

CSS: 26.1KB
HTML: 0.4KB
JavaScript: 3.9KB
PLpgSQL: 7.6KB
TypeScript: 1890.7KB
Created: 11/21/2024
Updated: 11/27/2024

All Repositories (1)