Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7113f7c669 | ||
|
|
f9d7935d84 | ||
|
|
acd5656d4d | ||
|
|
6d1d344c48 | ||
|
|
26b8c320ae | ||
|
|
c7f7f48222 | ||
|
|
e814248d9c | ||
|
|
d7a0613067 | ||
|
|
dbc031664d | ||
|
|
5640d48854 | ||
|
|
9d6739ea59 | ||
|
|
dc49683357 | ||
|
|
30496388c4 | ||
|
|
c2ef5eb51c | ||
|
|
277c2e2ed9 | ||
|
|
0ac5e59eb9 | ||
|
|
fa5e13b5d3 | ||
|
|
45bb790dd1 | ||
|
|
102a8c8224 | ||
|
|
472e737616 | ||
|
|
0345492e99 | ||
|
|
e650434061 | ||
|
|
6712911950 | ||
|
|
1387337955 | ||
|
|
a2b737e144 | ||
|
|
c5f9921dc9 | ||
|
|
830125c920 | ||
|
|
af89836b6c | ||
|
|
d85ee5fac3 | ||
|
|
8bb4d4bc11 | ||
|
|
3c6668b6c8 | ||
|
|
6aa2765a34 | ||
|
|
bbff67db0c | ||
|
|
ef2895fa2c | ||
|
|
cf44dae9ed | ||
|
|
c26be2d958 | ||
|
|
029741126f | ||
|
|
b5114dfe22 | ||
|
|
66270f7933 | ||
|
|
11b4d9e780 | ||
|
|
ad5aabcb7c | ||
|
|
3107ba1c37 | ||
|
|
897bdc75d5 | ||
|
|
87c645d633 | ||
|
|
15b4b4b2f9 | ||
|
|
18ad1afbde | ||
|
|
e70e9b9fcc | ||
|
|
dfe913e2a9 | ||
|
|
5bc50eb339 | ||
|
|
b61ce679e1 |
@@ -63,7 +63,7 @@ jobs:
|
||||
- name: Setup Biome
|
||||
uses: biomejs/setup-biome@a9763ed3d2388f5746f9dc3e1a55df7f4609bc89 # v2.5.1
|
||||
with:
|
||||
version: 2.0.0
|
||||
version: 2.0.4
|
||||
|
||||
- run: pnpm lint
|
||||
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Package Management
|
||||
|
||||
- Use `pnpm install` (or `pnpm install --ignore-scripts` on Windows)
|
||||
- Monorepo managed with Turborepo and pnpm workspaces
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Build all packages
|
||||
pnpm build
|
||||
|
||||
# Build specific packages with dependencies
|
||||
turbo run build --filter=./packages/*
|
||||
|
||||
# Development with watch mode
|
||||
pnpm dev # Core thirdweb package
|
||||
pnpm dashboard # Run dashboard + dependencies
|
||||
pnpm playground # Run playground + dependencies
|
||||
pnpm portal # Run portal docs + dependencies
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pnpm test
|
||||
|
||||
# Interactive testing (thirdweb package)
|
||||
cd packages/thirdweb && pnpm test:devr
|
||||
|
||||
# Test specific file
|
||||
pnpm test:dev <path-to-test-file>
|
||||
|
||||
# E2E testing (dashboard)
|
||||
cd apps/dashboard && pnpm playwright
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
|
||||
```bash
|
||||
# Lint all packages
|
||||
pnpm lint
|
||||
|
||||
# Auto-fix linting issues
|
||||
pnpm fix
|
||||
|
||||
# Format code
|
||||
turbo run format
|
||||
|
||||
# Biome is the primary linter/formatter
|
||||
```
|
||||
|
||||
### Development Workflow
|
||||
|
||||
```bash
|
||||
# Start development server for dashboard
|
||||
pnpm dashboard
|
||||
|
||||
# Start playground for SDK testing
|
||||
pnpm playground
|
||||
|
||||
# Generate changeset for releases
|
||||
pnpm changeset
|
||||
|
||||
# Version packages
|
||||
pnpm version-packages
|
||||
```
|
||||
|
||||
## Repository Architecture
|
||||
|
||||
### Monorepo Structure
|
||||
|
||||
This is a Turborepo monorepo with the main thirdweb v5 SDK consolidated into `/packages/thirdweb/`. Legacy packages are in `/legacy_packages/`.
|
||||
|
||||
### Core Package (`/packages/thirdweb/`)
|
||||
|
||||
**Main Modules:**
|
||||
|
||||
- `client/` - ThirdwebClient foundation
|
||||
- `chains/` - 50+ supported blockchain definitions
|
||||
- `contract/` - Contract interaction with automatic ABI resolution
|
||||
- `transaction/` - Transaction management and execution
|
||||
- `wallets/` - Comprehensive wallet integration system
|
||||
- `extensions/` - Modular contract extensions (ERC20, ERC721, etc.)
|
||||
- `auth/` - SIWE authentication and signature verification
|
||||
- `pay/` - Fiat and crypto payment infrastructure
|
||||
- `storage/` - IPFS integration for decentralized storage
|
||||
- `rpc/` - Low-level blockchain communication
|
||||
|
||||
**Exports Structure:**
|
||||
The SDK uses modular exports from `src/exports/` including:
|
||||
|
||||
- `thirdweb.ts` - Core client and utilities
|
||||
- `chains.ts` - Chain definitions
|
||||
- `wallets.ts` - Wallet connectors
|
||||
- `react.ts` - React hooks and components
|
||||
- `extensions/` - Contract standards and protocols
|
||||
|
||||
### Applications (`/apps/`)
|
||||
|
||||
- **dashboard** - Web-based developer console (Next.js, Chakra UI)
|
||||
- **playground-web** - Interactive SDK testing environment
|
||||
- **portal** - Documentation site with MDX
|
||||
- **nebula** - Account abstraction and smart wallet management
|
||||
- **wallet-ui** - Wallet interface and testing
|
||||
|
||||
### Key Packages (`/packages/`)
|
||||
|
||||
- **thirdweb** - Main SDK (TypeScript, React, React Native)
|
||||
- **engine** - thirdweb Engine API client
|
||||
- **insight** - Analytics and data APIs
|
||||
- **nebula** - Account abstraction client
|
||||
- **service-utils** - Shared utilities across services
|
||||
|
||||
## Development Practices
|
||||
|
||||
### GitHub Workflow & Pull Requests
|
||||
|
||||
- **PR titles**: Must start with affected workspace in brackets (e.g. `[SDK]`, `[Dashboard]`, `[Portal]`, `[Playground]`)
|
||||
- **PR descriptions**: Begin with one-sentence summary, add checklist of changes, reference issues with `Fixes #123`
|
||||
- **Commits**: Keep small and topical – one logical change per commit
|
||||
- **Branch naming**: Use `area/brief-topic` format (e.g. `sdk/fix-gas-estimate`). Avoid personal names
|
||||
- **Reviews**: Request at least one core maintainer review. Do not self-merge unless sole package owner
|
||||
- **CI requirements**: All checks (type-check, Biome, tests) must pass before merging
|
||||
|
||||
### Code Quality & Formatting
|
||||
|
||||
- **Biome**: Primary linter/formatter (rules in `biome.json`)
|
||||
- **Pre-commit**: Run `pnpm biome check --apply` before committing
|
||||
- **Build verification**: Run `pnpm build` after each file change to ensure everything builds
|
||||
- Avoid editor-specific configs; rely on shared settings
|
||||
|
||||
### TypeScript Guidelines
|
||||
|
||||
- **Style**: Write idiomatic TypeScript with explicit function declarations and return types
|
||||
- **File structure**: Limit each file to one stateless, single-responsibility function for clarity
|
||||
- **Types**: Re-use shared types from `@/types` or local `types.ts` barrels
|
||||
- **Interfaces vs Types**: Prefer type aliases over interface except for nominal shapes
|
||||
- **Type safety**: Avoid `any` and `unknown` unless unavoidable; narrow generics when possible
|
||||
- **Architecture**: Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.)
|
||||
|
||||
### Testing Strategy
|
||||
|
||||
- **Co-location**: Place tests alongside code: `foo.ts` ↔ `foo.test.ts`
|
||||
- **Test approach**: Use real function invocations with stub data; avoid brittle mocks
|
||||
- **Network mocking**: Use Mock Service Worker (MSW) for fetch/HTTP call interception
|
||||
- **Test quality**: Keep tests deterministic and side-effect free
|
||||
- **Running tests**: `cd packages/thirdweb && pnpm test:dev <filename>`
|
||||
- **Test accounts**: Predefined accounts in `test/src/test-wallets.ts`
|
||||
- **Chain forking**: Use `FORKED_ETHEREUM_CHAIN` for mainnet interactions, `ANVIL_CHAIN` for isolated tests
|
||||
|
||||
### SDK Development (`packages/thirdweb`)
|
||||
|
||||
#### Public API Guidelines
|
||||
- **Exports**: Export everything via `exports/` directory, grouped by feature
|
||||
- **Documentation**: Every public symbol must have comprehensive TSDoc with:
|
||||
- At least one `@example` block that compiles
|
||||
- Custom annotation tags (`@beta`, `@internal`, `@experimental`)
|
||||
- **Comments**: Comment only ambiguous logic; avoid restating TypeScript in prose
|
||||
|
||||
#### Performance Optimization
|
||||
- **Lazy loading**: Load heavy dependencies inside async paths to keep initial bundle lean:
|
||||
```typescript
|
||||
const { jsPDF } = await import("jspdf");
|
||||
```
|
||||
- **Bundle budgets**: Track via `package.json#size-limit`
|
||||
- **Dependencies**: De-duplicate across packages through pnpm workspace hoisting
|
||||
|
||||
### Dashboard & Playground Development
|
||||
|
||||
#### UI Component Standards
|
||||
- **Core components**: Import primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator)
|
||||
- **Navigation**: Use `NavLink` for internal navigation with automatic active states
|
||||
- **Organization**: Group feature-specific components under `feature/components/*` with barrel `index.ts`
|
||||
|
||||
#### Styling Conventions
|
||||
- **CSS framework**: Tailwind CSS only – no inline styles or CSS modules
|
||||
- **Class merging**: Use `cn()` from `@/lib/utils` for conditional logic
|
||||
- **Design tokens**: Use design system tokens (backgrounds: `bg-card`, borders: `border-border`, muted text: `text-muted-foreground`)
|
||||
- **Component API**: Expose `className` prop on root element for overrides
|
||||
|
||||
#### Component Architecture
|
||||
- **Server Components** (Node edge):
|
||||
- Start files with `import "server-only";`
|
||||
- Read cookies/headers with `next/headers`
|
||||
- Access server-only environment variables
|
||||
- Perform heavy data fetching
|
||||
- Implement redirect logic with `redirect()` from `next/navigation`
|
||||
- **Client Components** (browser):
|
||||
- Begin files with `'use client';`
|
||||
- Handle interactive UI with React hooks (`useState`, `useEffect`, React Query, wallet hooks)
|
||||
- Access browser APIs (`localStorage`, `window`, `IntersectionObserver`)
|
||||
- Support fast transitions with prefetched data
|
||||
|
||||
#### Data Fetching Patterns
|
||||
- **Server Side**:
|
||||
- Always call `getAuthToken()` to retrieve JWT from cookies
|
||||
- Use `Authorization: Bearer` header – never embed tokens in URLs
|
||||
- Return typed results (`Project[]`, `User[]`) – avoid `any`
|
||||
- **Client Side**:
|
||||
- Wrap calls in React Query (`@tanstack/react-query`)
|
||||
- Use descriptive, stable `queryKeys` for cache hits
|
||||
- Configure `staleTime`/`cacheTime` based on freshness (default ≥ 60s)
|
||||
- Keep tokens secret via internal API routes or server actions
|
||||
|
||||
#### Analytics Event Guidelines
|
||||
- **When to add**: Only create events that answer clear product/business questions
|
||||
- **Check duplicates**: Review `src/@/analytics/report.ts` first
|
||||
- **Naming**:
|
||||
- Event name: human-readable `<subject> <verb>` (e.g. "contract deployed")
|
||||
- Function: `report<Subject><Verb>` (PascalCase)
|
||||
- **Template**:
|
||||
```typescript
|
||||
/**
|
||||
* ### Why do we need to report this event?
|
||||
* - Tracks number of contracts deployed
|
||||
*
|
||||
* ### Who is responsible for this event?
|
||||
* @username
|
||||
*/
|
||||
export function reportContractDeployed(properties: {
|
||||
address: string;
|
||||
chainId: number;
|
||||
}) {
|
||||
posthog.capture("contract deployed", properties);
|
||||
}
|
||||
```
|
||||
- **Client-side only**: Never import `posthog-js` in server components
|
||||
- **Changes**: Inform **#eng-core-services** before renaming/removing events
|
||||
|
||||
### Extension Development
|
||||
|
||||
- Extensions follow modular pattern in `src/extensions/`
|
||||
- Auto-generated contracts from ABI definitions
|
||||
- Composable functions with TypeScript safety
|
||||
- Support for read/write operations
|
||||
|
||||
### Wallet Architecture
|
||||
|
||||
- Unified `Wallet` and `Account` interfaces
|
||||
- Support for in-app wallets (social/email login)
|
||||
- Smart wallets with account abstraction
|
||||
- EIP-1193, EIP-5792, EIP-7702 standard support
|
||||
|
||||
## Contribution Workflow
|
||||
|
||||
1. **Fork and Clone**: Create fork, clone, create feature branch
|
||||
2. **Install**: `pnpm install` (use `--ignore-scripts` on Windows)
|
||||
3. **Develop**: Use appropriate dev commands above
|
||||
4. **Test**: Write unit tests, run linting, test on demo apps
|
||||
5. **Changeset**: Run `pnpm changeset` for semantic versioning
|
||||
6. **PR**: Submit pull request to main branch
|
||||
|
||||
### Release Testing
|
||||
|
||||
Comment `/release-pr` on PR to trigger dev release to npm for testing.
|
||||
|
||||
### Changeset Guidelines
|
||||
|
||||
Each change in `packages/*` should contain a changeset for the appropriate package with the appropriate version bump:
|
||||
- **patch**: Changes that don't impact the public API
|
||||
- **minor**: Any new/modified public API
|
||||
- **major**: Breaking changes (surface prominently in PR descriptions)
|
||||
|
||||
### Documentation Standards
|
||||
|
||||
- For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code
|
||||
- Surface breaking changes prominently in PR descriptions
|
||||
- Keep documentation focused on developer experience and practical usage
|
||||
|
||||
## Multi-Platform Support
|
||||
|
||||
The SDK supports:
|
||||
|
||||
- **Web**: React hooks and components
|
||||
- **React Native**: Mobile-specific exports and components
|
||||
- **Node.js**: Server-side functionality
|
||||
- **Framework Adapters**: Wagmi, Ethers compatibility layers
|
||||
|
||||
Key files:
|
||||
|
||||
- `src/exports/react.native.ts` - React Native specific exports
|
||||
- `packages/react-native-adapter/` - Mobile platform shims
|
||||
- `packages/wagmi-adapter/` - Wagmi ecosystem integration
|
||||
@@ -10,9 +10,9 @@ module.exports = {
|
||||
"plugin:storybook/recommended",
|
||||
],
|
||||
overrides: [
|
||||
// disable restricted imports in tw-components
|
||||
// disable restricted imports in chakra
|
||||
{
|
||||
files: "src/tw-components/**/*",
|
||||
files: "src/chakra/**/*",
|
||||
rules: {
|
||||
"no-restricted-imports": ["off"],
|
||||
},
|
||||
@@ -92,7 +92,7 @@ module.exports = {
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
// these are provided by tw-components, so we don't want to import them from chakra directly
|
||||
// these are provided by chakra folder, so we don't want to import them from chakra directly
|
||||
importNames: [
|
||||
"Card",
|
||||
"Button",
|
||||
@@ -127,7 +127,7 @@ module.exports = {
|
||||
"StackProps",
|
||||
],
|
||||
message:
|
||||
'Use the equivalent component from "tw-components" instead.',
|
||||
'import component from "chakra" folder instead if you have to use chakra component, But use shadcn component otherwise',
|
||||
name: "@chakra-ui/react",
|
||||
},
|
||||
{
|
||||
@@ -151,12 +151,6 @@ module.exports = {
|
||||
'Use `import { useDashboardRouter } from "@/lib/DashboardRouter";` instead',
|
||||
name: "next/navigation",
|
||||
},
|
||||
{
|
||||
importNames: ["Link", "Table", "Sidebar"],
|
||||
message:
|
||||
'This is likely a mistake. If you really want to import this - postfix the imported name with Icon. Example - "LinkIcon"',
|
||||
name: "lucide-react",
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Import "posthog-js" directly only within the analytics helpers ("src/@/analytics/*"). Use the exported helpers from "@/analytics/track" elsewhere.',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.0.4/schema.json",
|
||||
"extends": "//"
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"$schema": "https://unpkg.com/knip@5/schema.json",
|
||||
"ignore": [
|
||||
"src/@/components/ui/**",
|
||||
"src/components/notices/AnnouncementBanner.tsx",
|
||||
"src/components/cmd-k-search/index.tsx",
|
||||
"src/lib/search.ts"
|
||||
"src/@/components/misc/AnnouncementBanner.tsx",
|
||||
"src/@/components/cmd-k-search/index.tsx",
|
||||
"src/@/lib/search.ts"
|
||||
],
|
||||
"ignoreBinaries": ["only-allow"],
|
||||
"ignoreDependencies": [
|
||||
|
||||
@@ -81,10 +81,10 @@
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"use-debounce": "^10.0.5",
|
||||
"vaul": "^1.1.2",
|
||||
"zod": "3.25.62"
|
||||
"zod": "3.25.67"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0",
|
||||
"@biomejs/biome": "2.0.4",
|
||||
"@chakra-ui/cli": "^2.4.1",
|
||||
"@chromatic-com/storybook": "4.0.0",
|
||||
"@next/bundle-analyzer": "15.3.3",
|
||||
@@ -128,7 +128,7 @@
|
||||
"dev": "next dev --turbopack",
|
||||
"fix": "biome check ./src --fix && eslint ./src --fix",
|
||||
"format": "biome format ./src --write",
|
||||
"gen:theme-typings": "chakra-cli tokens src/theme/index.ts",
|
||||
"gen:theme-typings": "chakra-cli tokens src/chakra/theme/index.ts",
|
||||
"knip": "knip",
|
||||
"lint": "biome check ./src && knip && eslint ./src",
|
||||
"playwright": "playwright test",
|
||||
|
||||
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 626 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.33106 4.3C8.33109 4.3 7.52045 5.11064 7.52045 6.11061C7.52045 7.11058 8.33109 7.92121 9.33106 7.92121C10.331 7.92121 11.1417 7.11058 11.1417 6.11061C11.1417 5.11064 10.331 4.3 9.33106 4.3ZM5.22045 6.11061C5.22045 3.84038 7.06084 2 9.33106 2C11.6013 2 13.4417 3.84038 13.4417 6.11061C13.4417 8.38083 11.6013 10.2212 9.33106 10.2212C7.06084 10.2212 5.22045 8.38083 5.22045 6.11061ZM4.20397 12.0858C4.97486 11.3149 6.0204 10.8818 7.11061 10.8818H11.5515C12.6417 10.8818 13.6873 11.3149 14.4581 12.0858C14.9073 12.5349 14.9073 13.263 14.4581 13.7121C14.009 14.1612 13.2809 14.1612 12.8318 13.7121C12.4922 13.3726 12.0317 13.1818 11.5515 13.1818H7.11061C6.6304 13.1818 6.16987 13.3726 5.83031 13.7121C5.49076 14.0517 5.3 14.5122 5.3 14.9924V16.4727C5.3 17.1079 4.78513 17.6227 4.15 17.6227C3.51487 17.6227 3 17.1079 3 16.4727V14.9924C3 13.9022 3.43308 12.8567 4.20397 12.0858ZM17.5457 14.9598C17.9948 14.5107 17.9948 13.7825 17.5457 13.3334C17.0966 12.8843 16.3685 12.8843 15.9194 13.3334L13.7719 15.4808L13.1048 14.8137C12.6557 14.3646 11.9276 14.3646 11.4785 14.8137C11.0294 15.2628 11.0294 15.991 11.4785 16.4401L12.9588 17.9204C13.4079 18.3695 14.136 18.3695 14.5851 17.9204L17.5457 14.9598Z" fill="#646D7A"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.4444 3H4.55556C3.69645 3 3 3.69645 3 4.55556V15.4444C3 16.3036 3.69645 17 4.55556 17H15.4444C16.3036 17 17 16.3036 17 15.4444V4.55556C17 3.69645 16.3036 3 15.4444 3Z" stroke="#646D7A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.3333 7.66666L7.66663 12.3333" stroke="#646D7A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 492 B |
|
Before Width: | Height: | Size: 6.0 KiB |
@@ -1,97 +0,0 @@
|
||||
// This file configures the initialization of Sentry on the client.
|
||||
// The config you add here will be used whenever a users loads a page in their browser.
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
Sentry.init({
|
||||
allowUrls: [/thirdweb-dev\.com/i, /thirdweb\.com/, /thirdweb-preview\.com/],
|
||||
|
||||
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
||||
debug: false,
|
||||
denyUrls: [
|
||||
// Google Adsense
|
||||
/pagead\/js/i,
|
||||
// Facebook flakiness
|
||||
/graph\.facebook\.com/i,
|
||||
// Facebook blocked
|
||||
/connect\.facebook\.net\/en_US\/all\.js/i,
|
||||
// Woopra flakiness
|
||||
/eatdifferent\.com\.woopra-ns\.com/i,
|
||||
/static\.woopra\.com\/js\/woopra\.js/i,
|
||||
// Chrome extensions
|
||||
/extensions\//i,
|
||||
/^chrome:\/\//i,
|
||||
// Other plugins
|
||||
// Cacaoweb
|
||||
/127\.0\.0\.1:4001\/isrunning/i,
|
||||
/webappstoolbarba\.texthelp\.com\//i,
|
||||
/metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
|
||||
// injected (extensions)
|
||||
/inject/i,
|
||||
],
|
||||
dsn: "https://[email protected]/6690186",
|
||||
ignoreErrors: [
|
||||
// Random plugins/extensions
|
||||
"top.GLOBALS",
|
||||
// See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html
|
||||
"originalCreateNotification",
|
||||
"canvas.contentDocument",
|
||||
"MyApp_RemoveAllHighlights",
|
||||
"http://tt.epicplay.com",
|
||||
"Can't find variable: ZiteReader",
|
||||
"jigsaw is not defined",
|
||||
"ComboSearch is not defined",
|
||||
"http://loading.retry.widdit.com/",
|
||||
"atomicFindClose",
|
||||
// Facebook borked
|
||||
"fb_xd_fragment",
|
||||
// ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha)
|
||||
// See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy
|
||||
"bmi_SafeAddOnload",
|
||||
"EBCallBackMessageReceived",
|
||||
// See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
|
||||
"conduitPage",
|
||||
// Avast extension error
|
||||
"_avast_submit",
|
||||
// Common non-actionable errors
|
||||
"rejected transaction",
|
||||
"User closed modal",
|
||||
"Loading chunk",
|
||||
"Failed to execute '",
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"googlefc is not defined",
|
||||
"__cmp is not defined",
|
||||
"Cannot read properties of undefined (reading 'cmp')",
|
||||
"Cannot read properties of undefined (reading 'outputCurrentConfiguration')",
|
||||
"apstagLOADED is not defined",
|
||||
"moat_px is not defined",
|
||||
"window.ReactNativeWebView.postMessage is not a function",
|
||||
"_reportEvent is not defined",
|
||||
"requestAnimationFrame is not defined",
|
||||
"window.requestAnimationFrame is not a function",
|
||||
"tronLink.setAddress is not a function",
|
||||
// benign errors
|
||||
"ResizeObserver loop limit exceeded",
|
||||
// cannot do anything with these errors
|
||||
"Non-Error promise rejection captured",
|
||||
],
|
||||
|
||||
// You can remove this option if you're not planning to use the Sentry Session Replay feature:
|
||||
integrations: [
|
||||
Sentry.replayIntegration({
|
||||
blockAllMedia: true,
|
||||
// Additional Replay configuration goes in here, for example:
|
||||
maskAllText: true,
|
||||
}),
|
||||
],
|
||||
|
||||
replaysOnErrorSampleRate: 1.0,
|
||||
|
||||
// This sets the sample rate to be 10%. You may want this to be 100% while
|
||||
// in development and sample at a lower rate in production
|
||||
replaysSessionSampleRate: 0.1,
|
||||
|
||||
// Adjust this value in production, or use tracesSampler for greater control
|
||||
tracesSampleRate: 0.1,
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function acceptInvite(options: {
|
||||
teamId: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function reSubscribePlan(options: {
|
||||
teamId: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function confirmEmailWithOTP(otp: string) {
|
||||
const token = await getAuthToken();
|
||||
|
||||
@@ -4,9 +4,9 @@ import "server-only";
|
||||
// biome-ignore lint/style/useNodejsImportProtocol: breaks storybook if it's `node:` prefixed
|
||||
import { randomBytes } from "crypto";
|
||||
import { format } from "date-fns";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import type { Team } from "@/api/team";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function createTeam(options?: { name?: string; slug?: string }) {
|
||||
const token = await getAuthToken();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
import "server-only";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function deleteTeam(options: { teamId: string }) {
|
||||
const token = await getAuthToken();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use server";
|
||||
import { defineDashboardChain } from "lib/defineDashboardChain";
|
||||
import { isAddress, toTokens, ZERO_ADDRESS } from "thirdweb";
|
||||
import { getWalletBalance } from "thirdweb/wallets";
|
||||
import { MORALIS_API_KEY } from "../constants/server-envs";
|
||||
import { serverThirdwebClient } from "../constants/thirdweb-client.server";
|
||||
import { MORALIS_API_KEY } from "@/constants/server-envs";
|
||||
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
|
||||
import { defineDashboardChain } from "@/lib/defineDashboardChain";
|
||||
|
||||
type BalanceQueryResponse = Array<{
|
||||
balance: string;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
"use server";
|
||||
|
||||
import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "@/constants/public-envs";
|
||||
import { MORALIS_API_KEY } from "@/constants/server-envs";
|
||||
import {
|
||||
generateAlchemyUrl,
|
||||
transformAlchemyResponseToNFT,
|
||||
} from "lib/wallet/nfts/alchemy";
|
||||
} from "@/lib/wallet/nfts/alchemy";
|
||||
import {
|
||||
generateMoralisUrl,
|
||||
transformMoralisResponseToNFT,
|
||||
} from "lib/wallet/nfts/moralis";
|
||||
import type { WalletNFT } from "lib/wallet/nfts/types";
|
||||
import { getVercelEnv } from "../../lib/vercel-utils";
|
||||
import { isAlchemySupported } from "../../lib/wallet/nfts/isAlchemySupported";
|
||||
import { isMoralisSupported } from "../../lib/wallet/nfts/isMoralisSupported";
|
||||
import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "../constants/public-envs";
|
||||
import { MORALIS_API_KEY } from "../constants/server-envs";
|
||||
} from "@/lib/wallet/nfts/moralis";
|
||||
import type { WalletNFT } from "@/lib/wallet/nfts/types";
|
||||
import { getVercelEnv } from "@/utils/vercel";
|
||||
import { isAlchemySupported } from "../lib/wallet/nfts/isAlchemySupported";
|
||||
import { isMoralisSupported } from "../lib/wallet/nfts/isMoralisSupported";
|
||||
|
||||
type WalletNFTApiReturn =
|
||||
| { result: WalletNFT[]; error?: undefined }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"use server";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import {
|
||||
NEXT_PUBLIC_ENGINE_CLOUD_URL,
|
||||
NEXT_PUBLIC_THIRDWEB_API_HOST,
|
||||
} from "../constants/public-envs";
|
||||
import { ANALYTICS_SERVICE_URL } from "../constants/server-envs";
|
||||
} from "@/constants/public-envs";
|
||||
import { ANALYTICS_SERVICE_URL } from "@/constants/server-envs";
|
||||
|
||||
type ProxyActionParams = {
|
||||
pathname: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function sendTeamInvites(options: {
|
||||
teamId: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import "server-only";
|
||||
|
||||
import Stripe from "stripe";
|
||||
import type { Team } from "../api/team";
|
||||
import { STRIPE_SECRET_KEY } from "../constants/server-envs";
|
||||
import type { Team } from "@/api/team";
|
||||
import { STRIPE_SECRET_KEY } from "@/constants/server-envs";
|
||||
|
||||
let existingStripe: Stripe | undefined;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use server";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export async function updateAccount(values: {
|
||||
name?: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import posthog from "posthog-js";
|
||||
|
||||
import type { Team } from "../api/team";
|
||||
import type { Team } from "@/api/team";
|
||||
|
||||
// ----------------------------
|
||||
// CONTRACTS
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import "server-only";
|
||||
|
||||
import { ANALYTICS_SERVICE_URL } from "@/constants/server-envs";
|
||||
import type {
|
||||
AnalyticsQueryParams,
|
||||
EcosystemWalletStats,
|
||||
@@ -12,9 +13,8 @@ import type {
|
||||
UserOpStats,
|
||||
WalletStats,
|
||||
WalletUserStats,
|
||||
} from "types/analytics";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { ANALYTICS_SERVICE_URL } from "../constants/server-envs";
|
||||
} from "@/types/analytics";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
import { getChains } from "./chain";
|
||||
|
||||
async function fetchAnalytics(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use server";
|
||||
|
||||
import "server-only";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export type AuditLogEntry = {
|
||||
who: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LAST_USED_TEAM_ID } from "constants/cookies";
|
||||
import { cookies } from "next/headers";
|
||||
import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
|
||||
import { LAST_USED_TEAM_ID } from "@/constants/cookies";
|
||||
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
|
||||
|
||||
export async function getAuthToken() {
|
||||
@@ -1,8 +1,8 @@
|
||||
import "server-only";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import type { ChainService } from "../../app/(app)/(dashboard)/(chain)/types/chain";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { API_SERVER_SECRET } from "../constants/server-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { API_SERVER_SECRET } from "@/constants/server-envs";
|
||||
import type { ChainService } from "@/types/chain";
|
||||
|
||||
export async function getGasSponsoredChains() {
|
||||
if (!API_SERVER_SECRET) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use server";
|
||||
import "server-only";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export async function createDedicatedSupportChannel(
|
||||
teamIdOrSlug: string,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import "server-only";
|
||||
import { getAddress } from "thirdweb";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
|
||||
export type ProjectContract = {
|
||||
@@ -43,3 +44,43 @@ export async function getProjectContracts(options: {
|
||||
|
||||
return data.result;
|
||||
}
|
||||
|
||||
export type PartialProject = {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
image: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* get a list of projects within a team that have a given contract imported
|
||||
*/
|
||||
export async function getContractImportedProjects(options: {
|
||||
teamId: string;
|
||||
authToken: string;
|
||||
chainId: number;
|
||||
contractAddress: string;
|
||||
}) {
|
||||
const url = new URL(
|
||||
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}/projects/contracts/lookup?chainId=${options.chainId}&contractAddress=${getAddress(options.contractAddress)}`,
|
||||
);
|
||||
|
||||
const res = await fetch(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${options.authToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const errorMessage = await res.text();
|
||||
console.error("Error fetching: /projects/contracts/lookup");
|
||||
console.error(errorMessage);
|
||||
return [];
|
||||
}
|
||||
|
||||
const data = (await res.json()) as {
|
||||
result: PartialProject[];
|
||||
};
|
||||
|
||||
return data.result;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
"use server";
|
||||
|
||||
import { getAuthToken } from "app/(app)/api/lib/getAuthToken";
|
||||
import { THIRDWEB_INSIGHT_API_DOMAIN } from "constants/urls";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { THIRDWEB_INSIGHT_API_DOMAIN } from "@/constants/urls";
|
||||
|
||||
export interface WebhookResponse {
|
||||
id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export type LinkedWallet = {
|
||||
createdAt: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use server";
|
||||
|
||||
import "server-only";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export type Notification = {
|
||||
id: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "server-only";
|
||||
import type { ProjectResponse } from "@thirdweb-dev/service-utils";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export type Project = ProjectResponse;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "server-only";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { API_SERVER_SECRET } from "../constants/server-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { API_SERVER_SECRET } from "@/constants/server-envs";
|
||||
|
||||
export type SMSCountryTiers = {
|
||||
tier1: string[];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export type TeamInvite = {
|
||||
id: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "server-only";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
const TeamAccountRole = {
|
||||
MEMBER: "MEMBER",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import type { ProductSKU } from "../lib/billing";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import type { ProductSKU } from "@/types/billing";
|
||||
|
||||
type InvoiceLine = {
|
||||
// amount for this line item
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import "server-only";
|
||||
import type { TeamResponse } from "@thirdweb-dev/service-utils";
|
||||
import { cookies } from "next/headers";
|
||||
import { LAST_USED_TEAM_ID } from "@/constants/cookies";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { API_SERVER_SECRET } from "@/constants/server-envs";
|
||||
import { getValidAccount } from "../../app/(app)/account/settings/getAccount";
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { LAST_USED_TEAM_ID } from "../../constants/cookies";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
import { getMemberByAccountId } from "./team-members";
|
||||
|
||||
export type Team = TeamResponse & { stripeCustomerId: string | null };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use server";
|
||||
import { getAuthToken } from "app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST } from "../../constants/public-envs";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST } from "@/constants/public-envs";
|
||||
|
||||
const UB_BASE_URL = NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use server";
|
||||
import type { ProjectResponse } from "@thirdweb-dev/service-utils";
|
||||
import { getAuthToken } from "app/(app)/api/lib/getAuthToken";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
|
||||
import { UB_BASE_URL } from "./constants";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "server-only";
|
||||
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "../../../app/(app)/api/lib/getAuthToken";
|
||||
|
||||
type LineItem = {
|
||||
quantity: number;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "server-only";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { ANALYTICS_SERVICE_URL } from "../../constants/server-envs";
|
||||
import { ANALYTICS_SERVICE_URL } from "@/constants/server-envs";
|
||||
|
||||
type Last24HoursRPCUsageApiResponse = {
|
||||
peakRate: {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use server";
|
||||
import "server-only";
|
||||
|
||||
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "../constants/public-envs";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "./auth-token";
|
||||
|
||||
export type VerifiedDomainResponse =
|
||||
| {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
"use client";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import type {
|
||||
DurationId,
|
||||
Range,
|
||||
} from "components/analytics/date-range-selector";
|
||||
} from "@/components/analytics/date-range-selector";
|
||||
import {
|
||||
DateRangeSelector,
|
||||
getLastNDaysRange,
|
||||
} from "components/analytics/date-range-selector";
|
||||
import { IntervalSelector } from "components/analytics/interval-selector";
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
} from "@/components/analytics/date-range-selector";
|
||||
import { IntervalSelector } from "@/components/analytics/interval-selector";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
|
||||
export function RangeSelector({
|
||||
@@ -11,8 +11,10 @@ import {
|
||||
Textarea,
|
||||
} from "@chakra-ui/react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { FileInput } from "components/shared/FileInput";
|
||||
import { Button } from "chakra/button";
|
||||
import { FormErrorMessage, FormHelperText, FormLabel } from "chakra/form";
|
||||
import { Heading } from "chakra/heading";
|
||||
import { Text } from "chakra/text";
|
||||
import { ChevronLeftIcon, EyeIcon, EyeOffIcon } from "lucide-react";
|
||||
import { useRef, useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
@@ -20,19 +22,13 @@ import { useForm } from "react-hook-form";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import type { CreateDelayedRevealBatchParams } from "thirdweb/extensions/erc721";
|
||||
import type { NFTInput } from "thirdweb/utils";
|
||||
import {
|
||||
Button,
|
||||
FormErrorMessage,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Heading,
|
||||
Text,
|
||||
} from "tw-components";
|
||||
import type { ComponentWithChildren } from "types/component-with-children";
|
||||
import { processInputData, shuffleData } from "utils/batch";
|
||||
import { z } from "zod";
|
||||
import { FileInput } from "@/components/blocks/FileInput";
|
||||
import { TransactionButton } from "@/components/tx-button";
|
||||
import { Checkbox, CheckboxWithLabel } from "@/components/ui/checkbox";
|
||||
import { UnderlineLink } from "@/components/ui/UnderlineLink";
|
||||
import type { ComponentWithChildren } from "@/types/component-with-children";
|
||||
import { processInputData, shuffleData } from "@/utils/batch";
|
||||
import { BatchTable } from "./batch-table";
|
||||
import { SelectOption } from "./lazy-mint-form/select-option";
|
||||
import { UploadStep } from "./upload-step";
|
||||
@@ -13,12 +13,12 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import { PRO_CONTACT_US_URL } from "@/constants/pro";
|
||||
import { useStripeRedirectEvent } from "@/hooks/stripe/redirect-event";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
import { useStripeRedirectEvent } from "../../../../../app/(app)/(stripe)/stripe-redirect/stripeRedirectChannel";
|
||||
import { buildCancelPlanUrl } from "../../../../../app/(app)/(stripe)/utils/build-url";
|
||||
import { PRO_CONTACT_US_URL } from "../../../../../constants/pro";
|
||||
import { pollWithTimeout } from "../../../../../utils/pollWithTimeout";
|
||||
import { tryCatch } from "../../../../../utils/try-catch";
|
||||
import { pollWithTimeout } from "@/utils/pollWithTimeout";
|
||||
import { buildCancelPlanUrl } from "@/utils/stripe/build-url";
|
||||
import { tryCatch } from "@/utils/try-catch";
|
||||
|
||||
export function CancelPlanButton(props: {
|
||||
teamId: string;
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { Account, BillingCredit } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { ChainIconClient } from "components/icons/ChainIcon";
|
||||
import { formatDistance } from "date-fns";
|
||||
import { useLocalStorage } from "hooks/useLocalStorage";
|
||||
import { CircleAlertIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { Account, BillingCredit } from "@/hooks/useApi";
|
||||
import { useLocalStorage } from "@/hooks/useLocalStorage";
|
||||
import { ChainIconClient } from "@/icons/ChainIcon";
|
||||
import { formatToDollars } from "./formatToDollars";
|
||||
|
||||
interface CreditsItemProps {
|
||||
@@ -61,14 +61,14 @@ export const CreditsItem: React.FC<CreditsItemProps> = ({
|
||||
alt="tw-credit"
|
||||
className="size-6"
|
||||
objectFit="contain"
|
||||
src={require("../../../../../public/brand/thirdweb-icon.svg")}
|
||||
src={require("../../../../public/brand/thirdweb-icon.svg")}
|
||||
/>
|
||||
) : isStartupCredit ? (
|
||||
<Image
|
||||
alt="tw-credit"
|
||||
className="size-6"
|
||||
objectFit="contain"
|
||||
src={require("../../../../../public/brand/thirdweb-icon.svg")}
|
||||
src={require("../../../../public/brand/thirdweb-icon.svg")}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -2,11 +2,8 @@
|
||||
|
||||
// TODO - convert to RSC
|
||||
|
||||
import {
|
||||
type Account,
|
||||
useAccountCredits,
|
||||
} from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { type Account, useAccountCredits } from "@/hooks/useApi";
|
||||
import { CreditsItem } from "./CreditsItem";
|
||||
|
||||
export const CreditsInfoCard = (props: {
|
||||
@@ -4,11 +4,10 @@ import { useTransition } from "react";
|
||||
import type { Team } from "@/api/team";
|
||||
import { PricingCard } from "@/components/blocks/pricing-card";
|
||||
import { Spinner } from "@/components/ui/Spinner/Spinner";
|
||||
import { PRO_CONTACT_US_URL } from "@/constants/pro";
|
||||
import { useStripeRedirectEvent } from "@/hooks/stripe/redirect-event";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
|
||||
import { useStripeRedirectEvent } from "../../../../app/(app)/(stripe)/stripe-redirect/stripeRedirectChannel";
|
||||
import { getValidTeamPlan } from "../../../../app/(app)/team/components/TeamHeader/getValidTeamPlan";
|
||||
import { PRO_CONTACT_US_URL } from "../../../../constants/pro";
|
||||
import { getValidTeamPlan } from "@/utils/getValidTeamPlan";
|
||||
|
||||
// this is used to determine whether to show "Upgrade" or "Downgrade" label based on tier level
|
||||
const planToTierRecord: Record<Team["billingPlan"], number> = {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Suspense } from "react";
|
||||
import { getAuthToken } from "@/api/auth-token";
|
||||
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
|
||||
import { getAuthToken } from "../../../../../app/(app)/api/lib/getAuthToken";
|
||||
import { CouponsClient } from "./CouponsClient";
|
||||
import type { CouponData } from "./CouponsUI";
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"use client";
|
||||
import { AlertTriangleIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import type { Team } from "@/api/team";
|
||||
import { Button, type ButtonProps } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { ProductSKU } from "@/types/billing";
|
||||
import {
|
||||
buildBillingPortalUrl,
|
||||
buildCheckoutUrl,
|
||||
} from "../../app/(app)/(stripe)/utils/build-url";
|
||||
import type { Team } from "../api/team";
|
||||
import type { ProductSKU } from "../lib/billing";
|
||||
import { cn } from "../lib/utils";
|
||||
import { Button, type ButtonProps } from "./ui/button";
|
||||
} from "@/utils/stripe/build-url";
|
||||
|
||||
export function CheckoutButton(props: {
|
||||
buttonProps?: Omit<ButtonProps, "children">;
|
||||
@@ -9,8 +9,8 @@ import type { Team } from "@/api/team";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/Spinner/Spinner";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
import { pollWithTimeout } from "../../../../../utils/pollWithTimeout";
|
||||
import { tryCatch } from "../../../../../utils/try-catch";
|
||||
import { pollWithTimeout } from "../../../utils/pollWithTimeout";
|
||||
import { tryCatch } from "../../../utils/try-catch";
|
||||
|
||||
export function RenewSubscriptionButton(props: {
|
||||
teamId: string;
|
||||
@@ -1,5 +1,3 @@
|
||||
import { CURRENCIES, type CurrencyMetadata } from "constants/currencies";
|
||||
import { useAllChainsData } from "hooks/chains/allChains";
|
||||
import { useMemo, useState } from "react";
|
||||
import { isAddress, NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "thirdweb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -11,6 +9,8 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { CURRENCIES, type CurrencyMetadata } from "@/constants/currencies";
|
||||
import { useAllChainsData } from "@/hooks/chains/allChains";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface CurrencySelectorProps {
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import { BadgeContainer } from "@/storybook/utils";
|
||||
import { DangerSettingCard } from "./DangerSettingCard";
|
||||
|
||||
const meta = {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { BadgeContainer } from "../../../../stories/utils";
|
||||
import { BadgeContainer } from "@/storybook/utils";
|
||||
import { GatedSwitch } from "./GatedSwitch";
|
||||
|
||||
const meta = {
|
||||
@@ -4,12 +4,9 @@ import type { Team } from "@/api/team";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import { planToTierRecordForGating } from "@/constants/planToTierRecord";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
getTeamPlanBadgeLabel,
|
||||
TeamPlanBadge,
|
||||
} from "../../../../app/(app)/components/TeamPlanBadge";
|
||||
import { planToTierRecordForGating } from "./planToTierRecord";
|
||||
import { getTeamPlanBadgeLabel, TeamPlanBadge } from "./TeamPlanBadge";
|
||||
|
||||
type SwitchProps = React.ComponentProps<typeof Switch>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { ImageIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import { BadgeContainer } from "@/storybook/utils";
|
||||
import { Button } from "../ui/button";
|
||||
import { Spinner } from "../ui/Spinner/Spinner";
|
||||
import { Img } from "./Img";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
"use client";
|
||||
import { useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
type imgElementProps = React.DetailedHTMLProps<
|
||||
React.ImgHTMLAttributes<HTMLImageElement>,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { usePathname } from "next/navigation";
|
||||
import { useMemo, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
RenderSidebarLinks,
|
||||
type SidebarBaseLink,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "@/storybook/utils";
|
||||
import { MultiNetworkSelector } from "./NetworkSelectors";
|
||||
|
||||
const meta = {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { ChainIconClient } from "components/icons/ChainIcon";
|
||||
import { useAllChainsData } from "hooks/chains/allChains";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { MultiSelect } from "@/components/blocks/multi-select";
|
||||
import { SelectWithSearch } from "@/components/blocks/select-with-search";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useAllChainsData } from "@/hooks/chains/allChains";
|
||||
import { ChainIconClient } from "@/icons/ChainIcon";
|
||||
|
||||
function cleanChainName(chainName: string) {
|
||||
return chainName.replace("Mainnet", "");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { Suspense } from "react";
|
||||
import { ClientOnly } from "@/components/blocks/client-only";
|
||||
import { useIsMobile } from "../hooks/use-mobile";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
|
||||
export function ResponsiveLayout(props: {
|
||||
desktop: React.ReactNode;
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import { BadgeContainer } from "@/storybook/utils";
|
||||
import { SettingsCard } from "./SettingsCard";
|
||||
|
||||
const meta = {
|
||||
|
||||
@@ -4,18 +4,20 @@ import {
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSubItem,
|
||||
SidebarRail,
|
||||
SidebarSeparator,
|
||||
SidebarTrigger,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { AppFooter } from "../footers/app-footer";
|
||||
import { NavLink } from "../ui/NavLink";
|
||||
import { Separator } from "../ui/separator";
|
||||
import { AppFooter } from "./app-footer";
|
||||
import { MobileSidebar, useActiveSidebarLink } from "./MobileSidebar";
|
||||
import { CustomSidebar, type SidebarLink } from "./Sidebar";
|
||||
|
||||
@@ -66,23 +68,13 @@ export function FullWidthSidebarLayout(props: {
|
||||
>
|
||||
{/* left - sidebar */}
|
||||
<Sidebar className="pt-2" collapsible="icon" side="left">
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
<RenderSidebarGroup
|
||||
groupName={undefined}
|
||||
sidebarLinks={contentSidebarLinks}
|
||||
/>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
<SidebarContent className="p-2">
|
||||
<RenderSidebarMenu links={contentSidebarLinks} />
|
||||
</SidebarContent>
|
||||
|
||||
{footerSidebarLinks && (
|
||||
<SidebarFooter className="pb-3">
|
||||
<RenderSidebarGroup
|
||||
groupName={undefined}
|
||||
sidebarLinks={footerSidebarLinks}
|
||||
/>
|
||||
<RenderSidebarMenu links={footerSidebarLinks} />
|
||||
</SidebarFooter>
|
||||
)}
|
||||
|
||||
@@ -106,17 +98,29 @@ export function FullWidthSidebarLayout(props: {
|
||||
|
||||
function RenderSidebarGroup(props: {
|
||||
sidebarLinks: SidebarLink[];
|
||||
groupName: string | undefined;
|
||||
groupName: string;
|
||||
}) {
|
||||
const { sidebarLinks } = props;
|
||||
const sidebar = useSidebar();
|
||||
return (
|
||||
<SidebarGroup className="p-0">
|
||||
<SidebarMenuItem>
|
||||
<SidebarGroupLabel> {props.groupName}</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<RenderSidebarMenu links={props.sidebarLinks} />
|
||||
</SidebarGroupContent>
|
||||
</SidebarMenuItem>
|
||||
</SidebarGroup>
|
||||
);
|
||||
}
|
||||
|
||||
function RenderSidebarMenu(props: { links: SidebarLink[] }) {
|
||||
const sidebar = useSidebar();
|
||||
return (
|
||||
<SidebarMenu className="gap-1.5">
|
||||
{sidebarLinks.map((link) => {
|
||||
{props.links.map((link, idx) => {
|
||||
// link
|
||||
if ("href" in link) {
|
||||
return (
|
||||
<SidebarMenuItem key={link.href}>
|
||||
<SidebarMenuSubItem key={link.href}>
|
||||
<SidebarMenuButton asChild>
|
||||
<NavLink
|
||||
activeClassName="text-foreground bg-accent"
|
||||
@@ -132,14 +136,24 @@ function RenderSidebarGroup(props: {
|
||||
<span>{link.label}</span>
|
||||
</NavLink>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenuSubItem>
|
||||
);
|
||||
}
|
||||
|
||||
// separator
|
||||
if ("separator" in link) {
|
||||
return <SidebarSeparator className="my-1" key={Math.random()} />;
|
||||
return (
|
||||
<SidebarSeparator
|
||||
className="my-1"
|
||||
key={`separator-${
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: index is fine here
|
||||
idx
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// group
|
||||
return (
|
||||
<RenderSidebarGroup
|
||||
groupName={link.group}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "@/storybook/utils";
|
||||
import { SingleNetworkSelector } from "./NetworkSelectors";
|
||||
|
||||
const meta = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { BadgeContainer } from "../../stories/utils";
|
||||
import { StepsCard } from "./StepsCard";
|
||||
import { StepsCard } from "@/components/blocks/StepsCard";
|
||||
import { BadgeContainer } from "@/storybook/utils";
|
||||
|
||||
const meta = {
|
||||
component: Component,
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import type { Team } from "@/api/team";
|
||||
import { Badge, type BadgeProps } from "@/components/ui/badge";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useDashboardRouter } from "../../../@/lib/DashboardRouter";
|
||||
|
||||
const teamPlanToBadgeVariant: Record<
|
||||
Team["billingPlan"],
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "@/storybook/utils";
|
||||
import { TokenSelector } from "./TokenSelector";
|
||||
|
||||
const meta = {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { useAllChainsData } from "hooks/chains/allChains";
|
||||
import { useTokensData } from "hooks/tokens/tokens";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import {
|
||||
getAddress,
|
||||
@@ -7,13 +5,15 @@ import {
|
||||
type ThirdwebClient,
|
||||
} from "thirdweb";
|
||||
import { shortenAddress } from "thirdweb/utils";
|
||||
import { replaceIpfsUrl } from "../../../lib/sdk";
|
||||
import { fallbackChainIcon } from "../../../utils/chain-icons";
|
||||
import type { TokenMetadata } from "../../api/universal-bridge/tokens";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { Img } from "./Img";
|
||||
import { SelectWithSearch } from "./select-with-search";
|
||||
import type { TokenMetadata } from "@/api/universal-bridge/tokens";
|
||||
import { Img } from "@/components/blocks/Img";
|
||||
import { SelectWithSearch } from "@/components/blocks/select-with-search";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useAllChainsData } from "@/hooks/chains/allChains";
|
||||
import { useTokensData } from "@/hooks/tokens";
|
||||
import { replaceIpfsUrl } from "@/lib/sdk";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { fallbackChainIcon } from "@/utils/chain-icons";
|
||||
|
||||
type Option = { label: string; value: string };
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { ArrowRightIcon, RocketIcon, StarIcon } from "lucide-react";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import { BadgeContainer } from "@/storybook/utils";
|
||||
import { UpsellBannerCard } from "./UpsellBannerCard";
|
||||
|
||||
function Story() {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../../stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "@/storybook/utils";
|
||||
import { Button } from "../../ui/button";
|
||||
import { GradientAvatar } from "./GradientAvatar";
|
||||
import { GradientAvatar } from "./gradient-avatar";
|
||||
|
||||
const meta = {
|
||||
component: Story,
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { Img } from "@/components/blocks/Img";
|
||||
import { resolveSchemeWithErrorHandler } from "../../../lib/resolveSchemeWithErrorHandler";
|
||||
import { cn } from "../../../lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
|
||||
import { GradientBlobbie } from "./GradientBlobbie";
|
||||
|
||||
export function GradientAvatar(props: {
|
||||
@@ -1,11 +1,8 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../../stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "@/storybook/utils";
|
||||
import { Button } from "../../ui/button";
|
||||
import { ProjectAvatar } from "./ProjectAvatar";
|
||||
import { ProjectAvatar } from "./project-avatar";
|
||||
|
||||
const meta = {
|
||||
component: Story,
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BoxIcon } from "lucide-react";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { Img } from "@/components/blocks/Img";
|
||||
import { resolveSchemeWithErrorHandler } from "../../../lib/resolveSchemeWithErrorHandler";
|
||||
import { cn } from "../../../lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
|
||||
|
||||
export function ProjectAvatar(props: {
|
||||
src: string | undefined;
|
||||
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
EmptyChartState,
|
||||
LoadingChartState,
|
||||
} from "components/analytics/empty-chart-state";
|
||||
import { format } from "date-fns";
|
||||
import { useMemo } from "react";
|
||||
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";
|
||||
import {
|
||||
EmptyChartState,
|
||||
LoadingChartState,
|
||||
} from "@/components/analytics/empty-chart-state";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
|
||||